-
Notifications
You must be signed in to change notification settings - Fork 14
Support for anyOf null, object #17
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
Comments
Thanks for this. You say it can be implemented easily, and you're right that it wouldn't be difficult to add code to look for precisely this case and substitute a schema with The generator currently doesn't try to do anything meaningful with |
@pwall567 - First of all, thanks for this library! I am testing your suggested workaround and ran into an issue with validation and code generation of nullable fields that I wanted to get your take on. We are going to start defining canonical, named types in our schema and referencing them with definitions:
SomeCommonType:
type: object
properties:
someProp:
type: string
SomeType:
type: object
properties:
commonType:
"$ref": "#/definitions/SomeCommonType" The library generates code correctly for this, but we run into problems when the SomeType:
type: object
properties:
commonType:
type: ["null", object]
"$ref": "#/definitions/SomeCommonType" This makes this library generate the code we want, but this JSON schema doesn't actually validate correctly: while the type allows null, the referenced sub-schema does not, so this schema is not actually viable for us to use for validation. From our experimentation, it seems that the only way to use canonical definitions and SomeType:
type: object
properties:
commonType:
oneOf:
- type: "null"
- "$ref": "#/definitions/SomeCommonType" I can work around this by transforming our canonical schema (which uses the Let me know if I'm missing something (e.g., is there an alternative you see that we're not seeing?). It seems like nullability is a something this library would support without this workaround. If it doesn't yet support it, what do you think about adding limited support for |
Hi @cmpaul , there is a simple solution to your problem – if you're prepared to accept the same compromise that I adopted in relation to
What would you expect to see generated for This shows the way round your problem. Just by omitting the property name from the This may not be what the authors of the JSON Schema specification had in mind, but it's difficult to see how else we could generate usable code from the above example. |
So it seems both of these workarounds are actually forcing the users to create a different schema than before, in a way that it actually validates different JSONs. For example your last suggestion allows: { "firstName": "Work", "lastName": "Around" } while the original schema with all 3 fields in the required list doesn't allow that: { "firstName": "Work", "middleName": null, "lastName": "Around" } "Omitted", and "existing but null" can make a meaningful difference in the API (not with middle name, but in other cases). Java/Kotlin is not able to express this though and they're logically both mapped to nullable fields. |
As I said, it involves a compromise. Your second example would not validate against the schema, but it would deserialize into the generated Kotlin. If you're concerned to reject this invalid case, you could validate the JSON prior to deserialization, and the It might be possible to generate Kotlin that would distinguish between It's my understanding that most users of the code generator are comfortable with the compromise, but I'm always willing to listen to ideas for improving the project. |
@pwall567 - Thank you! I see two downsides to the workaround you suggest. The first is that it prevents us from being able to ensure the presence of correctly formatted keys. In your example, consider the JSON payload: { "firstName": "John", "midleName": "Fitzgerald", "lastName": "Kennedy" } Notice that Second, this workaround does not work for an array of nullable fields. Consider an example where we want to define a list that contains items that are either SomeType:
type: object
properties:
someArray:
type: array
items:
"$ref": "#/definitions/SomeCommonType"
required:
# Nothing required This results in a data class with val someArray: List<SomeCommonType>? = null This isn't quite what we want, since this means that the list itself can be val someArray: List<SomeCommonType?> Right now, we can generate 2 schemas as a workaround: 1 that works for validation (using Are there other avenues we can explore? |
I see your misspelling problem as a different issue. Your JSON deserialization library will almost certainly have an option to reject unrecognised properties (I recommend the kjson library, which defaults to this behaviour, but other libraries have optional settings to the same effect). And if you are using JSON Schema Validation, the But I do accept that the use of
will probably achieve what you want, because the I'm starting to come around to the original proposal. I have tried to avoid putting in code for very narrow cases, but I think I may have to accept that this is a form of usage that is sufficiently frequently required that it justifies special treatment. What I am thinking of is allowing either I'll try to get a version for you (both) to test in a few days. |
On second thoughts – don't try the example in my previous post (using |
OK, I've implemented the special case of
should work as you expect. I've documented this in the README. (The explanation is probably not particularly clear, but anyone who has encountered the issue should be able to grasp it.) Version 0.87 includes this implementation; give it a try and let me know if it resolves this issue. |
Thank you, Peter! 🙇 Will test this today and let you know how it goes on our side. |
@pwall567 Confirmed! This works beautifully for us. Thanks again for the amazing turn-around on this. |
Way better @pwall567, now the generated code is usable, thank you! I wrote a quick script to test it ( @file:DependsOn("net.pwall.json:json-kotlin-schema-codegen:0.88")
import net.pwall.json.schema.codegen.CodeGenerator
import java.io.File
val codeGenerator = CodeGenerator().apply {
baseDirectoryName = "generated"
basePackageName = "com.github.repository"
}
// FullRepository.schema.json is a copy-paste of the response JSON Schema from
// https://docs.github.com/en/rest/repos/repos#get-a-repository
codeGenerator.generate(File("FullRepository.schema.json")) Compare these two outputs, heaven and earth... |
Uh oh!
There was an error while loading. Please reload this page.
I think there's an edge case of
oneOf
(#2) that can be implemented easily.I converterted https://docs.github.com/en/rest/repos/repos#get-a-repository 's "Response Schema" and I got
val license: Any
instead ofval license: License?
The text was updated successfully, but these errors were encountered: