jakartaee / jsonb-api

Jakarta JSON Binding
https://eclipse-ee4j.github.io/jsonb-api/
Other
78 stars 39 forks source link

Introspection API #189

Open andymc12 opened 5 years ago

andymc12 commented 5 years ago

Jackson has some handy JSON introspection APIs that could be useful for things like generating GraphQL schemas or OpenAPI templates, etc. It would be nice if JSON-B offered similar APIs to allow a user to query JSON fields based on the annotations on a given entity class.

As an example, suppose you want to generate a GraphQL schema from the following entity class:

public class Widget {

    private String name;
    @JsonbProperty("qty")
    private int quantity = -1;
    private double weight = -1.0;
    @JsonbTransient
    private Object ignorableObject;
...
    @JsonbProperty("tonnage")
    private int setWeight(double weight) {
        this.weight = weight;
    }
...
}

I would expect to be able to take the Widget class, introspect it and generate a GraphQL schema snippet like this:

input WidgetInput @_mappedType(type : "__internal__") {
  name: String @_mappedInputField(inputField : "__internal__")
  qty: Int! @_mappedInputField(inputField : "__internal__")
  tonnage: Float! @_mappedInputField(inputField : "__internal__")
}

Note that @JsonbProperty and @JsonbTransient annotations are taken into account.

Ideally, an API might exist similar to this:

JsonbSchema schema = Jsonb.schemaFromClass(Widget.class);
Map<String,ValueType> serializedFieldNames = schema.getSerializedFieldNamesAndTypes();

// for each entry in the map, write out the GraphQL schema using the field name and converting the JSON ValueType to GraphQL type

Likewise it would be good to also get the deserializedFieldNames so that users could accurately predict what JSON fields will exist when deserializing an instance of the specified class.

The actual API isn't as important to me as is the ability to easily get the JSON schema that would be used when serializing/deserializing an instance of a given class.

Thanks for considering!

rmannibucau commented 5 years ago

Hi Andy

In the context of openapi you can surely reuse https://github.com/apache/geronimo-openapi/blob/master/geronimo-openapi-impl/src/main/java/org/apache/geronimo/microprofile/openapi/impl/processor/SchemaProcessor.java

Now at jsonb, json schema has an issue which is that an adapter or serializer can make the impl not able to know at all the schema. Would you expect to fail if so?

I also like the introspector api, i use johnzon internal for now in apps needing it but standardizing it - without making it too verbose - can be worth it, at least something giving properties with their context (adapter, name, nillable, field/methods, class, etc)

andymc12 commented 5 years ago

Hi Romain,

Thanks for the pointers.

Now at jsonb, json schema has an issue which is that an adapter or serializer can make the impl not able to know at all the schema. Would you expect to fail if so?

I haven't done much with adapters or custom serializers, but iiuc, they could be used to serialize an object "differently" than simplejsonb.toJson(myObject)? Perhaps in such a case, then probably throwing some sort of unsupported exception is probably the best option. I think anything else would be a breaking change, right? (i.e. forcing the serializer to also implement an introspector).

Thanks again for the quick reply!

rmannibucau commented 5 years ago

You can also meta configure it with a new @JsonbSchemaProvider on the serializer/adapter but sounds complicated foe nothing.

m0mus commented 3 years ago

To get the precise result containing a serialized object with all possible customizations one need to actually serialize it and extract all needed information from the result. We may add a method to serialize directly to JsonValue skipping String result. This solution (workaroud?) is smelling a bit, but on the other hand it gives you a result with all possible adapters/serializers applied.

rmannibucau commented 3 years ago

@m0mus this does not work because your solution assumes you have something to serialize. It has 2 blockers:

  1. it is not always the case with integration code (typically when you generate a schema you don't have anything to serialize) - == static analyzis
  2. you assume the serialization is representative - adapters/(de)serializers can depend of a context - so you get a misleading output
  3. the customizations (adapters/(de)serializers) can fail