-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generating a POJO using oneOf, anyOf or allOf with constraints #392
Comments
No, I'm afraid these are not supported. It would be useful if you could explain how you would expect this to work in this case? What Java would you like to see produced? |
(see also #91) |
I'm not sure what I want it to look like yet... My intention is to replace a jaxb object with a jackson object. Something similar to the xsd choice @xmlelement: <xsd:element name="name" type="xsd:string" minOccurs="0"/>
<xsd:choice>
<xsd:element name="address" type="address"/>
<xsd:element name="phone-number" type="phoneNumber"/>
<xsd:element name="note" type="xsd:string"/>
</xsd:choice>
I'm currently looking at Jackson annotations that might be useful. |
Maybe you could blow oneOf out into several properties. @JsonProperty("idString")
@Nullable
private String idString;
@JsonProperty("idNumber")
@Nullable
private String idNumber;
public void setIdString(String newIdString)
{
idNumber = null;
idString = newIdString
}
... It would require a custom gson/jackson serialization/deserialization step for that part though. It could be pretty generic and we could write it once into the jsonschema2pojo library. |
Maybe oneOf rule can be implemented as class inheritance. In the example above, it could look like this: public abstract class id {
}
public class child1 extends id {
public String type;
}
public class child2 extends id {
public int type;
} I think allOf and anyOf do not make sense in java. |
True, but we have to work with gson/Jackson right? How will they know how On Mon, 10 Aug 2015 17:47 amilinko notifications@github.com wrote:
|
Yes, it would require Jackson (not sure about gson). There is an example of serialization/deserialization here. It is described in examples 4, 5 and 6. |
Looks like you'd end up doing reflective stuff like:
There's still a big question mark over how you decide which one to decode it as. Do you run up a JSON schema validator and see which one it passes? You probably need some extension to json schema to mark which one it is as some kind of enum. oneOf is really nice from a validation side but really awkward from a model side. If you look at swagger, they've ditched oneOf support because of this. here's an alternate schema definition that achieves the same thing I think:
|
I was considering submitting a PR for oneOf, anyOf, and allOf that just generates the fields required to properly bind the data, so that at least those constructs are usable. Solid support for these semantics will probably require providing a runtime dependency with (de)serializers for Jackson and objects to model these types. If a runtime dependency is something the project could support, then code that works like this (for the id example) could be generated:
|
oneOf does make sense in Java if you think about polymorphic types. For example: "dataSourceBindings": { "type": "array", "items": { "oneOf": [ { "genericDataSourceBinding": { "type": "object", "properties": { "dataSourceName": { "type": "string" } }, "required": [ "dataSourceName" ] } }, { "multiDataSourceBinding": { "type": "object", "properties": { "dataSourceName": { "type": "string" }, "algorithmType": { "type": "string", "enum": [ "Failover", "Load-Balancing"] } }, "required": [ "dataSourceName" ] } } ] } } What I would have hoped to see generated was a DataSourceBinding class, and two subclasses of it: GenericDataSourceBinding and MultiDataSourceBinding. |
@rpatrick00 That is an interesting idea. With |
Maybe so but the current behavior is a problematic too. The object containing the dataSourceBinding property has this: List dataSourceBindings and nothing else inside this is generated...not DataSourceBinding, GenericDataSourceBinding, or MultiDataSourceBinding. I can understand the fact that you don;t want to deal with polymorphism but it should, at minimum, generate the classes for types defined inside the oneOf... |
I have created some basic test cases and an empty rule in my fork feature_unions. Is there any interest in working on this as a group? |
I would be happy to contribute to oneOf, provided I understand the various use cases that you want to support. For me, the most important use case is for polymorphic object/array types. |
@rpatrick00 is the example you have provided consistent with draft 4 of the specification? It seems like you have added an extra level under It seems like it will be hard to alter the types being composed in a
a.json
b.json
c.json
C.java
This would probably require providing some special Jackson (de)serializers. |
I am not sure Java Intersection Types accomplish the same thing as Polymorphism. Your c.json shows what I need but in my case, the only "shared interface" is the superclass and the subclasses share no other common "interface" or properties (if they did, they would be in the super type, wouldn't they). Other parts of my code are accomplishing this starting with Java and JAXB/Jackson bindings. In this module, I need to start with JSON and was hoping to generate the Java code. I was able to make something close to what I wanted work (the generated code uses List<Object> instead of List<DataSourceBinding> but it works for me). |
We could also constrain on the common superclass, so that wouldn't be a problem. I do think that the common superclass would need to come from the way the children are specified and not from their participation in a I have started a test project locally, to see what can be done for Jackson support. It seems like we would need some annotations like the following to properly support
I will push that up to github when I have some minimal examples working. NOTE: Due to Java Annotations limitations on cycles, etc., custom annotation bindings is probably not the way to go. Instead, purpose built deserializers is probably the best way to make Jackson handle these Json Schema constructs. |
It looks like static inner JsonDeserializers may be the best way to implement these features. I have created a gist showing an example of what we could create for oneOf. I didn't polish this, but it works. The basic pattern would be:
@joelittlejohn really interested in what you think of this. |
I'm not sure that this works as a general approach, how do you pick the type in the general case? Were you suggesting these deserializers are generated by the tool or are written manually to choose the type based on whatever manual checks are required? |
I see this as two problems, computing the correct merged schema and getting Jackson to deserialize what was computed. For the deserialization part, I am proposing generating the deserializers in the model. Determining a reasonable and correct way to represent the types seems like a challenge and shouldn't be attempted unless we can work with the types generated. |
As far as computing the types, a wiki page should probably be started. High level, the needed rules seem something like: For
For
For
This strategy would only work for Jackson. I have no clue how GSON deals with types like this. I guess |
It looks like something similar can be accomplished with GSON 2.3+ using |
I have added a page to the wiki with a proposal for implementing these keywords. |
I had folked and created a simple solution for "oneOf", see oneOfTypesProduceObjects Test. No inheritance,just enum and fields mapping. Basic concept is finding a best match based on required and optional fields, because sometimes there may not have any common fields in "oneOf". |
It would be nice if |
@ben-manes if the functionality was constrained to a single discriminator field, it probably would not be hard to support both Jackson and Gson. For anything more complex, you could just bail out to a generic type like JsonNode for Jackson or JsonElement for Gson. After attempting more complete support for oneOf/anyOf/allOf several times, I do not think it is feasible. There is just too much impedance between what Java object models can represent and what JSON Schema can specify. The project might as well settle for very limited support. |
Trying to force Java OO onto JsonSchema definitely doesn't work. The codegen works beautifully for RPCs, but for more complex cases I bail out to JsonPath. All I'd hope for is more support for the easy cases rather than trying to bridge paradigms completely. |
Hi all
|
@s13o I put that proposal out there and the consensus seems to be that these keywords are just too problematic to generate good solutions for. If you want basic support, I would create a PR where these keywords generate fields of Object. That could be achieved with minimal work and should result in the mappers injecting their generic node types. |
Proposal is detailed enough. It more than 1 year old already. Let's stop talking and start to do something. In a feature-branch. |
What about a getter that returns a railroad oriented data type? For example, "oneOf": [
{ "type": "number" },
{ "type": "string" }
] could generate a getter that returns something like Functional Java's Either data type. In practice you'd probably end up generating a class for each field that can be multiple types. interface SomethingEither {
default Optional<Number> number() { return Optional.empty() }
default Optional<String> string() { return Optional.empty(); }
} So you would get code generated with a method something like this: SomethingEither getSomethingEither() {
if(something instanceOf Number) {
return new SomethingEither() { public Optional<Number> number() { return Optional.of((Number) something); } };
}
if(something instanceOf String) {
return return new SomethingEither() { public Optional<String> string() { return Optional.of((String) something); } };
}
} |
@JLLeitschuh I like this. I can imagine SomethingEither having another method marked One question remains though - and it's the same challenge with many of the other solutions - how does the This schema is easy to accommodate:
this one not so much:
Lets take a really simple, concrete example:
How do we know which of the Either values should be populated for an incoming piece of JSON? What's the general rule? |
You'd have to generate some sort of unnamed type that you'd have to define just like you'd have to do for a field that defines only one object. Jackson would end up serializing into one of these objects and then you'd have to do the same casting thing. More concretely: The method would be: SomethingEither getSomethingEither() {
if(something instanceOf SomethingAnnonA) {
return new SomethingEither() { public Optional<SomethingAnnonA> somethingAnnonA() { return Optional.of((SomethingAnnonA) something); } };
}
if(something instanceOf SomethingAnnonB) {
return return new SomethingEither() { public Optional<SomethingAnnonB> somethingAnnonB() { return Optional.of((SomethingAnnonB) something); } };
}
} I don't really know how jackson works under the hood, I've never worked with jackson's API directly. I've only ever used it through spring where it does most things automagically. |
This is the part that's missing:
It's not possible for Jackson to choose one of these types. Once you have a value, returning it correctly via your Either type would be possible, but how do you correctly choose which type the value should have in the example I gave? |
Try/catch jackson deserializing every possible type that |
I think you can use |
Hello, I am jumping in this conversation to see what is the current status. Do you guys think it's actually possible to generate this Java code with feature such as @JLLeitschuh last proposals seem to do the job to me. I would like to generate Java classes for this pretty big schema: https://github.com/vega/schema/blob/master/vega-lite/v2.0.0-beta.10.json that heavily use the |
+1 for allOf, oneOf, anyOf support... |
With XSD, the concept of choice exists also, and when building the Java object based on XSD with JAXB, we get an object with getter and setter of all sub objects. In the java application, you can manage this choice. |
Any update about this issue? Especially the "allOf" field ? In my case I'm trying to generate the Java class corresponding to this schema https://raw.githubusercontent.com/oasis-open/cti-stix2-json-schemas/stix2.1/schemas/sdos/attack-pattern.json |
Any update for allOf support? |
I'm generating a POJO using the jsonschema2pojo-maven-plugin and need to pass constraints in using oneOf, anyOf & allOf.
When I try the following code in a schema validator it works:
However, the POJO after building has no constraints:
I would like to see some restrictions annotated, is this not supported with the plugin yet?
The text was updated successfully, but these errors were encountered: