• Re: Java HTTP API Signatures, schemas, XML and JSON, Pojo's and Poji's, Java and Spring and schema

    From Ross Finlayson@ross.a.finlayson@gmail.com to comp.lang.java.programmer on Fri Apr 19 10:22:18 2024
    From Newsgroup: comp.lang.java.programmer

    On 04/19/2024 09:30 AM, Ross Finlayson wrote:
    Signature API

    ccc.api
    ccc.api.exception
    ccc.api.fault

    ccc.api.client

    ccc.springsup.web

    ccc.serdes


    Api ApiMapping

    ApiFlt ApiHardFlt
    OtherCauseFault CovariantFault

    Pth Hdr Qpa Req Rsp Flt Err


    The other day I was writing a Spring Boot server,
    and the implementation of the Api looks like this

    For a service Srv, group of APIs Grp, and API Api

    public interface Srv {
    interface Grp {
    interface Api extends ccc.api.Api {

    static class Pth{}
    static class Qpa{}
    static class Hdr{}
    static class Req{}
    static class Rsp{}
    static class Flt{}
    static class Err{}


    Rsp api(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Qpa qpa,
    @Valid @NotNull Hdr hdr,
    @Valid @NotNull Req req
    ) throws ApiFlt;

    }
    }

    }

    The validation annotations have to be on the root type,
    so, they go on the Api.

    public interface SrvMapping {
    interface Grp {
    @RequestMapping
    interface Api extends Srv.Grp.Api, ApiMapping {

    @Override
    @GetMapping("/api/{pth}")
    @ResponseBody
    Rsp api(
    @PathVariable Pth pth,
    @QueryParam Qpa qpa,
    @RequestHeader Hdr hdr,
    @RequestBody Req req
    ) throws ApiFlt;

    }
    }
    }

    The request mapping and also the openapi or documentation
    interfaces have to be on the interface the controller implements,
    and they don't mean anything to the Api, so they go on the ApiMapping.

    @Controller
    public class SrvController implements SrvMapping.Grp.Api
    {
    @Override
    Srv.Grp.Rsp api(
    Srv.Grp.Pth pth,
    Srv.Grp.Qpa qpa,
    Srv.Grp.Hdr hdr,
    Srv.Grp.Req req
    ) throws ApiFlt;
    }

    The controller just implements the Api, Spring Web wires
    it up and Openapi documents it up.

    And it results sort of thusly a very simple organization of APIs.

    public interface Srv {

    interface Grp1 {
    interface Api1 { /* */ }
    interface Api2 { /* */ }
    interface Api3 { /* */ }
    interface Api4 { /* */ }
    }
    interface Grp@ {
    interface Api1 { /* */ }
    interface Api2 { /* */ }
    interface Api3 { /* */ }
    interface Api4 { /* */ }
    }
    /* */
    }

    The key is that given those, the Api and ApiMapping an entire
    Signature, of the mapping, sort of results, with adding this
    sort of ApiStatusMapping, to relate the HTTP status codes,
    with, the covariant return bodies, then it's sort of all one thing.

    ("a functional interface may still have multiple default methods ...")

    The idea is that the interfaces carry very well down from these.

    For most often usual "APIs" these days it'd often look:

    @Data
    static class MyGrp {

    }

    public interface Srv {
    interface Grp {
    interface Get1 extends ccc.api.Api {

    static class Pth{ String myGrpId;}
    static class Req extends MyGrp{};
    static class Rsp{}
    static class Flt{}
    static class Err{}

    Rsp get1(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Req req
    ) throws ApiFlt;

    }
    interface Put1 extends ccc.api.Api {

    static class Pth{ String myGrpId;}
    static class Req extends MyGrp{}
    static class Rsp{}
    static class Flt{}
    static class Err{}

    Rsp put1(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Req req
    ) throws ApiFlt;

    }
    }

    }


    public interface SrvMapping {
    interface Grp {
    @RequestMapping
    interface Api extends Srv.Grp.Get1, ApiMapping {

    @Override
    @GetMapping("/grp/{myGrpId}")
    @ResponseBody
    Rsp get1(
    @PathVariable("myGrpId") Pth pth,
    @RequestBody Req req
    ) throws ApiFlt;

    }
    @RequestMapping
    interface Api extends Srv.Grp.Put1, ApiMapping {

    @Override
    @PutMapping("/grp/{myGrpId}")
    @ResponseBody
    Rsp put1(
    @PathVariable("myGrpId") String myGrpId,
    @RequestBody Req req
    ) throws ApiFlt;

    }
    }
    }


    Then, an issue involves that the Pth Hdr Qpa Req are distinct
    types, among all the APIs, though they just extend the common
    types. Then, those usually being the outside of the document,
    so, not "in" the document as it were, all the members just get
    copied among those, interchangeably, while the types in the
    signatures, keep each API's types distinct. It results quite a few
    types yet that also makes it great as each simply can be referred
    to by its class constant, and it totally makes it so that common
    behavior is a simple matter of extension.

    Relating the HTTP status codes to the resulting response bodies,
    is for the covariant return types, or fault, and how to make a
    convention in the exceptions,


    The Signature, Api + ApiMapping, then, basically encapsulates everything there is to make an HTTP request and interpret an HTTP response
    according to the Api validation indicating values and ranges
    and ApiMapping mapping indicating HTTP request and response
    semantics.

    Then, the covariant response semantics, is to get figured out,
    to make it so that the exception types have a neat little convention
    to extract according to response status and headers, the response
    body, besides the usual case the success case.

    For responses with no content, it's figured to have a distinguished
    Rsp type or just to return void.

    For common types then also is for common semantics, then as
    with regards to those resulting the "schema" as what it is,
    though that this is only about "interface first" as it were
    with not much care except in the Java ecosystem, then as
    with regards to Spring Web semantics and, JAX-RS semantics, say.

    Api
    ApiMapping <- Spring Web
    ApiRsmapping <- JAX-RS Jersey


    Hdr
    Pth
    Mtx // "MatrixVariable"
    Qpa
    Req
    Rsp
    Err
    Cov1
    Cov2

    Then, how to associate status with the Covariant responses,
    is sort of for annotations and repeated annotation, that relate
    statuses, to, response bodies, then of the various kinds of response
    bodies, then to sort of adopt the OneOf of the "Variant" return
    types, among those.

    class CovariantFault extends ApiFlt

    @Success( status = 200)
    @Success(status = 201, result = Accepted201.class)
    @Success(status = 204, result = NoContent204.class)

    @Covariant(status = 400, result = Error.class)
    @Covariant(range = "4xx", result = Error.class)
    class ErrorFault extends CovariantFault { static class covariantClass = Error.class;}

    @Covariant(status = 404, result = NotFound404.class)
    class NotFoundException extends NovariantFault {}

    @Covariant(range = "5xx", result = RetryOrCircuitBreak.class)
    class BackendException extends CovariantFault {}

    The idea is to sort of just inspect the interface for its members,
    then find off of those the status. Then, inspect the interface
    for its exceptions, and make what results for those the covariant
    return values, and whatever other cases result from invocation.

    @ResultSuccess(status = 200) @ResultCovariant(result = {Cov1.class, Cov2.class})

    @ResultCovariant(status = 400, range = "4xx", result = Error.class,
    exception = ErrorFlt.class)


    public interface Srv {
    interface Grp {
    interface Api extends ccc.api.Api {

    static class Pth{}
    static class Qpa{}
    static class Hdr{}
    static class Req{}
    static class Rsp{}
    static class Flt{}
    static class Err extends Error {}
    static class ErrFlt extends ErrorFault{}
    static class Cov extends Error {}
    static class CovFlt extends CovariantFault{ static class covariantClass = Cov.class;}


    Rsp api(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Qpa qpa,
    @Valid @NotNull Hdr hdr,
    @Valid @NotNull Req req
    ) throws ApiFlt, ErrFlt, CovFlt;

    }
    }

    }


    For aligning with OpenApi, then there's a default range named "default",
    then whether the 2xx, 3xx, 4xx, 5xx ranges are named like 3XX or 3xx.
    (Upper case, like '5XX'.) Then the idea would be that usual sorts of
    unit tests check that the annotation match for the ApiMapping among the Jersey or Spring RequestMappings, the OpenApi documentation and type declarations, then those all being defined simply enough as a usual sort
    of HTTP Api with Pth, Hdr, Qpa, Req, Rsp, then Flt, Err, Cov, and so on.


    Anyways I got it running this way and it works pretty good,
    works just great with plain vanilla framework, and today's.

    Then, for the types, is sort of to indicate the Inner and Outer or
    Inward and Outer types, and for branching, with the idea then
    that the relations of types are defined first by inheritance for
    the composition of their contents, then as with regards to
    the document, basically for JSON and XML whether the document
    has a root in it like XML or is a branching like JSON (or that most
    usually it's a "JSON object" vis-a-vis plain values in JSON).

    This gets into two major cases, where there are alternatives
    on the outside, and where there are alternatives in the members,
    with regards to "any" and these kinds of things.

    Basically this seems for whenever extending a class, to provide
    it its own type for differentiation and declaration, whether it
    still is to be considered that it "is" the parent class, so that,
    it's really of a copy-constructor in semantics, in terms of
    assigning it values of the parent object,

    Superclass superclass = subclass ; // is assignable

    Subclass subclass = superclass ; // not assignable


    Then, the idea of declaring "Subclass" and "Superclass",
    or "Sub" and "Sup", is to make it so that it results sort
    of the thing.

    I.e., the object that only extends to establish its own
    type in the interface and signature, is to have some sort
    idiom to result that what it extends, is assignable to it,
    that this would be overloading "=" assignment, in a sense,
    for the superclass, as an instance of (the values in the structure
    of) the subclass.

    Superclass superclassInstance = subclassInstance; // is assignable

    So, the idea is to implement a method named sup,
    on these extensions, that accepts a superclass,
    and returns an instance of the same-shape sub-class
    for assignment.

    Subclass subclassInstance = Subclass.sub(superclassInstance);

    I.e., the "is-a" relation is reflective, or for, "asA", ..., "ofA".

    Subclass subclassInstance = Subclass.ofA(superclassInstance);


    For openApi then it seems for populating subtypes, but mostly
    is the idea is that the Api Signature annotations will indicate
    what openapi annotations get create, then to employ those.


    class org.PojoXsdDefinedType {}

    class MyPojo extends PojoXsdDefinedType {}

    The idea is that inside the framework, each Api has its own type,
    but on the wire, the XML-style with the document in the root,
    or the JSON-style with the document projected into the root,
    are two different styles, and the Serializer and Deserializer of
    the bodies or payloads, make for marking for an object what
    is its payload, then that the framework makes and returns the
    things, so it is simple and thorough overall, while not much
    encumbered or intrusive, and not very tightly-coupled, except
    of course all defined well according to types.

    Java has single inheritance of classes and multiple inheritance
    of interfaces, with regards to patterns like diamond and so
    on. Pretty much all the usual surround of Pojos are classes,
    vis-a-vis Poji's or plain-old-Java-interfaces.


    class MyGrp {
    int id; // notOnTheCreate
    String name;
    List<Integer> memberIndividuals;
    List<Integer> memberGroups;

    String onlyOnTheCreate;
    String onlyOnTheUpdate;
    String onlyOnTheGet;
    }

    The idea is that often the POJO will have various fields in it,
    and the validation or constraints, only apply with regards to
    being a request or response, and they can't be differentiated
    exactly and only by the type.

    class MyGrp {
    int id; // prefer Integer or boxed types everywhere, so, validation
    String name;
    List<Integer> memberIndividualIds;
    List<Integer> memberGroupIds;

    }

    class MyGrpCreateReq extends MyGrp {
    String onlyOnTheCreate;
    }
    class MyGrpUpdateReq extends MyGrp {
    String onlyOnTheUpdate;
    }

    class MyGrpGetRsp extends MyGrp {
    String onlyOnTheGet;
    }


    There isn't a way to make a sub-class override the validation
    constraints, about jakarta.validation nee javax.validation, where it's figured exactly that the XSD constraints and the javax.validation
    constraints go on the one POJO definition once then are to be same and re-used throughout.

    (Anybody know a good XJC plugin that translates the XSD constraints
    exactly to javax.validation constraints? There's this krasa bit I
    haven't.)

    So, Java can't implement the "Diamond" in this sense, or, subclasses
    of course inherit all members of superclasses, about what it results
    then to just leave the constraints off the fields of the superclass
    that are different in subclasses, with regards to "Mixins", that usually
    the goal would be to add a Mixin of onlyOnTheRequest and
    onlyOnTheResponse apiece, ..., then with regards to that the
    Api methods are in these types, and then that the external
    Signature thoroughly encloses what all's in all the Apis among
    a bunch of Apis, according to these ApiMappings, for XML and JSON.

    About Mixins, the most usual sort of thing is BeanUtil copyProperties, figuring that here that's just an associative-array of objects pretty much,

    <SUB,SUP super SUB> Mixin.copyInto(SUB sub, Class<SUP super SUB>
    supClass, SUP sup);

    <SUB, SUP super SUB> SUB Mixin.construct(Class<SUB> subClass, SUP sup);


    About Xjc, basically the idea is this: a very slim xjc output, fields
    only, then that adds lombok annotations to the output classes (yeah, I
    know), so that the JAX/B binding annotations are on the fields, and then
    the lombok annotations go on the classes, then perhaps with some of the jackson annotations on the fields/classes, but mostly the
    javax.validation annotations on the fields/classes.

    The XJC has a cool convention on List members, doesn't generate setters
    by default, and always initializes empty (and, non-null) list members.
    The is about the "otherwise behaviorless" structure, what the behavior
    of access to list members should be, List or Map, or as with regards
    to "getters" and "setters", "adders" and "putters". A usual idea is
    that "if it's null it's null", very usual.

    It's sort of like "isn't there something since XJC to translate XSD
    schemas into suitable POJO's for JAX/B", and it's like, "XJC is about
    one of the greatest things with regards to anything to do with Java,
    XML, and JAX/B". XJC and JCodeModel are pretty much great.

    https://github.com/kohsuke/jaxb/blob/master/jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/ModelLoader.java



    Then, it sort of seems like for making a slimmed-down inspired-by-Xjc
    sort of thing, yet, there's still for any sort of WSDL using wscompile
    or this sort of thing, about, XML and XSD, and SOAP and WS, ..., which
    is very usual.


    It's pretty much POJO's everywhere, though I'd be a big fan of POJI's,
    but pretty much it sort of results that for plain-old-data (and no
    behavior at all except as structured data in values), POJO's everywhere,
    ..., here with the goals of declarative type-safety and validation,
    while, not exploding the number of types, and, surfacing the relations
    of inheritance of types, out of what results the framework into schema.

    POJO's everywhere pretty much have "and it must be private fields and getters/setters everywhere because the static analysis first thinks so", should be that whatever results from Schema the derived POJOs,
    and vice-versa, should mostly work off the fields and their annotations,
    what with the getters and setters then being gratuitous in the
    definition. (This is that any non-static member field is an otherwise behaviorless property, and that any conversions or coercions are either
    only boxing in the language or outside on the serialization and
    validation, type conversion and coercion.)

    There's mostly only one framework serializer in Spring about JSON,
    and it's FasterXML Jackson, while for XML, mostly one would rely
    on JAX/B annotations to reflect the richer structure and schema of XML.
    In Spring Web, there's also to be considered the
    MethodArgumentResolvers, about the corner case of headers and query parameters whose keys aren't usual Java beans identifiers, and clubbing
    those into the one or multiple Hdr or Qpa API Signature parameters,
    above, because the usual RequestParam and RequestHeader don't have one
    and MultiValueMap and so on, and KeyValuePairArray and KvpLiteral or the least-needful to model the API Mapping.

    That Java had a plain "Struct" type, ..., though the "record" class
    object is pretty first-class, ..., and most Bean-like property copiers
    will discover the getters of the properties thusly, ..., has mostly that
    the getters are named "get" and the setters named "set", ..., that
    there's something to be said for POJI's on records as immutables then
    just adding setters as the property name field1(String 1 f1).

    Then again some people want to replace _every single instance of String_
    with a strongly typed language of the String as a CharSequence, .... Or,
    at least I do, with an overall approach to Strings, Enums, and in CharSequences.

    Schema is one thing that seems missing the most in all the modern-ish HTTP-JSON-RESTy world, which is good and bad. Luckily the whole XML
    with XSD schemas really set a great example of how it should be done,
    or rather, what use-cases it should fulfill. So, it's to be expected
    that at some point JSON schema finally gets into the toolchain, because what's derived should be derived.

    So, about POJOs, they're pretty much fungible, and pretty much
    ubiquitous. While that may be so, the construct-and-build and stream-and-read use-cases are pretty much entirely different, for given types, what one would hope would result POJI's, that basically for a
    given POJO, it has two POJI's, the immutable part of the getters and the mutable part of the setters.


    class Pojo{
    String p;

    String getP() { return p; }
    void setP(String p) }{ this.p = p;}
    }

    interface PojiGet {
    String p();
    }

    interface PojiSet {
    void p(String p);
    }

    class PojoPojied implements PojoGet, PojoSet {

    }

    record PojoRecord implements PojoGet {
    String p;
    }

    The serialization and deserialization frameworks pretty much expect
    their various no-arg and all-arg constructors, about the other great
    boojum of structured data in an associate-array class property world, property order.

    A usual sort of idea is to go through a world of POJOs that exist,
    because they're everywhere and model all the things, and make
    a "derived" framework of Pojis the getters and setters for them,
    of a sort of "Imm" and "Mut" as it were, and "Get" and "Set",
    and making constructors and property order and builders then
    for whether builders result mutable or immutable, these kinds of
    things.


    class Pojo {
    String p;
    String getP() { return p;}
    void setP(String p) { this.p = p; }
    }

    interface PojiGetter {
    P p();
    }

    interface PojiSetter {
    void p(String p);
    }

    interface PojiImmutable extends Setter {
    default void p(String p) { throw new
    UnsupportedOperationException(); }
    }

    interface PojiMutable extends Setter {
    // eg, override some of the otherwise immutable
    }


    class PojoPoji implements PojiGetter, PojiSetter {

    String p;

    PojoPoji(Pojo pojo) {
    this.p =
    }

    @Override
    String p() { return p;}

    @Override
    void p(String p) { this.p = p; }
    }

    record PojoRecordPoji implement PojiGetter {

    String p;

    PojoRecordPoji(Pojo pojo) {
    this(pojo.getP()); // propertyOrder for the initializer, ....
    }
    }

    So, it's sort of the idea of an APT tool, to find everything marked @lombok.Data, and derive and generate these things, then carry along the relevant @Json... annotations.

    The property order is about the thing to get figured out, there's a
    plethora of annotations relating it in java.beans, java.xml.bind,
    the Jackson annotations, what Lombok makes, variously, all
    should mean about same, and where it is so that -parameters
    isn't necessarily so and that at runtime there isn't necessarily
    byte-code introspection, only the language and runtime's
    guaranteed reflections according to class, and record, and
    java.lang.reflect, and java.lang.annotation.

    Property order and one or the other of getP/setP or p-and/or-p.

    Pretty much bog-standard and everywhere, ....


    So, first there's the idea that HTTP APIs have a standard Signature,
    pretty much a normative signature, then about what gets involved
    as directly on the data structures to indicate their type relations,
    anything extra the plain composition of their values as plain
    old data objects, and "Beans" in a sense yet to distinguish from
    both "J2EE Beans" and "Spring Beans", variously, and their notions
    of the property editor and magic of J2EE beans vis-a-vis the module
    instance name/type association of Spring Beans, just Pojo's and
    Poji's, then plain getter/setter Pojo's and get/imm/mut Poji's.

    Schema, ..., in the language.





    So, the idea is that what results is a "Signature", or HTTP signature,
    which follows a bit of reflection about these

    request mapping annotations, Spring Web or Jersey
    serialization annotations, Jackson or JAX/B, KvpLiteral
    these SuccessResult and CovariantResult result annotations
    these CovariantFault annotations on Exceptions
    some Inner/Outer or Sub/Sup annotations to indicate things

    then it results that for an <A extends Api, AM extends ApiMapping>,
    there results a Signature, of the MethodParams, these various
    Pth, Hdr, Qpa, Req, Rsp, and the Flt types,
    that both implements ClientBuilder for the Api,
    given serializers the framework's Jackson and JAX/B,
    and client the frameworks Http, Rest, Web clients,
    and java.lang.reflect.Proxy and InvocationHandler,
    that HTTP ClientBuilders are derived from HTTP Signature.

    Then, also the OpenApi annotations are derived from the Signature,
    making it so that the Inner/Outer types of the APIs, then have
    what results an OpenApi definition (or, for what should be
    SOAP-WS and these types services, what it is), then it so results
    that it all sort of follows from the Java language declarations
    and definitions, naturally following extension of interfaces and
    classes, in the most usual sort of world of Pojos, that it results
    the Controller's just implement each of the ApiMappings and
    the Client's just implement each of the Api's according to the
    HTTP Signature of the ApiMappings, with that the ClientBuilders
    each have a totally simple implementation with very well-known
    and understood (and, guaranteed) semantics, that as well support
    the Covariant and Error return types, according to exception
    specification, in the language and neatly.

    Then, the goal would seem to be to make it so that these same sorts
    things get generated round-trip and derive round-trip, both the
    schemas, OpenApi as it may be here, and the interface, the
    Api and ApiMapping interfaces, all one neat little thing.

    I wrote one of these last month so now I re-write the exact
    same thing as it's only about ten or twenty classes then
    adding MethodArgumentResolvers to WebMvcConfigurer
    then some ExceptionHandler to the Controller to result
    the Covariant return types, then a bit of implementing
    client builders after an AbstractSignatureHttpClientBuilder,
    then for all the validation being according to jakarta.validation,
    as what results just dropping that code into any maven or gradle
    "spring-boot microservice", bit, and making it all that way.



    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Ross Finlayson@ross.a.finlayson@gmail.com to comp.lang.java.programmer on Fri Apr 19 11:49:30 2024
    From Newsgroup: comp.lang.java.programmer

    On 04/19/2024 10:22 AM, Ross Finlayson wrote:
    On 04/19/2024 09:30 AM, Ross Finlayson wrote:
    Signature API

    ccc.api
    ccc.api.exception
    ccc.api.fault

    ccc.api.client

    ccc.springsup.web

    ccc.serdes


    Api ApiMapping

    ApiFlt ApiHardFlt
    OtherCauseFault CovariantFault

    Pth Hdr Qpa Req Rsp Flt Err


    The other day I was writing a Spring Boot server,
    and the implementation of the Api looks like this

    For a service Srv, group of APIs Grp, and API Api

    public interface Srv {
    interface Grp {
    interface Api extends ccc.api.Api {

    static class Pth{}
    static class Qpa{}
    static class Hdr{}
    static class Req{}
    static class Rsp{}
    static class Flt{}
    static class Err{}


    Rsp api(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Qpa qpa,
    @Valid @NotNull Hdr hdr,
    @Valid @NotNull Req req
    ) throws ApiFlt;

    }
    }

    }

    The validation annotations have to be on the root type,
    so, they go on the Api.

    public interface SrvMapping {
    interface Grp {
    @RequestMapping
    interface Api extends Srv.Grp.Api, ApiMapping {

    @Override
    @GetMapping("/api/{pth}")
    @ResponseBody
    Rsp api(
    @PathVariable Pth pth,
    @QueryParam Qpa qpa,
    @RequestHeader Hdr hdr,
    @RequestBody Req req
    ) throws ApiFlt;

    }
    }
    }

    The request mapping and also the openapi or documentation
    interfaces have to be on the interface the controller implements,
    and they don't mean anything to the Api, so they go on the ApiMapping.

    @Controller
    public class SrvController implements SrvMapping.Grp.Api
    {
    @Override
    Srv.Grp.Rsp api(
    Srv.Grp.Pth pth,
    Srv.Grp.Qpa qpa,
    Srv.Grp.Hdr hdr,
    Srv.Grp.Req req
    ) throws ApiFlt;
    }

    The controller just implements the Api, Spring Web wires
    it up and Openapi documents it up.

    And it results sort of thusly a very simple organization of APIs.

    public interface Srv {

    interface Grp1 {
    interface Api1 { /* */ }
    interface Api2 { /* */ }
    interface Api3 { /* */ }
    interface Api4 { /* */ }
    }
    interface Grp@ {
    interface Api1 { /* */ }
    interface Api2 { /* */ }
    interface Api3 { /* */ }
    interface Api4 { /* */ }
    }
    /* */
    }

    The key is that given those, the Api and ApiMapping an entire
    Signature, of the mapping, sort of results, with adding this
    sort of ApiStatusMapping, to relate the HTTP status codes,
    with, the covariant return bodies, then it's sort of all one thing.

    ("a functional interface may still have multiple default methods ...")

    The idea is that the interfaces carry very well down from these.

    For most often usual "APIs" these days it'd often look:

    @Data
    static class MyGrp {

    }

    public interface Srv {
    interface Grp {
    interface Get1 extends ccc.api.Api {

    static class Pth{ String myGrpId;}
    static class Req extends MyGrp{};
    static class Rsp{}
    static class Flt{}
    static class Err{}

    Rsp get1(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Req req
    ) throws ApiFlt;

    }
    interface Put1 extends ccc.api.Api {

    static class Pth{ String myGrpId;}
    static class Req extends MyGrp{}
    static class Rsp{}
    static class Flt{}
    static class Err{}

    Rsp put1(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Req req
    ) throws ApiFlt;

    }
    }

    }


    public interface SrvMapping {
    interface Grp {
    @RequestMapping
    interface Api extends Srv.Grp.Get1, ApiMapping {

    @Override
    @GetMapping("/grp/{myGrpId}")
    @ResponseBody
    Rsp get1(
    @PathVariable("myGrpId") Pth pth,
    @RequestBody Req req
    ) throws ApiFlt;

    }
    @RequestMapping
    interface Api extends Srv.Grp.Put1, ApiMapping {

    @Override
    @PutMapping("/grp/{myGrpId}")
    @ResponseBody
    Rsp put1(
    @PathVariable("myGrpId") String myGrpId,
    @RequestBody Req req
    ) throws ApiFlt;

    }
    }
    }


    Then, an issue involves that the Pth Hdr Qpa Req are distinct
    types, among all the APIs, though they just extend the common
    types. Then, those usually being the outside of the document,
    so, not "in" the document as it were, all the members just get
    copied among those, interchangeably, while the types in the
    signatures, keep each API's types distinct. It results quite a few
    types yet that also makes it great as each simply can be referred
    to by its class constant, and it totally makes it so that common
    behavior is a simple matter of extension.

    Relating the HTTP status codes to the resulting response bodies,
    is for the covariant return types, or fault, and how to make a
    convention in the exceptions,


    The Signature, Api + ApiMapping, then, basically encapsulates everything
    there is to make an HTTP request and interpret an HTTP response
    according to the Api validation indicating values and ranges
    and ApiMapping mapping indicating HTTP request and response
    semantics.

    Then, the covariant response semantics, is to get figured out,
    to make it so that the exception types have a neat little convention
    to extract according to response status and headers, the response
    body, besides the usual case the success case.

    For responses with no content, it's figured to have a distinguished
    Rsp type or just to return void.

    For common types then also is for common semantics, then as
    with regards to those resulting the "schema" as what it is,
    though that this is only about "interface first" as it were
    with not much care except in the Java ecosystem, then as
    with regards to Spring Web semantics and, JAX-RS semantics, say.

    Api
    ApiMapping <- Spring Web
    ApiRsmapping <- JAX-RS Jersey


    Hdr
    Pth
    Mtx // "MatrixVariable"
    Qpa
    Req
    Rsp
    Err
    Cov1
    Cov2

    Then, how to associate status with the Covariant responses,
    is sort of for annotations and repeated annotation, that relate
    statuses, to, response bodies, then of the various kinds of response
    bodies, then to sort of adopt the OneOf of the "Variant" return
    types, among those.

    class CovariantFault extends ApiFlt

    @Success( status = 200)
    @Success(status = 201, result = Accepted201.class)
    @Success(status = 204, result = NoContent204.class)

    @Covariant(status = 400, result = Error.class)
    @Covariant(range = "4xx", result = Error.class)
    class ErrorFault extends CovariantFault { static class covariantClass =
    Error.class;}

    @Covariant(status = 404, result = NotFound404.class)
    class NotFoundException extends NovariantFault {}

    @Covariant(range = "5xx", result = RetryOrCircuitBreak.class)
    class BackendException extends CovariantFault {}

    The idea is to sort of just inspect the interface for its members,
    then find off of those the status. Then, inspect the interface
    for its exceptions, and make what results for those the covariant
    return values, and whatever other cases result from invocation.

    @ResultSuccess(status = 200) @ResultCovariant(result = {Cov1.class,
    Cov2.class})

    @ResultCovariant(status = 400, range = "4xx", result = Error.class,
    exception = ErrorFlt.class)


    public interface Srv {
    interface Grp {
    interface Api extends ccc.api.Api {

    static class Pth{}
    static class Qpa{}
    static class Hdr{}
    static class Req{}
    static class Rsp{}
    static class Flt{}
    static class Err extends Error {}
    static class ErrFlt extends ErrorFault{}
    static class Cov extends Error {}
    static class CovFlt extends CovariantFault{ static class
    covariantClass = Cov.class;}


    Rsp api(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Qpa qpa,
    @Valid @NotNull Hdr hdr,
    @Valid @NotNull Req req
    ) throws ApiFlt, ErrFlt, CovFlt;

    }
    }

    }


    For aligning with OpenApi, then there's a default range named "default",
    then whether the 2xx, 3xx, 4xx, 5xx ranges are named like 3XX or 3xx.
    (Upper case, like '5XX'.) Then the idea would be that usual sorts of
    unit tests check that the annotation match for the ApiMapping among the
    Jersey or Spring RequestMappings, the OpenApi documentation and type
    declarations, then those all being defined simply enough as a usual sort
    of HTTP Api with Pth, Hdr, Qpa, Req, Rsp, then Flt, Err, Cov, and so on.


    Anyways I got it running this way and it works pretty good,
    works just great with plain vanilla framework, and today's.

    Then, for the types, is sort of to indicate the Inner and Outer or
    Inward and Outer types, and for branching, with the idea then
    that the relations of types are defined first by inheritance for
    the composition of their contents, then as with regards to
    the document, basically for JSON and XML whether the document
    has a root in it like XML or is a branching like JSON (or that most
    usually it's a "JSON object" vis-a-vis plain values in JSON).

    This gets into two major cases, where there are alternatives
    on the outside, and where there are alternatives in the members,
    with regards to "any" and these kinds of things.

    Basically this seems for whenever extending a class, to provide
    it its own type for differentiation and declaration, whether it
    still is to be considered that it "is" the parent class, so that,
    it's really of a copy-constructor in semantics, in terms of
    assigning it values of the parent object,

    Superclass superclass = subclass ; // is assignable

    Subclass subclass = superclass ; // not assignable


    Then, the idea of declaring "Subclass" and "Superclass",
    or "Sub" and "Sup", is to make it so that it results sort
    of the thing.

    I.e., the object that only extends to establish its own
    type in the interface and signature, is to have some sort
    idiom to result that what it extends, is assignable to it,
    that this would be overloading "=" assignment, in a sense,
    for the superclass, as an instance of (the values in the structure
    of) the subclass.

    Superclass superclassInstance = subclassInstance; // is assignable

    So, the idea is to implement a method named sup,
    on these extensions, that accepts a superclass,
    and returns an instance of the same-shape sub-class
    for assignment.

    Subclass subclassInstance = Subclass.sub(superclassInstance);

    I.e., the "is-a" relation is reflective, or for, "asA", ..., "ofA".

    Subclass subclassInstance = Subclass.ofA(superclassInstance);


    For openApi then it seems for populating subtypes, but mostly
    is the idea is that the Api Signature annotations will indicate
    what openapi annotations get create, then to employ those.


    class org.PojoXsdDefinedType {}

    class MyPojo extends PojoXsdDefinedType {}

    The idea is that inside the framework, each Api has its own type,
    but on the wire, the XML-style with the document in the root,
    or the JSON-style with the document projected into the root,
    are two different styles, and the Serializer and Deserializer of
    the bodies or payloads, make for marking for an object what
    is its payload, then that the framework makes and returns the
    things, so it is simple and thorough overall, while not much
    encumbered or intrusive, and not very tightly-coupled, except
    of course all defined well according to types.

    Java has single inheritance of classes and multiple inheritance
    of interfaces, with regards to patterns like diamond and so
    on. Pretty much all the usual surround of Pojos are classes,
    vis-a-vis Poji's or plain-old-Java-interfaces.


    class MyGrp {
    int id; // notOnTheCreate
    String name;
    List<Integer> memberIndividuals;
    List<Integer> memberGroups;

    String onlyOnTheCreate;
    String onlyOnTheUpdate;
    String onlyOnTheGet;
    }

    The idea is that often the POJO will have various fields in it,
    and the validation or constraints, only apply with regards to
    being a request or response, and they can't be differentiated
    exactly and only by the type.

    class MyGrp {
    int id; // prefer Integer or boxed types everywhere, so, validation
    String name;
    List<Integer> memberIndividualIds;
    List<Integer> memberGroupIds;

    }

    class MyGrpCreateReq extends MyGrp {
    String onlyOnTheCreate;
    }
    class MyGrpUpdateReq extends MyGrp {
    String onlyOnTheUpdate;
    }

    class MyGrpGetRsp extends MyGrp {
    String onlyOnTheGet;
    }


    There isn't a way to make a sub-class override the validation
    constraints, about jakarta.validation nee javax.validation, where it's
    figured exactly that the XSD constraints and the javax.validation
    constraints go on the one POJO definition once then are to be same and
    re-used throughout.

    (Anybody know a good XJC plugin that translates the XSD constraints
    exactly to javax.validation constraints? There's this krasa bit I
    haven't.)

    So, Java can't implement the "Diamond" in this sense, or, subclasses
    of course inherit all members of superclasses, about what it results
    then to just leave the constraints off the fields of the superclass
    that are different in subclasses, with regards to "Mixins", that usually
    the goal would be to add a Mixin of onlyOnTheRequest and
    onlyOnTheResponse apiece, ..., then with regards to that the
    Api methods are in these types, and then that the external
    Signature thoroughly encloses what all's in all the Apis among
    a bunch of Apis, according to these ApiMappings, for XML and JSON.

    About Mixins, the most usual sort of thing is BeanUtil copyProperties,
    figuring that here that's just an associative-array of objects pretty
    much,

    <SUB,SUP super SUB> Mixin.copyInto(SUB sub, Class<SUP super SUB>
    supClass, SUP sup);

    <SUB, SUP super SUB> SUB Mixin.construct(Class<SUB> subClass, SUP sup);


    About Xjc, basically the idea is this: a very slim xjc output, fields
    only, then that adds lombok annotations to the output classes (yeah, I
    know), so that the JAX/B binding annotations are on the fields, and then
    the lombok annotations go on the classes, then perhaps with some of the
    jackson annotations on the fields/classes, but mostly the
    javax.validation annotations on the fields/classes.

    The XJC has a cool convention on List members, doesn't generate setters
    by default, and always initializes empty (and, non-null) list members.
    The is about the "otherwise behaviorless" structure, what the behavior
    of access to list members should be, List or Map, or as with regards
    to "getters" and "setters", "adders" and "putters". A usual idea is
    that "if it's null it's null", very usual.

    It's sort of like "isn't there something since XJC to translate XSD
    schemas into suitable POJO's for JAX/B", and it's like, "XJC is about
    one of the greatest things with regards to anything to do with Java,
    XML, and JAX/B". XJC and JCodeModel are pretty much great.

    https://github.com/kohsuke/jaxb/blob/master/jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/ModelLoader.java




    Then, it sort of seems like for making a slimmed-down inspired-by-Xjc
    sort of thing, yet, there's still for any sort of WSDL using wscompile
    or this sort of thing, about, XML and XSD, and SOAP and WS, ..., which
    is very usual.


    It's pretty much POJO's everywhere, though I'd be a big fan of POJI's,
    but pretty much it sort of results that for plain-old-data (and no
    behavior at all except as structured data in values), POJO's everywhere,
    ..., here with the goals of declarative type-safety and validation,
    while, not exploding the number of types, and, surfacing the relations
    of inheritance of types, out of what results the framework into schema.

    POJO's everywhere pretty much have "and it must be private fields and
    getters/setters everywhere because the static analysis first thinks so",
    should be that whatever results from Schema the derived POJOs,
    and vice-versa, should mostly work off the fields and their annotations,
    what with the getters and setters then being gratuitous in the
    definition. (This is that any non-static member field is an otherwise
    behaviorless property, and that any conversions or coercions are either
    only boxing in the language or outside on the serialization and
    validation, type conversion and coercion.)

    There's mostly only one framework serializer in Spring about JSON,
    and it's FasterXML Jackson, while for XML, mostly one would rely
    on JAX/B annotations to reflect the richer structure and schema of XML.
    In Spring Web, there's also to be considered the
    MethodArgumentResolvers, about the corner case of headers and query
    parameters whose keys aren't usual Java beans identifiers, and clubbing
    those into the one or multiple Hdr or Qpa API Signature parameters,
    above, because the usual RequestParam and RequestHeader don't have one
    and MultiValueMap and so on, and KeyValuePairArray and KvpLiteral or the
    least-needful to model the API Mapping.

    That Java had a plain "Struct" type, ..., though the "record" class
    object is pretty first-class, ..., and most Bean-like property copiers
    will discover the getters of the properties thusly, ..., has mostly that
    the getters are named "get" and the setters named "set", ..., that
    there's something to be said for POJI's on records as immutables then
    just adding setters as the property name field1(String 1 f1).

    Then again some people want to replace _every single instance of String_
    with a strongly typed language of the String as a CharSequence, .... Or,
    at least I do, with an overall approach to Strings, Enums, and in
    CharSequences.

    Schema is one thing that seems missing the most in all the modern-ish
    HTTP-JSON-RESTy world, which is good and bad. Luckily the whole XML
    with XSD schemas really set a great example of how it should be done,
    or rather, what use-cases it should fulfill. So, it's to be expected
    that at some point JSON schema finally gets into the toolchain, because
    what's derived should be derived.

    So, about POJOs, they're pretty much fungible, and pretty much
    ubiquitous. While that may be so, the construct-and-build and
    stream-and-read use-cases are pretty much entirely different, for given
    types, what one would hope would result POJI's, that basically for a
    given POJO, it has two POJI's, the immutable part of the getters and the
    mutable part of the setters.


    class Pojo{
    String p;

    String getP() { return p; }
    void setP(String p) }{ this.p = p;}
    }

    interface PojiGet {
    String p();
    }

    interface PojiSet {
    void p(String p);
    }

    class PojoPojied implements PojoGet, PojoSet {

    }

    record PojoRecord implements PojoGet {
    String p;
    }

    The serialization and deserialization frameworks pretty much expect
    their various no-arg and all-arg constructors, about the other great
    boojum of structured data in an associate-array class property world,
    property order.

    A usual sort of idea is to go through a world of POJOs that exist,
    because they're everywhere and model all the things, and make
    a "derived" framework of Pojis the getters and setters for them,
    of a sort of "Imm" and "Mut" as it were, and "Get" and "Set",
    and making constructors and property order and builders then
    for whether builders result mutable or immutable, these kinds of
    things.


    class Pojo {
    String p;
    String getP() { return p;}
    void setP(String p) { this.p = p; }
    }

    interface PojiGetter {
    P p();
    }

    interface PojiSetter {
    void p(String p);
    }

    interface PojiImmutable extends Setter {
    default void p(String p) { throw new
    UnsupportedOperationException(); }
    }

    interface PojiMutable extends Setter {
    // eg, override some of the otherwise immutable
    }


    class PojoPoji implements PojiGetter, PojiSetter {

    String p;

    PojoPoji(Pojo pojo) {
    this.p =
    }

    @Override
    String p() { return p;}

    @Override
    void p(String p) { this.p = p; }
    }

    record PojoRecordPoji implement PojiGetter {

    String p;

    PojoRecordPoji(Pojo pojo) {
    this(pojo.getP()); // propertyOrder for the initializer, ....
    }
    }

    So, it's sort of the idea of an APT tool, to find everything marked
    @lombok.Data, and derive and generate these things, then carry along the
    relevant @Json... annotations.

    The property order is about the thing to get figured out, there's a
    plethora of annotations relating it in java.beans, java.xml.bind,
    the Jackson annotations, what Lombok makes, variously, all
    should mean about same, and where it is so that -parameters
    isn't necessarily so and that at runtime there isn't necessarily
    byte-code introspection, only the language and runtime's
    guaranteed reflections according to class, and record, and
    java.lang.reflect, and java.lang.annotation.

    Property order and one or the other of getP/setP or p-and/or-p.

    Pretty much bog-standard and everywhere, ....


    So, first there's the idea that HTTP APIs have a standard Signature,
    pretty much a normative signature, then about what gets involved
    as directly on the data structures to indicate their type relations,
    anything extra the plain composition of their values as plain
    old data objects, and "Beans" in a sense yet to distinguish from
    both "J2EE Beans" and "Spring Beans", variously, and their notions
    of the property editor and magic of J2EE beans vis-a-vis the module
    instance name/type association of Spring Beans, just Pojo's and
    Poji's, then plain getter/setter Pojo's and get/imm/mut Poji's.

    Schema, ..., in the language.





    So, the idea is that what results is a "Signature", or HTTP signature,
    which follows a bit of reflection about these

    request mapping annotations, Spring Web or Jersey
    serialization annotations, Jackson or JAX/B, KvpLiteral
    these SuccessResult and CovariantResult result annotations
    these CovariantFault annotations on Exceptions
    some Inner/Outer or Sub/Sup annotations to indicate things

    then it results that for an <A extends Api, AM extends ApiMapping>,
    there results a Signature, of the MethodParams, these various
    Pth, Hdr, Qpa, Req, Rsp, and the Flt types,
    that both implements ClientBuilder for the Api,
    given serializers the framework's Jackson and JAX/B,
    and client the frameworks Http, Rest, Web clients,
    and java.lang.reflect.Proxy and InvocationHandler,
    that HTTP ClientBuilders are derived from HTTP Signature.

    Then, also the OpenApi annotations are derived from the Signature,
    making it so that the Inner/Outer types of the APIs, then have
    what results an OpenApi definition (or, for what should be
    SOAP-WS and these types services, what it is), then it so results
    that it all sort of follows from the Java language declarations
    and definitions, naturally following extension of interfaces and
    classes, in the most usual sort of world of Pojos, that it results
    the Controller's just implement each of the ApiMappings and
    the Client's just implement each of the Api's according to the
    HTTP Signature of the ApiMappings, with that the ClientBuilders
    each have a totally simple implementation with very well-known
    and understood (and, guaranteed) semantics, that as well support
    the Covariant and Error return types, according to exception
    specification, in the language and neatly.

    Then, the goal would seem to be to make it so that these same sorts
    things get generated round-trip and derive round-trip, both the
    schemas, OpenApi as it may be here, and the interface, the
    Api and ApiMapping interfaces, all one neat little thing.

    I wrote one of these last month so now I re-write the exact
    same thing as it's only about ten or twenty classes then
    adding MethodArgumentResolvers to WebMvcConfigurer
    then some ExceptionHandler to the Controller to result
    the Covariant return types, then a bit of implementing
    client builders after an AbstractSignatureHttpClientBuilder,
    then for all the validation being according to jakarta.validation,
    as what results just dropping that code into any maven or gradle
    "spring-boot microservice", bit, and making it all that way.






    Another usual idea is to tag the API interfaces with their
    roles,

    R Read, Read-Only
    W Write, "Write-only" or, Read/Write, Write-or-Read
    B Basic, least access
    A Admin, all access
    S Supervisor (approvals)
    T Technician (delegations)

    then for usual sort role rules on each the APIs,
    the expressions are very uniform and same.

    R | W | A : read-only
    W | A : write-or-read

    S + R | S + W | A : Supervisor required
    T+ R | T + W | A : Technician only

    S + W | A : Supervisor required
    T + W | A : Technician only

    That what's available to Basic at all looks like

    B | A | R | W | T | S

    Or, just R or W.

    These then get associated with the scopes and grants of the security
    methods.

    This is where the security methods or AuthN AuthZ
    mostly just go in the client configuration for the
    endpoint, annotating those on the Controller and
    having them build into the Client, from just a
    block of annotations on the Api and ApiMapping.

    The Endpoints is another datum with regards to the Api,
    usually about the "environment" or "stage", eg a usual
    sort of "Local, Dev, Preprod, Prod", or along the lines of
    "Local, Dev, Test, Preprod, Stage, Prod", then as with regards
    to Endpoints by stage X zone, eg "East, West, EU, JP, CN",
    or "NE, SE, NW, SW", cardinal and regional zones.

    Then the Endpoints sort of relate and then to the various
    notions of Principals the Identities and Grants and Scopes
    the Roles, about a pretty simple table or catalog or source
    of those, what are the APIs'.

    About AuthN and AuthZ and the identities and roles,
    and, delegations and the system account, and journaling
    and auditing, it's a sort of usual thing, "HTTP web services".

    Then, the idea of this Api and ApiMapping pattern,
    is basically to result that it looks more like, "Remote
    Procedure Call", from the caller's perspective being
    the same, and indeed, the same code calling to a
    given built Proxy Client or just wired right into the
    Controller, or for test fixtures of same and all sorts
    usual things, without then after that much after caring
    about the protocol in the middle, at all.


    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Ross Finlayson@ross.a.finlayson@gmail.com to comp.lang.java.programmer on Fri Apr 19 13:48:59 2024
    From Newsgroup: comp.lang.java.programmer

    On 04/19/2024 11:49 AM, Ross Finlayson wrote:
    On 04/19/2024 10:22 AM, Ross Finlayson wrote:
    On 04/19/2024 09:30 AM, Ross Finlayson wrote:
    Signature API

    ccc.api
    ccc.api.exception
    ccc.api.fault

    ccc.api.client

    ccc.springsup.web

    ccc.serdes


    Api ApiMapping

    ApiFlt ApiHardFlt
    OtherCauseFault CovariantFault

    Pth Hdr Qpa Req Rsp Flt Err


    The other day I was writing a Spring Boot server,
    and the implementation of the Api looks like this

    For a service Srv, group of APIs Grp, and API Api

    public interface Srv {
    interface Grp {
    interface Api extends ccc.api.Api {

    static class Pth{}
    static class Qpa{}
    static class Hdr{}
    static class Req{}
    static class Rsp{}
    static class Flt{}
    static class Err{}


    Rsp api(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Qpa qpa,
    @Valid @NotNull Hdr hdr,
    @Valid @NotNull Req req
    ) throws ApiFlt;

    }
    }

    }

    The validation annotations have to be on the root type,
    so, they go on the Api.

    public interface SrvMapping {
    interface Grp {
    @RequestMapping
    interface Api extends Srv.Grp.Api, ApiMapping {

    @Override
    @GetMapping("/api/{pth}")
    @ResponseBody
    Rsp api(
    @PathVariable Pth pth,
    @QueryParam Qpa qpa,
    @RequestHeader Hdr hdr,
    @RequestBody Req req
    ) throws ApiFlt;

    }
    }
    }

    The request mapping and also the openapi or documentation
    interfaces have to be on the interface the controller implements,
    and they don't mean anything to the Api, so they go on the ApiMapping.

    @Controller
    public class SrvController implements SrvMapping.Grp.Api
    {
    @Override
    Srv.Grp.Rsp api(
    Srv.Grp.Pth pth,
    Srv.Grp.Qpa qpa,
    Srv.Grp.Hdr hdr,
    Srv.Grp.Req req
    ) throws ApiFlt;
    }

    The controller just implements the Api, Spring Web wires
    it up and Openapi documents it up.

    And it results sort of thusly a very simple organization of APIs.

    public interface Srv {

    interface Grp1 {
    interface Api1 { /* */ }
    interface Api2 { /* */ }
    interface Api3 { /* */ }
    interface Api4 { /* */ }
    }
    interface Grp@ {
    interface Api1 { /* */ }
    interface Api2 { /* */ }
    interface Api3 { /* */ }
    interface Api4 { /* */ }
    }
    /* */
    }

    The key is that given those, the Api and ApiMapping an entire
    Signature, of the mapping, sort of results, with adding this
    sort of ApiStatusMapping, to relate the HTTP status codes,
    with, the covariant return bodies, then it's sort of all one thing.

    ("a functional interface may still have multiple default methods ...")

    The idea is that the interfaces carry very well down from these.

    For most often usual "APIs" these days it'd often look:

    @Data
    static class MyGrp {

    }

    public interface Srv {
    interface Grp {
    interface Get1 extends ccc.api.Api {

    static class Pth{ String myGrpId;}
    static class Req extends MyGrp{};
    static class Rsp{}
    static class Flt{}
    static class Err{}

    Rsp get1(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Req req
    ) throws ApiFlt;

    }
    interface Put1 extends ccc.api.Api {

    static class Pth{ String myGrpId;}
    static class Req extends MyGrp{}
    static class Rsp{}
    static class Flt{}
    static class Err{}

    Rsp put1(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Req req
    ) throws ApiFlt;

    }
    }

    }


    public interface SrvMapping {
    interface Grp {
    @RequestMapping
    interface Api extends Srv.Grp.Get1, ApiMapping {

    @Override
    @GetMapping("/grp/{myGrpId}")
    @ResponseBody
    Rsp get1(
    @PathVariable("myGrpId") Pth pth,
    @RequestBody Req req
    ) throws ApiFlt;

    }
    @RequestMapping
    interface Api extends Srv.Grp.Put1, ApiMapping {

    @Override
    @PutMapping("/grp/{myGrpId}")
    @ResponseBody
    Rsp put1(
    @PathVariable("myGrpId") String myGrpId,
    @RequestBody Req req
    ) throws ApiFlt;

    }
    }
    }


    Then, an issue involves that the Pth Hdr Qpa Req are distinct
    types, among all the APIs, though they just extend the common
    types. Then, those usually being the outside of the document,
    so, not "in" the document as it were, all the members just get
    copied among those, interchangeably, while the types in the
    signatures, keep each API's types distinct. It results quite a few
    types yet that also makes it great as each simply can be referred
    to by its class constant, and it totally makes it so that common
    behavior is a simple matter of extension.

    Relating the HTTP status codes to the resulting response bodies,
    is for the covariant return types, or fault, and how to make a
    convention in the exceptions,


    The Signature, Api + ApiMapping, then, basically encapsulates everything >>> there is to make an HTTP request and interpret an HTTP response
    according to the Api validation indicating values and ranges
    and ApiMapping mapping indicating HTTP request and response
    semantics.

    Then, the covariant response semantics, is to get figured out,
    to make it so that the exception types have a neat little convention
    to extract according to response status and headers, the response
    body, besides the usual case the success case.

    For responses with no content, it's figured to have a distinguished
    Rsp type or just to return void.

    For common types then also is for common semantics, then as
    with regards to those resulting the "schema" as what it is,
    though that this is only about "interface first" as it were
    with not much care except in the Java ecosystem, then as
    with regards to Spring Web semantics and, JAX-RS semantics, say.

    Api
    ApiMapping <- Spring Web
    ApiRsmapping <- JAX-RS Jersey


    Hdr
    Pth
    Mtx // "MatrixVariable"
    Qpa
    Req
    Rsp
    Err
    Cov1
    Cov2

    Then, how to associate status with the Covariant responses,
    is sort of for annotations and repeated annotation, that relate
    statuses, to, response bodies, then of the various kinds of response
    bodies, then to sort of adopt the OneOf of the "Variant" return
    types, among those.

    class CovariantFault extends ApiFlt

    @Success( status = 200)
    @Success(status = 201, result = Accepted201.class)
    @Success(status = 204, result = NoContent204.class)

    @Covariant(status = 400, result = Error.class)
    @Covariant(range = "4xx", result = Error.class)
    class ErrorFault extends CovariantFault { static class covariantClass =
    Error.class;}

    @Covariant(status = 404, result = NotFound404.class)
    class NotFoundException extends NovariantFault {}

    @Covariant(range = "5xx", result = RetryOrCircuitBreak.class)
    class BackendException extends CovariantFault {}

    The idea is to sort of just inspect the interface for its members,
    then find off of those the status. Then, inspect the interface
    for its exceptions, and make what results for those the covariant
    return values, and whatever other cases result from invocation.

    @ResultSuccess(status = 200) @ResultCovariant(result = {Cov1.class,
    Cov2.class})

    @ResultCovariant(status = 400, range = "4xx", result = Error.class,
    exception = ErrorFlt.class)


    public interface Srv {
    interface Grp {
    interface Api extends ccc.api.Api {

    static class Pth{}
    static class Qpa{}
    static class Hdr{}
    static class Req{}
    static class Rsp{}
    static class Flt{}
    static class Err extends Error {}
    static class ErrFlt extends ErrorFault{}
    static class Cov extends Error {}
    static class CovFlt extends CovariantFault{ static class
    covariantClass = Cov.class;}


    Rsp api(
    @Valid @NotNull Pth pth,
    @Valid @NotNull Qpa qpa,
    @Valid @NotNull Hdr hdr,
    @Valid @NotNull Req req
    ) throws ApiFlt, ErrFlt, CovFlt;

    }
    }

    }


    For aligning with OpenApi, then there's a default range named "default", >>> then whether the 2xx, 3xx, 4xx, 5xx ranges are named like 3XX or 3xx.
    (Upper case, like '5XX'.) Then the idea would be that usual sorts of
    unit tests check that the annotation match for the ApiMapping among the
    Jersey or Spring RequestMappings, the OpenApi documentation and type
    declarations, then those all being defined simply enough as a usual sort >>> of HTTP Api with Pth, Hdr, Qpa, Req, Rsp, then Flt, Err, Cov, and so on. >>>

    Anyways I got it running this way and it works pretty good,
    works just great with plain vanilla framework, and today's.

    Then, for the types, is sort of to indicate the Inner and Outer or
    Inward and Outer types, and for branching, with the idea then
    that the relations of types are defined first by inheritance for
    the composition of their contents, then as with regards to
    the document, basically for JSON and XML whether the document
    has a root in it like XML or is a branching like JSON (or that most
    usually it's a "JSON object" vis-a-vis plain values in JSON).

    This gets into two major cases, where there are alternatives
    on the outside, and where there are alternatives in the members,
    with regards to "any" and these kinds of things.

    Basically this seems for whenever extending a class, to provide
    it its own type for differentiation and declaration, whether it
    still is to be considered that it "is" the parent class, so that,
    it's really of a copy-constructor in semantics, in terms of
    assigning it values of the parent object,

    Superclass superclass = subclass ; // is assignable

    Subclass subclass = superclass ; // not assignable


    Then, the idea of declaring "Subclass" and "Superclass",
    or "Sub" and "Sup", is to make it so that it results sort
    of the thing.

    I.e., the object that only extends to establish its own
    type in the interface and signature, is to have some sort
    idiom to result that what it extends, is assignable to it,
    that this would be overloading "=" assignment, in a sense,
    for the superclass, as an instance of (the values in the structure
    of) the subclass.

    Superclass superclassInstance = subclassInstance; // is assignable

    So, the idea is to implement a method named sup,
    on these extensions, that accepts a superclass,
    and returns an instance of the same-shape sub-class
    for assignment.

    Subclass subclassInstance = Subclass.sub(superclassInstance);

    I.e., the "is-a" relation is reflective, or for, "asA", ..., "ofA".

    Subclass subclassInstance = Subclass.ofA(superclassInstance);


    For openApi then it seems for populating subtypes, but mostly
    is the idea is that the Api Signature annotations will indicate
    what openapi annotations get create, then to employ those.


    class org.PojoXsdDefinedType {}

    class MyPojo extends PojoXsdDefinedType {}

    The idea is that inside the framework, each Api has its own type,
    but on the wire, the XML-style with the document in the root,
    or the JSON-style with the document projected into the root,
    are two different styles, and the Serializer and Deserializer of
    the bodies or payloads, make for marking for an object what
    is its payload, then that the framework makes and returns the
    things, so it is simple and thorough overall, while not much
    encumbered or intrusive, and not very tightly-coupled, except
    of course all defined well according to types.

    Java has single inheritance of classes and multiple inheritance
    of interfaces, with regards to patterns like diamond and so
    on. Pretty much all the usual surround of Pojos are classes,
    vis-a-vis Poji's or plain-old-Java-interfaces.


    class MyGrp {
    int id; // notOnTheCreate
    String name;
    List<Integer> memberIndividuals;
    List<Integer> memberGroups;

    String onlyOnTheCreate;
    String onlyOnTheUpdate;
    String onlyOnTheGet;
    }

    The idea is that often the POJO will have various fields in it,
    and the validation or constraints, only apply with regards to
    being a request or response, and they can't be differentiated
    exactly and only by the type.

    class MyGrp {
    int id; // prefer Integer or boxed types everywhere, so, validation >>> String name;
    List<Integer> memberIndividualIds;
    List<Integer> memberGroupIds;

    }

    class MyGrpCreateReq extends MyGrp {
    String onlyOnTheCreate;
    }
    class MyGrpUpdateReq extends MyGrp {
    String onlyOnTheUpdate;
    }

    class MyGrpGetRsp extends MyGrp {
    String onlyOnTheGet;
    }


    There isn't a way to make a sub-class override the validation
    constraints, about jakarta.validation nee javax.validation, where it's
    figured exactly that the XSD constraints and the javax.validation
    constraints go on the one POJO definition once then are to be same and
    re-used throughout.

    (Anybody know a good XJC plugin that translates the XSD constraints
    exactly to javax.validation constraints? There's this krasa bit I
    haven't.)

    So, Java can't implement the "Diamond" in this sense, or, subclasses
    of course inherit all members of superclasses, about what it results
    then to just leave the constraints off the fields of the superclass
    that are different in subclasses, with regards to "Mixins", that usually >>> the goal would be to add a Mixin of onlyOnTheRequest and
    onlyOnTheResponse apiece, ..., then with regards to that the
    Api methods are in these types, and then that the external
    Signature thoroughly encloses what all's in all the Apis among
    a bunch of Apis, according to these ApiMappings, for XML and JSON.

    About Mixins, the most usual sort of thing is BeanUtil copyProperties,
    figuring that here that's just an associative-array of objects pretty
    much,

    <SUB,SUP super SUB> Mixin.copyInto(SUB sub, Class<SUP super SUB>
    supClass, SUP sup);

    <SUB, SUP super SUB> SUB Mixin.construct(Class<SUB> subClass, SUP sup);


    About Xjc, basically the idea is this: a very slim xjc output, fields
    only, then that adds lombok annotations to the output classes (yeah, I
    know), so that the JAX/B binding annotations are on the fields, and then >>> the lombok annotations go on the classes, then perhaps with some of the
    jackson annotations on the fields/classes, but mostly the
    javax.validation annotations on the fields/classes.

    The XJC has a cool convention on List members, doesn't generate setters
    by default, and always initializes empty (and, non-null) list members.
    The is about the "otherwise behaviorless" structure, what the behavior
    of access to list members should be, List or Map, or as with regards
    to "getters" and "setters", "adders" and "putters". A usual idea is
    that "if it's null it's null", very usual.

    It's sort of like "isn't there something since XJC to translate XSD
    schemas into suitable POJO's for JAX/B", and it's like, "XJC is about
    one of the greatest things with regards to anything to do with Java,
    XML, and JAX/B". XJC and JCodeModel are pretty much great.

    https://github.com/kohsuke/jaxb/blob/master/jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/ModelLoader.java





    Then, it sort of seems like for making a slimmed-down inspired-by-Xjc
    sort of thing, yet, there's still for any sort of WSDL using wscompile
    or this sort of thing, about, XML and XSD, and SOAP and WS, ..., which
    is very usual.


    It's pretty much POJO's everywhere, though I'd be a big fan of POJI's,
    but pretty much it sort of results that for plain-old-data (and no
    behavior at all except as structured data in values), POJO's everywhere, >>> ..., here with the goals of declarative type-safety and validation,
    while, not exploding the number of types, and, surfacing the relations
    of inheritance of types, out of what results the framework into schema.

    POJO's everywhere pretty much have "and it must be private fields and
    getters/setters everywhere because the static analysis first thinks so", >>> should be that whatever results from Schema the derived POJOs,
    and vice-versa, should mostly work off the fields and their annotations, >>> what with the getters and setters then being gratuitous in the
    definition. (This is that any non-static member field is an otherwise
    behaviorless property, and that any conversions or coercions are either
    only boxing in the language or outside on the serialization and
    validation, type conversion and coercion.)

    There's mostly only one framework serializer in Spring about JSON,
    and it's FasterXML Jackson, while for XML, mostly one would rely
    on JAX/B annotations to reflect the richer structure and schema of XML.
    In Spring Web, there's also to be considered the
    MethodArgumentResolvers, about the corner case of headers and query
    parameters whose keys aren't usual Java beans identifiers, and clubbing
    those into the one or multiple Hdr or Qpa API Signature parameters,
    above, because the usual RequestParam and RequestHeader don't have one
    and MultiValueMap and so on, and KeyValuePairArray and KvpLiteral or the >>> least-needful to model the API Mapping.

    That Java had a plain "Struct" type, ..., though the "record" class
    object is pretty first-class, ..., and most Bean-like property copiers
    will discover the getters of the properties thusly, ..., has mostly that >>> the getters are named "get" and the setters named "set", ..., that
    there's something to be said for POJI's on records as immutables then
    just adding setters as the property name field1(String 1 f1).

    Then again some people want to replace _every single instance of String_ >>> with a strongly typed language of the String as a CharSequence, .... Or, >>> at least I do, with an overall approach to Strings, Enums, and in
    CharSequences.

    Schema is one thing that seems missing the most in all the modern-ish
    HTTP-JSON-RESTy world, which is good and bad. Luckily the whole XML
    with XSD schemas really set a great example of how it should be done,
    or rather, what use-cases it should fulfill. So, it's to be expected
    that at some point JSON schema finally gets into the toolchain, because
    what's derived should be derived.

    So, about POJOs, they're pretty much fungible, and pretty much
    ubiquitous. While that may be so, the construct-and-build and
    stream-and-read use-cases are pretty much entirely different, for given
    types, what one would hope would result POJI's, that basically for a
    given POJO, it has two POJI's, the immutable part of the getters and the >>> mutable part of the setters.


    class Pojo{
    String p;

    String getP() { return p; }
    void setP(String p) }{ this.p = p;}
    }

    interface PojiGet {
    String p();
    }

    interface PojiSet {
    void p(String p);
    }

    class PojoPojied implements PojoGet, PojoSet {

    }

    record PojoRecord implements PojoGet {
    String p;
    }

    The serialization and deserialization frameworks pretty much expect
    their various no-arg and all-arg constructors, about the other great
    boojum of structured data in an associate-array class property world,
    property order.

    A usual sort of idea is to go through a world of POJOs that exist,
    because they're everywhere and model all the things, and make
    a "derived" framework of Pojis the getters and setters for them,
    of a sort of "Imm" and "Mut" as it were, and "Get" and "Set",
    and making constructors and property order and builders then
    for whether builders result mutable or immutable, these kinds of
    things.


    class Pojo {
    String p;
    String getP() { return p;}
    void setP(String p) { this.p = p; }
    }

    interface PojiGetter {
    P p();
    }

    interface PojiSetter {
    void p(String p);
    }

    interface PojiImmutable extends Setter {
    default void p(String p) { throw new
    UnsupportedOperationException(); }
    }

    interface PojiMutable extends Setter {
    // eg, override some of the otherwise immutable
    }


    class PojoPoji implements PojiGetter, PojiSetter {

    String p;

    PojoPoji(Pojo pojo) {
    this.p =
    }

    @Override
    String p() { return p;}

    @Override
    void p(String p) { this.p = p; }
    }

    record PojoRecordPoji implement PojiGetter {

    String p;

    PojoRecordPoji(Pojo pojo) {
    this(pojo.getP()); // propertyOrder for the initializer, ....
    }
    }

    So, it's sort of the idea of an APT tool, to find everything marked
    @lombok.Data, and derive and generate these things, then carry along the >>> relevant @Json... annotations.

    The property order is about the thing to get figured out, there's a
    plethora of annotations relating it in java.beans, java.xml.bind,
    the Jackson annotations, what Lombok makes, variously, all
    should mean about same, and where it is so that -parameters
    isn't necessarily so and that at runtime there isn't necessarily
    byte-code introspection, only the language and runtime's
    guaranteed reflections according to class, and record, and
    java.lang.reflect, and java.lang.annotation.

    Property order and one or the other of getP/setP or p-and/or-p.

    Pretty much bog-standard and everywhere, ....


    So, first there's the idea that HTTP APIs have a standard Signature,
    pretty much a normative signature, then about what gets involved
    as directly on the data structures to indicate their type relations,
    anything extra the plain composition of their values as plain
    old data objects, and "Beans" in a sense yet to distinguish from
    both "J2EE Beans" and "Spring Beans", variously, and their notions
    of the property editor and magic of J2EE beans vis-a-vis the module
    instance name/type association of Spring Beans, just Pojo's and
    Poji's, then plain getter/setter Pojo's and get/imm/mut Poji's.

    Schema, ..., in the language.





    So, the idea is that what results is a "Signature", or HTTP signature,
    which follows a bit of reflection about these

    request mapping annotations, Spring Web or Jersey
    serialization annotations, Jackson or JAX/B, KvpLiteral
    these SuccessResult and CovariantResult result annotations
    these CovariantFault annotations on Exceptions
    some Inner/Outer or Sub/Sup annotations to indicate things

    then it results that for an <A extends Api, AM extends ApiMapping>,
    there results a Signature, of the MethodParams, these various
    Pth, Hdr, Qpa, Req, Rsp, and the Flt types,
    that both implements ClientBuilder for the Api,
    given serializers the framework's Jackson and JAX/B,
    and client the frameworks Http, Rest, Web clients,
    and java.lang.reflect.Proxy and InvocationHandler,
    that HTTP ClientBuilders are derived from HTTP Signature.

    Then, also the OpenApi annotations are derived from the Signature,
    making it so that the Inner/Outer types of the APIs, then have
    what results an OpenApi definition (or, for what should be
    SOAP-WS and these types services, what it is), then it so results
    that it all sort of follows from the Java language declarations
    and definitions, naturally following extension of interfaces and
    classes, in the most usual sort of world of Pojos, that it results
    the Controller's just implement each of the ApiMappings and
    the Client's just implement each of the Api's according to the
    HTTP Signature of the ApiMappings, with that the ClientBuilders
    each have a totally simple implementation with very well-known
    and understood (and, guaranteed) semantics, that as well support
    the Covariant and Error return types, according to exception
    specification, in the language and neatly.

    Then, the goal would seem to be to make it so that these same sorts
    things get generated round-trip and derive round-trip, both the
    schemas, OpenApi as it may be here, and the interface, the
    Api and ApiMapping interfaces, all one neat little thing.

    I wrote one of these last month so now I re-write the exact
    same thing as it's only about ten or twenty classes then
    adding MethodArgumentResolvers to WebMvcConfigurer
    then some ExceptionHandler to the Controller to result
    the Covariant return types, then a bit of implementing
    client builders after an AbstractSignatureHttpClientBuilder,
    then for all the validation being according to jakarta.validation,
    as what results just dropping that code into any maven or gradle
    "spring-boot microservice", bit, and making it all that way.






    Another usual idea is to tag the API interfaces with their
    roles,

    R Read, Read-Only
    W Write, "Write-only" or, Read/Write, Write-or-Read
    B Basic, least access
    A Admin, all access
    S Supervisor (approvals)
    T Technician (delegations)

    then for usual sort role rules on each the APIs,
    the expressions are very uniform and same.

    R | W | A : read-only
    W | A : write-or-read

    S + R | S + W | A : Supervisor required
    T+ R | T + W | A : Technician only

    S + W | A : Supervisor required
    T + W | A : Technician only

    That what's available to Basic at all looks like

    B | A | R | W | T | S

    Or, just R or W.

    These then get associated with the scopes and grants of the security
    methods.

    This is where the security methods or AuthN AuthZ
    mostly just go in the client configuration for the
    endpoint, annotating those on the Controller and
    having them build into the Client, from just a
    block of annotations on the Api and ApiMapping.

    The Endpoints is another datum with regards to the Api,
    usually about the "environment" or "stage", eg a usual
    sort of "Local, Dev, Preprod, Prod", or along the lines of
    "Local, Dev, Test, Preprod, Stage, Prod", then as with regards
    to Endpoints by stage X zone, eg "East, West, EU, JP, CN",
    or "NE, SE, NW, SW", cardinal and regional zones.

    Then the Endpoints sort of relate and then to the various
    notions of Principals the Identities and Grants and Scopes
    the Roles, about a pretty simple table or catalog or source
    of those, what are the APIs'.

    About AuthN and AuthZ and the identities and roles,
    and, delegations and the system account, and journaling
    and auditing, it's a sort of usual thing, "HTTP web services".

    Then, the idea of this Api and ApiMapping pattern,
    is basically to result that it looks more like, "Remote
    Procedure Call", from the caller's perspective being
    the same, and indeed, the same code calling to a
    given built Proxy Client or just wired right into the
    Controller, or for test fixtures of same and all sorts
    usual things, without then after that much after caring
    about the protocol in the middle, at all.






    The Annotation in Java is effectively final, and not really
    extending other interfaces, and the framework (here
    Spring + Jackson + JAX/B + JSR303 validation the jakarta
    varieties, and Lombok the getter/setter generator),
    and these Signature HTTP Api annotations mentioned above,
    has that the framework is a great bit of convention,
    what results the thing.

    So, about annotations then, the goal is to have the annotation
    only appear once, then to have its intent inherited, then that
    the declarations and definitions follow so naturally in the
    language, of classes and interfaces, singly and multiply inherited,
    records, and in the semantics of calls and exceptions.

    The validation annotations, have semantics variously about
    the method arguments and return value, and the classes
    and the fields of the classes. The idea is that all the method
    arguments are annotated exactly the same, @Valid @NotNull,
    and that's it. This is where, the only method argument that
    might be a built-in are the path variables, and indeed the
    path variable @PathVariable or matrix variable @MatrixVariable,
    lives in the method signature, while otherwise the headers are
    clubbed in a Hdr and the query parameters clubbed in a Qpa
    and the request body is an object, a Req, each of those defined
    as static inner classes of the API's S.A.M. (definable as a lambda
    with an arrow function), the method arguments each get
    @Valid @NotNull in the method signature.

    Then, the validation annotations on the classes, have that
    each class is marked @Valid, then that what's required is
    marked @NotNull and the rest is whatever makes it valid,
    according to "the schema".

    The validation annotations have to go on the root of the
    inheritance hierarchy of objects, subclasses can't override
    them according to the validation implementation's
    walking up the inheritance hierarchy finding the validation
    annotations. So, they go on the Pojo's and on the Api methods,
    once each, and same each.

    It is since about Spring 5.2 or recently in the world of Spring
    that's about 6.1, that RequestMapping annotations can
    go on an interface that Controller implements, so that
    Controller need not duplicate the annotations. However,
    it only looks up one inheritance level to look for annotations,
    so the RequestMapping annotations have to be directly on
    the interface that the Controller thusly implements the convention.

    Then, the OpenApi annotations, the OpenApi 3 spec, has
    that the usual swagger-ui also looks up one inheritance level
    from the Controller, so that way, whatever's annotated on
    the RequestMappings the ApiMapping, gets picked up by
    both the Controller and the OpenApi generator and resulting
    swagger-ui.

    Api
    jakarta.validation "Validation annotations"

    ApiMapping
    org.springframework.web "RequestMapping annotations"
    io.oas.v3.swagger "OpenApi annotations"


    The "Data" objects, have involved the Lombok annotations,
    and, the FasterXml JSON annotations, and, the Validation annotations.

    The usual ideas of data objects include "DAO: Data Access Object",
    "DTO: Data Transfer Object", "DPO: Data Presentation Object",
    here basically is that Req and Rsp are DTO's while Hdr and Qpa
    are clubbed key-value-pair-arrays/multimap, then that the
    SuccessResult and CovariantResults are various DTO's the responses,
    that all the DTO's get annotated with lombok.Data and they
    get annotated with Json "serialize non-null" and "deserialize
    ignore-unknown",
    the annotations are the same on every DTO. When DTO's are
    implemented by inheritance of composition, then there's an
    extra bit involved for lombok.EqualsAndHashcode(callSuper=true),
    so the annotations are not necessarily identical on every single
    Pojo, yet they're identical for Pojos that extend others and they're
    identical for Pojos that don't extend others.

    Then the Validation annotations on the POJOs essentially
    enforce required values. Since recently the
    spring-boot-starter-validation,
    actually sort of drops in neatly and then @Validated on the @Controller
    results that it works alright, and pretty much @Validated on any
    Spring Bean sort of works alright.

    About the "default" values, that's a bit tougher to figure out.
    The idea is that the Pojo's have no initializers and what's null
    is absent and what's non-null is present. Otherwise one might
    figure that primitives like int would mean required and int i = 0
    would mean default, except 0's also just the default value of
    primitive int. So, in the language, the idea is to use Integer
    the boxed type instead of int, then as with regards to a default,
    that it sort of deserves its own annotation, so that then
    a "Defaulter" as it were can, "defaulticator", "defaultifier",
    has that as the Controller receives the validated DTO request,
    it sets the default on whatever's otherwise null.

    Then, it's figured the clubbed Hdr and Qpa look like this,
    as example

    class Hdr {
    String s;
    Boolean b;
    @Literal("X-Lit") @JsonProperty("X-Lit")
    String lit;
    List<String> repeated;
    }

    It's figured then that those headers result in the HTTP request
    like so.

    s: ...
    b: true
    X-Lit: ...
    repeated: r1
    repeated: r2

    It's similar with Qpa query parameters, they just have a convention
    that matches the key to a field name and the value to a field type.

    Why there is this @Literal or @KvpLiteral, is because, where
    everywhere in JSON serialization/deserialization the @JsonProperty
    will keep intact the key name, in the MethodArgumentResolver
    that would otherwise convert RequestHeader or RequestParam,
    to the object that it invokes on the Controller or its proxy in Spring,
    it will give exactly and only a LinkedMultiValueMap implements
    MultiValueMap,
    so that clubbed parameters in Spring will otherwise only accept
    MultiValueMap
    or concretely LinkedMultiValueMap, and don't have annotations to indicate
    the @KvpLiteral, which would otherwise clutter the method signature.
    So, without getting into the Binders or PropertyEditors, it's added
    two MethodArgumentResolver's, in WebMvcConfigurer. Then, the
    ApiMapping doesn't have @RequestHeader or @RequestParam on otherwise
    these requests. These wouldn't be required, some @RequestHEaderKvp and @RequestParamKvp, except, to get the @KvpLiteral to make the HTTP
    header key or query parameter key that doesn't make a Java field
    identifier,
    in the convention of reflection.

    Then, it's sort of figured to only support String, Integer, and Boolean,
    in those, then List's of those or otherwise not adding new types to
    the DTO's, the Pojo's, while still having them all strongly typed.

    That's not to say the signature couldn't break those out variously,

    interface Post extends Api {

    static class Headers1 {}
    static class Headers2 {}

    static class Req{}
    static class Rsp{}

    Rsp post(Headers1, Headers2, Req req) throws ApiFlt;

    }

    interface PostMapping extends Post, ApiMapping {
    @Override
    @PostMapping(value = "/grp", produces = "application/json", consumes = "application/json")
    @ResponseBody
    Rsp post(@RequestHeader Headers1, @RequestHeader Headers2, @RequestBody
    Req req) throws ApiFlt;

    }


    Yet, it's to be avoided, with exactly and only one method argument for each
    of the Hdr, Qpa, and Req. The Pth and Mtx or PathVariable and
    MatrixVariable,
    they each get their own one, figuring they definitely must be satisified
    to fulfill
    the request mapping, while the other, though non-null, may otherwise be
    empty,
    what with regards to what validates them.

    interface Get extends Api {
    static class Rsp {}

    static class Flt extends ApiFlt {}

    Rsp get(String pth1, String pth2, String pth3) throws ApiFlt, Flt;

    }

    interface GetMapping extends Get, ApiMapping {
    @Override
    @GetMapping(value = "/grp/{pth1}/{pth2}/{pth3}", consumes = "application/json")
    @ResponseBody Rsp get(@PathVariable("pth1") String pth1, @PathVariable("pth2") String pth2, @PathVariable("pth3") String pth3)
    throws ApiFlt;
    }

    It's figured to leave the Controller just marked with Controller not RestController,
    and specifically just mark the @ResponseBody on the ApiMapping, and that
    the consumes and produces as most usually application/json, isn't that
    much to be saying.

    import api.ApiFlt;
    import my.Get;
    import my.GetMapping;
    import my.Post;
    import my.PostMapping

    @RequestMapping(value = "/srv/v1")
    class Controller implements GetMapping, PostMapping {

    @Override
    Get.Rsp get(pth1, pth2, pth3) throws ApiFlt {
    throw new ApiFlt();
    }

    @Override
    Post.Rsp post(Post.Headers1 h1, Post.Headers2 h2, Post.Req req) throws
    ApiFlt {
    throw new ApiFlt();
    }

    }


    This way the Controller inherits the RequestMapping annotations from GetMapping,
    while as the names are unambiguous according to import, then it starts
    looking
    more brief than "MyServiceGroupApiMethod" types everywhere, with
    "import my.service.Srv.Group.Get" then just referencing Get's member
    inner static classes all in the Api interface.

    It works pretty well this way though it's only since about Spring 5.2 that
    the RequestMapping interface can be separated from the Controller,
    if only one deep, and also recently then that OpenApi reads off the
    v3 OpenApi annotations from the interface, also, so that Controller
    starts looking un-cluttered. The Validation implementation sort of
    smoothly works with Spring Web this way also sort of recently.
    So, it's nice to get it all together.



    One especially great thing is that the compiler in interface
    implementation,
    by declaring @Override, it's great that extension interfaces definitely
    declare the same API method its signature, and otherwise the compiler guarantees that that types are all about the same and about the declaration
    of the exception specification, then resulting what it does.


    --- Synchronet 3.21d-Linux NewsLink 1.2