Open oliTheTM opened 2 years ago
False-Negative?
This schema seems to work fine for me when I try it at jsonschema2pojo.org, which suggests that you have a problem in your own code.
If you remove all the additional code you have added to modify the classes, and just build the result of schemaMapper.generate, does it work correctly?
I'll try that now, thanks.
Right, so what exactly do you get as an output when you test this in your env? Also, what version of the library are you using?
If I run it just by itself without config I don't even produce a file anymore.. :(
@oliTheTM URI's like "https://domain/schema/address.schema.json"
are not resolvable and hence were probably omitted by joelittlejohn when attempting to validate the claim.
If those ref's are omitted (there's no possibility to determine their content) jsonschema2pojo
ver. 1.1.1 generated output that starts has following content (providing only head and tail of body):
import java.util.HashMap;
import java.util.Map;
import javax.annotation.processing.Generated;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonValue;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"propertyValuation",
"propertyType",
"bedrooms",
"keyWorkerScheme",
"buyToLet",
"tenure",
"floors",
"country"
})
@Generated("jsonschema2pojo")
public class Property {
/**
*
* (Required)
*
*/
@JsonProperty("propertyValuation")
private Double propertyValuation;
/**
*
* (Required)
*
*/
@JsonProperty("propertyType")
private Property.PropertyType propertyType;
... CODE DELIBERATELY OMITTED TO REDUCE SIZE ...
@Generated("jsonschema2pojo")
public enum Tenure {
LEASEHOLD("Leasehold"),
FREEHOLD("Freehold");
private final String value;
private final static Map<String, Property.Tenure> CONSTANTS = new HashMap<String, Property.Tenure>();
static {
for (Property.Tenure c: values()) {
CONSTANTS.put(c.value, c);
}
}
Tenure(String value) {
this.value = value;
}
@Override
public String toString() {
return this.value;
}
@JsonValue
public String value() {
return this.value;
}
@JsonCreator
public static Property.Tenure fromValue(String value) {
Property.Tenure constant = CONSTANTS.get(value);
if (constant == null) {
throw new IllegalArgumentException(value);
} else {
return constant;
}
}
}
}
So if the claim holds that nothing is generated without providing custom configuration - perhaps the issue is with referenced schemas
I have ordered my schemas starting with the Independant ones and then followed by 1st degree dependent ones then 2nd, etc..
I have observed that this works for other entities of my model.
Could it be the "if"
expression that's part of this schema that's the problem??
I mean, surely it reads the URL as an ID and just pattern-matches with the IDs of pre-processed schemas; no??
It didn't turn out to be a problem for me, here's what steps have been taken:
"address": {
"$ref": "https://domain/schema/address.schema.json"
},
"assetCharges": {
"type": "array",
"items": {
"$ref": "https://domain/schema/property-asset-charge.json"
}
}
jsonschema2pojo -s Property.json -t .
Source type
to be JSON Schema
4.b. Clicked Preview buttonBut isn't it true that the $ref
could be either an ID lookup or, if there were a schema-register, an HTTP|GET. Then, in my case it would be a lookup because the $id
matches an entity that it parsed before? Right?
What I'm trying to say is, does it not remember what it processed before???
It didn't turn out to be a problem for me, here's what steps have been taken:
- json schema copied from Generator generated Empty Java class from perfectly valid Jackson Schema #1387 (comment)
- following parts removed from json schema file
"address": { "$ref": "https://domain/schema/address.schema.json" },
"assetCharges": { "type": "array", "items": { "$ref": "https://domain/schema/property-asset-charge.json" } }
- following command executed:
jsonschema2pojo -s Property.json -t .
- copied json schema (with ref's removed from it) to https://www.jsonschema2pojo.org/ 4.a. Selected
Source type
to beJSON Schema
4.b. Clicked Preview button
I really can't omit those dependencies, sorry. There needs to be another way. Besides, it does actually seem to work in most cases.
I assume the answer to my question is Yes. If that is so, what is causing this particular schema to return empty?
You still haven't shown me what is produced on your end?
You still haven't shown me what is produced on your end?
Partial output was provided here Also all the steps were provided - and it should be possible to reproduce output.
Without content of $ref
's issue wasn't reproduced
There is a conditional part to the schema (the "if"
components). I would like to see how that got interpreted.
Unfortunately this is omitted from the partial output.
Or if you like you can just tell me how "if"
components are generally handled?
You still haven't shown me what is produced on your end?
Partial output was provided here Also all the steps were provided - and it should be possible to reproduce output.
Without content of
$ref
's issue wasn't reproduced
I cannot ignore the $ref
's
I cannot ignore the $ref's
It's understood as should be understood that without these $ref
's being valid/reachable/having meaningful content it's impossible to replicate your issue.
Or if you like you can just tell me how "if" components are generally handled?
It's quite simple - conditional subschemas are not supported they are ignored, to assert that claim we could take an overly simplified version of schema at hand:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://domain/schema/property.schema.json",
"type": "object",
"additionalProperties": false,
"required": [
"buyToLet"
],
"properties": {
"buyToLet": {
"type": "boolean"
}
},
"if": {
"properties": { "buyToLet": { "const": true } }
},
"then": {
"properties": {
"buyToLetType": {
"type": "string",
"enum": ["Commercial", "Consumer"]
}
},
"required": ["buyToLetType"],
"if": {
"properties": { "buyToLetType" : { "const": "Commercial" } }
},
"then": {
"properties": {
"selfFunding": {
"type": "boolean"
}
},
"required": ["selfFunding"]
}
}
}
Which (jsonschema2pojo.bat -s Property.json -t .
) produces following result:
import javax.annotation.processing.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"buyToLet"
})
@Generated("jsonschema2pojo")
public class Property {
/**
*
* (Required)
*
*/
@JsonProperty("buyToLet")
private Boolean buyToLet;
/**
*
* (Required)
*
*/
@JsonProperty("buyToLet")
public Boolean getBuyToLet() {
return buyToLet;
}
/**
*
* (Required)
*
*/
@JsonProperty("buyToLet")
public void setBuyToLet(Boolean buyToLet) {
this.buyToLet = buyToLet;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(Property.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('[');
sb.append("buyToLet");
sb.append('=');
sb.append(((this.buyToLet == null)?"<null>":this.buyToLet));
sb.append(',');
if (sb.charAt((sb.length()- 1)) == ',') {
sb.setCharAt((sb.length()- 1), ']');
} else {
sb.append(']');
}
return sb.toString();
}
@Override
public int hashCode() {
int result = 1;
result = ((result* 31)+((this.buyToLet == null)? 0 :this.buyToLet.hashCode()));
return result;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if ((other instanceof Property) == false) {
return false;
}
Property rhs = ((Property) other);
return ((this.buyToLet == rhs.buyToLet)||((this.buyToLet!= null)&&this.buyToLet.equals(rhs.buyToLet)));
}
}
Is there any configuration I can use (an overload e.g.) that allows me to manage "if"
elements?
Is there any configuration I can use (an overload e.g.) that allows me to manage "if" elements?
Perhaps overriding RuleFactory::getObjectRule
to return extended/customized ObjectRule
Is there any configuration I can use (an overload e.g.) that allows me to manage "if" elements?
Perhaps overriding
RuleFactory::getObjectRule
to return extended/customizedObjectRule
Er... how exactly do you make a custom ObjectRule
?
Also, ObjectRule
has protected instantiation.
Thanks.
There are several strategies, for example:
ObjectRule
and make adjustmentsObjectRule
and override method callsObjectRule
wrapper/delegatorI can't do the 1st 2 because, as I said, ObjectRule
has protected instantiation.
A practical example would be nice.
Thanks.
static class CustomObjectRule extends ObjectRule {
public CustomObjectRule(
RuleFactory ruleFactory,
ParcelableHelper parcelableHelper,
ReflectionHelper reflectionHelper) {
super(ruleFactory, parcelableHelper, reflectionHelper);
}
@Override
public JType apply(String nodeName, JsonNode node, JsonNode parent, JPackage _package, Schema schema) {
final JType result = super.apply(nodeName, node, parent, _package, schema);
// custom logic goes here
return result;
}
}
static {
GenerationConfig config = new DefaultGenerationConfig() {
@Override
public boolean isIncludeGeneratedAnnotation() {
return false;
}
};
schemaMapper = new SchemaMapper(
new RuleFactory(
config,
new Jackson2Annotator(config),
new SchemaStore()) {
@Override
public Rule<JPackage, JType> getObjectRule() {
return new CustomObjectRule(this, new ParcelableHelper(), getReflectionHelper());
}
},
new SchemaGenerator());
schemaTransformer = new JCodeModel();
}
One more question sorry.
Is this method apply
called multiple times during 1 class generation or is it only called once?
I assume the former given it has the parameter nodeName
.
ObjectRule::apply
should be called once per object definition.
Ah.. so then how would I traverse the Node tree in order to find an "if"
?
Ah.. so then how would I traverse the Node tree in order to find an "if" ?
In provided example above you'd be doing it here // custom logic goes here
\ P.S. Please note that:
questions how to handle/implement if/then logic are not related to given topic
answer to "False-Negative?" has been provided to the best extent given the limited input set
Let me do some things and get back to you as to whether/not there really is an Issue; sorry.
No problem.
@joelittlejohn @unkish @HanSolo @davidpadbury What do you think of this?\/ It's only possible if I can mute & clone schemas & their components.
[*Premise: jsonSchema2POJO is called on the original schema and the following hook is triggered*]
a. PARSE the Original schema in order to compute (propertyDefinitions : Map<String, (Property : <name,JSONtype,required?,predicate:Function<?, bool>,generator:Function<Random,?>>)>)
b. ENUMERATE the conditional-part of the Original-Schema in order to compute (polymorphisms : List<Polymorphism>)
c. GIVEN propertyDefinitions & polymorphisms..
d. DELETE the "if","then","else" on the original schema
e. COMPLETE the generation of the new class corresponding to the original-schema without ifThenElse
f. ASSIGN the superType property to all elements in polymorphisms as this newly generated type
g. COPY the Original Schema as a Polymorphism schema |polymorphisms| times
h. ForAll schema copies & corresponding polymorphisms (<Si, Pi>):
h1. Use Pi in order to MUTE Si such that:
h1i. Iff required then ensures existence in "required" JsonNode
h1ii. The type is polymorphic to JSONtype
h2. CALL jsonSchema2POJO on Si
h3. GIVEN another hook in jsonSchema2POJO; it's called only now, then it does the following:
h3i. Mute the generated-class so that it inherits from Si.superClass (see [f])
h3ii. Mute the generated-class constructor so that it initially calls super()
h3iii. Mute said constructor again so that all predicates of Si are asserted else EXCEPTION
h4. COMPLETE the generation of this sub-class
h5. ASSIGN Si.subType as this new generated class
[*EVERY OBJECT HERE/\ INTERNAL TO GeneratedClassFactory*]
i. GIVEN all polymorphism Java classes are now generated (and all inherit the super) and are determined by their associated Predicate & Generator..
j. STORE all of this information in GeneratedClassFactory; in order for the following to be applied:
j1. GeneratedClassFactory::newSample : <Class<T>, Integer> --> List<T>
j2. GeneratedClassFactory::deserialize : <String, Class<T>> --> ~T
[*Since any Polymorphism corresponds to a Test-Case, it follows that newSample knows, ahead of time, which Polymorphism to use*]
Here is the schema:
Here's the Java file image:
Here's my config: