From e64dd8a1a9ea7bd1d7414145bda0ecb25e71d055 Mon Sep 17 00:00:00 2001 From: meluzinj Date: Wed, 13 Mar 2024 14:59:47 +0100 Subject: [PATCH 1/2] Added includeRequireNonNullOnRequiredFields param --- .../ant/Jsonschema2PojoTask.java | 14 ++++++++++++-- .../src/site/Jsonschema2PojoTask.html | 6 ++++++ .../java/org/jsonschema2pojo/cli/Arguments.java | 7 +++++++ .../DefaultGenerationConfig.java | 5 +++++ .../org/jsonschema2pojo/GenerationConfig.java | 6 ++++++ .../org/jsonschema2pojo/rules/PropertyRule.java | 17 ++++++++++++++--- jsonschema2pojo-gradle-plugin/README.md | 3 ++- .../gradle/JsonSchemaExtension.groovy | 4 ++++ .../maven/Jsonschema2PojoMojo.java | 9 ++++++++- 9 files changed, 64 insertions(+), 7 deletions(-) diff --git a/jsonschema2pojo-ant/src/main/java/org/jsonschema2pojo/ant/Jsonschema2PojoTask.java b/jsonschema2pojo-ant/src/main/java/org/jsonschema2pojo/ant/Jsonschema2PojoTask.java index 810da8ec0..0bc72d009 100644 --- a/jsonschema2pojo-ant/src/main/java/org/jsonschema2pojo/ant/Jsonschema2PojoTask.java +++ b/jsonschema2pojo-ant/src/main/java/org/jsonschema2pojo/ant/Jsonschema2PojoTask.java @@ -66,8 +66,8 @@ * Task */ public class Jsonschema2PojoTask extends Task implements GenerationConfig { - - private boolean generateBuilders; + + private boolean generateBuilders; private boolean includeTypeInfo = false; @@ -115,6 +115,8 @@ public class Jsonschema2PojoTask extends Task implements GenerationConfig { private boolean includeJsr303Annotations = false; + private boolean includeRequireNonNullOnRequiredFields = false; + private boolean includeJsr305Annotations = false; private boolean useOptionalForGetters; @@ -947,6 +949,10 @@ public void setCustomDateTimePattern(String customDateTimePattern) { public void setRefFragmentPathDelimiters(String refFragmentPathDelimiters) { this.refFragmentPathDelimiters = refFragmentPathDelimiters; } + + public void setIncludeRequireNonNullOnRequiredFields(boolean includeRequireNonNullOnRequiredFields) { + this.includeRequireNonNullOnRequiredFields = includeRequireNonNullOnRequiredFields; + } /** * Sets the 'sourceSortOrder' property of this class @@ -1338,4 +1344,8 @@ public boolean isIncludeGeneratedAnnotation() { public boolean isUseJakartaValidation() { return useJakartaValidation; } + @Override + public boolean isIncludeRequireNonNullOnRequiredFields() { + return includeRequireNonNullOnRequiredFields; + } } diff --git a/jsonschema2pojo-ant/src/site/Jsonschema2PojoTask.html b/jsonschema2pojo-ant/src/site/Jsonschema2PojoTask.html index d2df628fc..9ecef5819 100644 --- a/jsonschema2pojo-ant/src/site/Jsonschema2PojoTask.html +++ b/jsonschema2pojo-ant/src/site/Jsonschema2PojoTask.html @@ -293,6 +293,12 @@

Parameters

No (default true) + + includeRequireNonNullOnRequiredFields + Whether to include java.util.Objects.requireNonNull(property) in each setter for required field + + No (default false) + includeJsr303Annotations Whether to include getCustomRuleFactory() { return customRuleFactory; } + @Override + public boolean isIncludeRequireNonNullOnRequiredFields() { + return includeRequireNonNullOnRequiredFields; + } + @Override public boolean isIncludeJsr303Annotations() { return includeJsr303Annotations; diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/DefaultGenerationConfig.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/DefaultGenerationConfig.java index 02cab71af..1fc497a0a 100644 --- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/DefaultGenerationConfig.java +++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/DefaultGenerationConfig.java @@ -495,4 +495,9 @@ public boolean isIncludeGeneratedAnnotation() { public boolean isUseJakartaValidation() { return false; } + + @Override + public boolean isIncludeRequireNonNullOnRequiredFields() { + return false; + } } diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/GenerationConfig.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/GenerationConfig.java index 963266c12..6b7d3c1c2 100644 --- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/GenerationConfig.java +++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/GenerationConfig.java @@ -250,6 +250,12 @@ public interface GenerationConfig { * generated Java types. */ boolean isIncludeJsr305Annotations(); + /** + * Gets the 'includeRequireNonNullOnRequiredFields' configuration option. + * + * @return Whether to add non-null check in setter method on given field. + */ + boolean isIncludeRequireNonNullOnRequiredFields(); /** * Gets the 'useOptionalForGetters' configuration option. diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java index 9bb0ecb72..4f145db3c 100644 --- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java +++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java @@ -22,14 +22,19 @@ import com.fasterxml.jackson.databind.JsonNode; import com.sun.codemodel.JBlock; +import com.sun.codemodel.JClass; import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JDocCommentable; import com.sun.codemodel.JExpr; import com.sun.codemodel.JFieldVar; +import com.sun.codemodel.JInvocation; import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; import com.sun.codemodel.JType; import com.sun.codemodel.JVar; + +import java.util.Objects; + import org.apache.commons.lang.StringUtils; /** @@ -99,14 +104,15 @@ public JDefinedClass apply(String nodeName, JsonNode node, JsonNode parent, JDef ruleFactory.getAnnotator().propertyField(field, jclass, nodeName, node); + boolean required = isRequired(nodeName, node, schema); if (isIncludeGetters) { - JMethod getter = addGetter(jclass, field, nodeName, node, isRequired(nodeName, node, schema), useOptional(nodeName, node, schema)); + JMethod getter = addGetter(jclass, field, nodeName, node, required, useOptional(nodeName, node, schema)); ruleFactory.getAnnotator().propertyGetter(getter, jclass, nodeName); propertyAnnotations(nodeName, node, schema, getter); } if (isIncludeSetters) { - JMethod setter = addSetter(jclass, field, nodeName, node); + JMethod setter = addSetter(jclass, field, nodeName, node, required); ruleFactory.getAnnotator().propertySetter(setter, jclass, nodeName); propertyAnnotations(nodeName, node, schema, setter); } @@ -256,11 +262,16 @@ private JMethod addGetter(JDefinedClass c, JFieldVar field, String jsonPropertyN return getter; } - private JMethod addSetter(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node) { + private JMethod addSetter(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node, boolean required) { JMethod setter = c.method(JMod.PUBLIC, void.class, getSetterName(jsonPropertyName, node)); JVar param = setter.param(field.type(), field.name()); JBlock body = setter.body(); + if (required && ruleFactory.getGenerationConfig().isIncludeRequireNonNullOnRequiredFields()) { + JClass ref = c.owner().ref(Objects.class); + JInvocation staticInvoke = ref.staticInvoke("requireNonNull").arg(param).arg(c.fullName()+"#"+ field.name()+" must not be null"); + body.add(staticInvoke); + } body.assign(JExpr._this().ref(field), param); return setter; diff --git a/jsonschema2pojo-gradle-plugin/README.md b/jsonschema2pojo-gradle-plugin/README.md index 29ded90c4..455d746b8 100644 --- a/jsonschema2pojo-gradle-plugin/README.md +++ b/jsonschema2pojo-gradle-plugin/README.md @@ -153,7 +153,8 @@ jsonSchema2Pojo { // Whether to include JSR-305 annotations, for schema rules like Nullable, NonNull, etc includeJsr305Annotations = false - + // Whether to add Objects.requireNonNull in setter + includeRequireNonNullOnRequiredFields = false // The Level of inclusion to set in the generated Java types (for Jackson serializers) inclusionLevel = InclusionLevel.NON_NULL diff --git a/jsonschema2pojo-gradle-plugin/src/main/groovy/org/jsonschema2pojo/gradle/JsonSchemaExtension.groovy b/jsonschema2pojo-gradle-plugin/src/main/groovy/org/jsonschema2pojo/gradle/JsonSchemaExtension.groovy index eb06e24b8..c2cbd39f5 100644 --- a/jsonschema2pojo-gradle-plugin/src/main/groovy/org/jsonschema2pojo/gradle/JsonSchemaExtension.groovy +++ b/jsonschema2pojo-gradle-plugin/src/main/groovy/org/jsonschema2pojo/gradle/JsonSchemaExtension.groovy @@ -98,6 +98,8 @@ public class JsonSchemaExtension implements GenerationConfig { Map formatTypeMapping boolean includeGeneratedAnnotation boolean useJakartaValidation + boolean includeRequireNonNullOnRequiredFields + public JsonSchemaExtension() { // See DefaultGenerationConfig @@ -150,6 +152,7 @@ public class JsonSchemaExtension implements GenerationConfig { includeDynamicGetters = false includeDynamicSetters = false includeDynamicBuilders = false + includeRequireNonNullOnRequiredFields = false formatDates = false formatTimes = false formatDateTimes = false @@ -255,6 +258,7 @@ public class JsonSchemaExtension implements GenerationConfig { |customAnnotator = ${customAnnotator.getName()} |customRuleFactory = ${customRuleFactory.getName()} |includeJsr303Annotations = ${includeJsr303Annotations} + |includeRequireNonNullOnRequiredFields = ${includeRequireNonNullOnRequiredFields} |includeJsr305Annotations = ${includeJsr305Annotations} |useOptionalForGetters = ${useOptionalForGetters} |sourceType = ${sourceType.toString().toLowerCase()} diff --git a/jsonschema2pojo-maven-plugin/src/main/java/org/jsonschema2pojo/maven/Jsonschema2PojoMojo.java b/jsonschema2pojo-maven-plugin/src/main/java/org/jsonschema2pojo/maven/Jsonschema2PojoMojo.java index 5c3d4d279..508ce2f14 100644 --- a/jsonschema2pojo-maven-plugin/src/main/java/org/jsonschema2pojo/maven/Jsonschema2PojoMojo.java +++ b/jsonschema2pojo-maven-plugin/src/main/java/org/jsonschema2pojo/maven/Jsonschema2PojoMojo.java @@ -331,7 +331,10 @@ public class Jsonschema2PojoMojo extends AbstractMojo implements GenerationConfi */ @Parameter(property = "jsonschema2pojo.includeJsr303Annotations", defaultValue = "false") private boolean includeJsr303Annotations = false; - + + + @Parameter(property = "jsonschema2pojo.includeRequireNonNullOnRequiredFields", defaultValue = "false") + private boolean includeRequireNonNullOnRequiredFields = false; /** * Whether to include * JSR-305 annotations @@ -992,6 +995,10 @@ public Class getCustomRuleFactory() { } } + @Override + public boolean isIncludeRequireNonNullOnRequiredFields() { + return includeRequireNonNullOnRequiredFields; + } @Override public boolean isIncludeJsr303Annotations() { return includeJsr303Annotations; From 9ae09a46af1833a4141f98473aa48f7bf6f94037 Mon Sep 17 00:00:00 2001 From: meluzinj Date: Thu, 14 Mar 2024 13:03:30 +0100 Subject: [PATCH 2/2] Added nonnull check even for initializers of enums --- .../jsonschema2pojo/rules/DefaultRule.java | 10 +++++ .../jsonschema2pojo/rules/PropertyRule.java | 38 +++++++++++-------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/DefaultRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/DefaultRule.java index a5f2807e4..5ba68cbab 100644 --- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/DefaultRule.java +++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/DefaultRule.java @@ -96,6 +96,13 @@ public JFieldVar apply(String nodeName, JsonNode node, JsonNode parent, JFieldVa } else if (fieldType.startsWith(String.class.getName()) && node != null ) { field.init(getDefaultValue(field.type(), node)); } else if (defaultPresent) { + boolean requireNonNullCheck = (ruleFactory.getGenerationConfig().isIncludeRequireNonNullOnRequiredFields() && isRequired(nodeName, node, currentSchema)); + if (requireNonNullCheck) { + + if (field.type() instanceof JDefinedClass && ((JDefinedClass) field.type()).getClassType().equals(ClassType.ENUM)) { + field.annotate(SuppressWarnings.class).param("value", "null"); + } + } field.init(getDefaultValue(field.type(), node)); } @@ -107,6 +114,9 @@ static JExpression getDefaultValue(JType fieldType, JsonNode node) { return getDefaultValue(fieldType, node.asText()); } + private boolean isRequired(String nodeName, JsonNode node, Schema schema) { + return PropertyRule.isRequired(nodeName, node, schema); + } static JExpression getDefaultValue(JType fieldType, String value) { fieldType = fieldType.unboxify(); diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java index 4f145db3c..c98794071 100644 --- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java +++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java @@ -118,7 +118,7 @@ public JDefinedClass apply(String nodeName, JsonNode node, JsonNode parent, JDef } if (ruleFactory.getGenerationConfig().isGenerateBuilders()) { - addBuilderMethod(jclass, field, nodeName, node); + addBuilderMethod(jclass, field, nodeName, node, required); } if (node.has("pattern")) { @@ -142,7 +142,7 @@ public JDefinedClass apply(String nodeName, JsonNode node, JsonNode parent, JDef return jclass; } - private boolean hasEnumerated(Schema schema, String arrayFieldName, String nodeName) { + protected static boolean hasEnumerated(Schema schema, String arrayFieldName, String nodeName) { JsonNode array = schema.getContent().get(arrayFieldName); if (array != null) { for (JsonNode requiredNode : array) { @@ -154,7 +154,7 @@ private boolean hasEnumerated(Schema schema, String arrayFieldName, String nodeN return false; } - private boolean hasFlag(JsonNode node, String fieldName) { + protected static boolean hasFlag(JsonNode node, String fieldName) { if (node.has(fieldName)) { final JsonNode requiredNode = node.get(fieldName); return requiredNode.asBoolean(); @@ -163,15 +163,15 @@ private boolean hasFlag(JsonNode node, String fieldName) { return false; } - private boolean isDeclaredAs(String type, String nodeName, JsonNode node, Schema schema) { + protected static boolean isDeclaredAs(String type, String nodeName, JsonNode node, Schema schema) { return hasEnumerated(schema, type, nodeName) || hasFlag(node, type); } - private boolean isRequired(String nodeName, JsonNode node, Schema schema) { + protected static boolean isRequired(String nodeName, JsonNode node, Schema schema) { return isDeclaredAs("required", nodeName, node, schema); } - private boolean useOptional(String nodeName, JsonNode node, Schema schema) { + protected static boolean useOptional(String nodeName, JsonNode node, Schema schema) { return isDeclaredAs("javaOptional", nodeName, node, schema); } @@ -267,44 +267,50 @@ private JMethod addSetter(JDefinedClass c, JFieldVar field, String jsonPropertyN JVar param = setter.param(field.type(), field.name()); JBlock body = setter.body(); - if (required && ruleFactory.getGenerationConfig().isIncludeRequireNonNullOnRequiredFields()) { - JClass ref = c.owner().ref(Objects.class); - JInvocation staticInvoke = ref.staticInvoke("requireNonNull").arg(param).arg(c.fullName()+"#"+ field.name()+" must not be null"); - body.add(staticInvoke); - } + addRequireNonNullCheck(c, field, required, param, body); body.assign(JExpr._this().ref(field), param); return setter; } - private JMethod addBuilderMethod(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node) { + public void addRequireNonNullCheck(JDefinedClass c, JFieldVar field, boolean required, JVar param, JBlock body) { + if (required && ruleFactory.getGenerationConfig().isIncludeRequireNonNullOnRequiredFields()) { + JClass ref = c.owner().ref(Objects.class); + JInvocation staticInvoke = ref.staticInvoke("requireNonNull").arg(param).arg(c.fullName()+"#"+ field.name()+" must not be null"); + body.add(staticInvoke); + } + } + + private JMethod addBuilderMethod(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node, boolean required) { JMethod result = null; if(ruleFactory.getGenerationConfig().isUseInnerClassBuilders()) { - result = addInnerBuilderMethod(c, field, jsonPropertyName, node); + result = addInnerBuilderMethod(c, field, jsonPropertyName, node, required); } else { - result = addLegacyBuilder(c, field, jsonPropertyName, node); + result = addLegacyBuilder(c, field, jsonPropertyName, node, required); } return result; } - private JMethod addLegacyBuilder(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node) { + private JMethod addLegacyBuilder(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node, boolean required) { JMethod builder = c.method(JMod.PUBLIC, c, getBuilderName(jsonPropertyName, node)); JVar param = builder.param(field.type(), field.name()); JBlock body = builder.body(); + addRequireNonNullCheck(c, field, required, param, body); body.assign(JExpr._this().ref(field), param); body._return(JExpr._this()); return builder; } - private JMethod addInnerBuilderMethod(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node) { + private JMethod addInnerBuilderMethod(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node, boolean required) { JDefinedClass builderClass = ruleFactory.getReflectionHelper().getBaseBuilderClass(c); JMethod builderMethod = builderClass.method(JMod.PUBLIC, builderClass, getBuilderName(jsonPropertyName, node)); JVar param = builderMethod.param(field.type(), field.name()); JBlock body = builderMethod.body(); + addRequireNonNullCheck(c, field, required, param, body); body.assign(JExpr.ref(JExpr.cast(c, JExpr._this().ref("instance")), field), param); body._return(JExpr._this());