${basedir}/src/main/resources/schema
com.example.types
@@ -33,9 +32,9 @@ Useful pages:
* **[Getting started](https://github.com/joelittlejohn/jsonschema2pojo/wiki/Getting-Started)**
* **[How to contribute](https://github.com/joelittlejohn/jsonschema2pojo/blob/master/CONTRIBUTING.md)**
* [Reference](https://github.com/joelittlejohn/jsonschema2pojo/wiki/Reference)
- * [Latest Javadocs](https://joelittlejohn.github.io/jsonschema2pojo/javadocs/0.5.1/)
- * [Documentation for the Maven plugin](https://joelittlejohn.github.io/jsonschema2pojo/site/0.5.1/generate-mojo.html)
- * [Documentation for the Ant task](https://joelittlejohn.github.io/jsonschema2pojo/site/0.5.1/Jsonschema2PojoTask.html)
+ * [Latest Javadocs](https://joelittlejohn.github.io/jsonschema2pojo/javadocs/1.0.1/)
+ * [Documentation for the Maven plugin](https://joelittlejohn.github.io/jsonschema2pojo/site/1.0.1/generate-mojo.html)
+ * [Documentation for the Ant task](https://joelittlejohn.github.io/jsonschema2pojo/site/1.0.1/Jsonschema2PojoTask.html)
Project resources:
* [Downloads](https://github.com/joelittlejohn/jsonschema2pojo/releases)
diff --git a/jsonschema2pojo-ant/pom.xml b/jsonschema2pojo-ant/pom.xml
index b327f204c..a14e031be 100644
--- a/jsonschema2pojo-ant/pom.xml
+++ b/jsonschema2pojo-ant/pom.xml
@@ -5,7 +5,7 @@
jsonschema2pojo
org.jsonschema2pojo
- 1.0.0-beta2-SNAPSHOT
+ 1.0.2-SNAPSHOT
jsonschema2pojo-ant
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 5e0a7f625..e629b9e07 100644
--- a/jsonschema2pojo-ant/src/main/java/org/jsonschema2pojo/ant/Jsonschema2PojoTask.java
+++ b/jsonschema2pojo-ant/src/main/java/org/jsonschema2pojo/ant/Jsonschema2PojoTask.java
@@ -69,6 +69,10 @@ public class Jsonschema2PojoTask extends Task implements GenerationConfig {
private boolean generateBuilders;
+ private boolean includeTypeInfo = false;
+
+ private boolean useInnerClassBuilders = false;
+
private boolean includeConstructors = false;
private boolean usePrimitives;
@@ -300,6 +304,22 @@ public void setGenerateBuilders(boolean generateBuilders) {
this.generateBuilders = generateBuilders;
}
+ /**
+ * Sets the 'includeTypeInfo' property of this class.
+ *
+ * @param includeTypeInfo
+ * Whether to use include json type info information to class. Often required to support polymorphic type deserialization.
+ *
+ * By default the type information is stored in the @class property, this can be overridden in the deserializationClassProperty of the schema.
+ *
+ * Default: false
.
+ *
+ * @see https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization
+ */
+ public void setIncludeTypeInfo(boolean includeTypeInfo) {
+ this.includeTypeInfo = includeTypeInfo;
+ }
+
/**
* Sets the 'usePrimitives' property of this class.
*
@@ -890,6 +910,12 @@ public boolean isGenerateBuilders() {
return generateBuilders;
}
+ @Override
+ public boolean isIncludeTypeInfo()
+ {
+ return includeTypeInfo;
+ }
+
@Override
public boolean isUsePrimitives() {
return usePrimitives;
@@ -1201,5 +1227,18 @@ public Language getTargetLanguage() {
public Map getFormatTypeMapping() {
return formatTypeMapping;
}
-
+
+ @Override
+ public boolean isUseInnerClassBuilders() {
+ return useInnerClassBuilders;
+ }
+
+ /**
+ * Sets the 'useInnerClassBuilders' property of this class
+ *
+ * @param useInnerClassBuilders determines whether builders will be chainable setters or embedded classes when {@link #isGenerateBuilders()} used
+ */
+ public void setUseInnerClassBuilders(boolean useInnerClassBuilders) {
+ this.useInnerClassBuilders = useInnerClassBuilders;
+ }
}
diff --git a/jsonschema2pojo-ant/src/site/Jsonschema2PojoTask.html b/jsonschema2pojo-ant/src/site/Jsonschema2PojoTask.html
index 5b823df1b..9677d9da9 100644
--- a/jsonschema2pojo-ant/src/site/Jsonschema2PojoTask.html
+++ b/jsonschema2pojo-ant/src/site/Jsonschema2PojoTask.html
@@ -156,6 +156,19 @@ Parameters
No (default false ) |
+
+ includeTypeInfo |
+
+ Whether to include json type information; often required to support polymorphic type handling.
+ By default the type information is stored in the @class property, this can be overridden in the deserializationClassProperty of the schema.
+ |
+ No (default false ) |
+
+
+ useInnerClassBuilders |
+ Determines whether builders will be chainable setters or embedded classes when generateBuilders is used. |
+ No (default false ) |
+
includeGetters |
Whether to include getters or to omit these accessor methods and create public fields instead. |
diff --git a/jsonschema2pojo-cli/pom.xml b/jsonschema2pojo-cli/pom.xml
index 2f61d83cd..19032dd94 100644
--- a/jsonschema2pojo-cli/pom.xml
+++ b/jsonschema2pojo-cli/pom.xml
@@ -5,7 +5,7 @@
jsonschema2pojo
org.jsonschema2pojo
- 1.0.0-beta2-SNAPSHOT
+ 1.0.2-SNAPSHOT
jsonschema2pojo-cli
diff --git a/jsonschema2pojo-cli/src/main/java/org/jsonschema2pojo/cli/Arguments.java b/jsonschema2pojo-cli/src/main/java/org/jsonschema2pojo/cli/Arguments.java
index f7b5f33de..861c82c72 100644
--- a/jsonschema2pojo-cli/src/main/java/org/jsonschema2pojo/cli/Arguments.java
+++ b/jsonschema2pojo-cli/src/main/java/org/jsonschema2pojo/cli/Arguments.java
@@ -63,6 +63,12 @@ public class Arguments implements GenerationConfig {
@Parameter(names = { "-b", "--generate-builders" }, description = "Generate builder-style methods as well as setters")
private boolean generateBuilderMethods = false;
+ @Parameter(names = { "--include-type-info" }, description = "Include json type info; required to support polymorphic type handling. https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization")
+ private boolean includeTypeInfo = false;
+
+ @Parameter(names = { "--use-inner-class-builders" }, description = "Generate an inner class with builder-style methods")
+ private boolean useInnerClassBuilders = false;
+
@Parameter(names = { "-c", "--generate-constructors" }, description = "Generate constructors")
private boolean generateConstructors = false;
@@ -278,6 +284,17 @@ public boolean isGenerateBuilders() {
return generateBuilderMethods;
}
+ @Override
+ public boolean isIncludeTypeInfo()
+ {
+ return includeTypeInfo;
+ }
+
+ @Override
+ public boolean isUseInnerClassBuilders() {
+ return useInnerClassBuilders;
+ }
+
@Override
public boolean isUsePrimitives() {
return usePrimitives;
diff --git a/jsonschema2pojo-core/pom.xml b/jsonschema2pojo-core/pom.xml
index f9ed720b2..f82ffc40e 100644
--- a/jsonschema2pojo-core/pom.xml
+++ b/jsonschema2pojo-core/pom.xml
@@ -5,7 +5,7 @@
jsonschema2pojo
org.jsonschema2pojo
- 1.0.0-beta2-SNAPSHOT
+ 1.0.2-SNAPSHOT
jsonschema2pojo-core
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/AbstractAnnotator.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/AbstractAnnotator.java
index 9b17cc303..081cd8f92 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/AbstractAnnotator.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/AbstractAnnotator.java
@@ -41,6 +41,11 @@ public AbstractAnnotator(GenerationConfig generationConfig) {
this.generationConfig = generationConfig;
}
+ @Override
+ public void typeInfo(JDefinedClass clazz, JsonNode schema) {
+
+ }
+
@Override
public void propertyOrder(JDefinedClass clazz, JsonNode propertiesNode) {
}
@@ -91,6 +96,11 @@ public boolean isAdditionalPropertiesSupported() {
public void additionalPropertiesField(JFieldVar field, JDefinedClass clazz, String propertyName) {
}
+ @Override
+ public boolean isPolymorphicDeserializationSupported(JsonNode node) {
+ return false;
+ }
+
public GenerationConfig getGenerationConfig() {
return generationConfig;
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/AbstractTypeInfoAwareAnnotator.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/AbstractTypeInfoAwareAnnotator.java
new file mode 100644
index 000000000..5c3179c92
--- /dev/null
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/AbstractTypeInfoAwareAnnotator.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jsonschema2pojo;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.sun.codemodel.JDefinedClass;
+
+public abstract class AbstractTypeInfoAwareAnnotator extends AbstractAnnotator
+{
+ public AbstractTypeInfoAwareAnnotator(GenerationConfig generationConfig) {
+ super(generationConfig);
+ }
+
+ @Override
+ public void typeInfo(JDefinedClass clazz, JsonNode node) {
+ if(getGenerationConfig().isIncludeTypeInfo()) {
+ // Have per-schema JavaTypeInfo configuration override what is defined in generation config; backward comparability
+ if (node.has("deserializationClassProperty")) {
+ String annotationName = node.get("deserializationClassProperty").asText();
+ addJsonTypeInfoAnnotation(clazz, annotationName);
+ } else {
+ addJsonTypeInfoAnnotation(clazz, "@class");
+ }
+ } else {
+ // per-schema JsonTypeInfo configuration
+ if (node.has("deserializationClassProperty")) {
+ String annotationName = node.get("deserializationClassProperty").asText();
+ addJsonTypeInfoAnnotation(clazz, annotationName);
+ }
+ }
+ }
+
+ @Override
+ public boolean isPolymorphicDeserializationSupported(JsonNode node) {
+ return getGenerationConfig().isIncludeTypeInfo() || node.has("deserializationClassProperty");
+ }
+
+ abstract protected void addJsonTypeInfoAnnotation(JDefinedClass clazz, String propertyName);
+}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Annotator.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Annotator.java
index ee6dbf325..65498c7ad 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Annotator.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Annotator.java
@@ -32,6 +32,20 @@
*/
public interface Annotator {
+ /**
+ * Add the necessary annotation to dictate correct type information during
+ * serialization and deserialization; often required with polymorphic types.
+ *
+ * @see Jackson Docs - Polymorphic Type Handling
+ *
+ * @param clazz
+ * a generated pojo class, that is serialized to JSON
+ * @param schema
+ * the object schema associated with this clazz
+ */
+ void typeInfo(JDefinedClass clazz, JsonNode schema);
+
/**
* Add the necessary annotation to dictate correct property order during
* serialization
@@ -195,4 +209,6 @@ public interface Annotator {
void timeField(JFieldVar field, JDefinedClass clazz, JsonNode propertyNode);
void additionalPropertiesField(JFieldVar field, JDefinedClass clazz, String propertyName);
+
+ boolean isPolymorphicDeserializationSupported(JsonNode node);
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/CompositeAnnotator.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/CompositeAnnotator.java
index 21d680623..393dbb96a 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/CompositeAnnotator.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/CompositeAnnotator.java
@@ -43,6 +43,13 @@ public CompositeAnnotator(Annotator... annotators) {
this.annotators = annotators;
}
+ @Override
+ public void typeInfo(JDefinedClass clazz, JsonNode node) {
+ for (Annotator annotator : annotators) {
+ annotator.typeInfo(clazz, node);
+ }
+ }
+
@Override
public void propertyOrder(JDefinedClass clazz, JsonNode propertiesNode) {
for (Annotator annotator : annotators) {
@@ -130,7 +137,17 @@ public void additionalPropertiesField(JFieldVar field, JDefinedClass clazz, Stri
}
}
- @Override
+ @Override
+ public boolean isPolymorphicDeserializationSupported(JsonNode node) {
+ for (Annotator annotator : annotators) {
+ if (!annotator.isPolymorphicDeserializationSupported(node)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
public void dateTimeField(JFieldVar field, JDefinedClass clazz, JsonNode propertyNode) {
for (Annotator annotator : annotators) {
annotator.dateTimeField(field, clazz, propertyNode);
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/DefaultGenerationConfig.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/DefaultGenerationConfig.java
index d295b2690..ba0886336 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/DefaultGenerationConfig.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/DefaultGenerationConfig.java
@@ -38,6 +38,15 @@ public boolean isGenerateBuilders() {
return false;
}
+ /**
+ * @return false
+ */
+ @Override
+ public boolean isIncludeTypeInfo()
+ {
+ return false;
+ }
+
/**
* @return false
*/
@@ -444,5 +453,7 @@ public Language getTargetLanguage() {
public Map getFormatTypeMapping() {
return Collections.emptyMap();
}
-
+
+ @Override
+ public boolean isUseInnerClassBuilders() { 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 efcf91f5d..48d7f4d75 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/GenerationConfig.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/GenerationConfig.java
@@ -43,6 +43,16 @@ public interface GenerationConfig {
boolean isGenerateBuilders();
/**
+ * Gets the 'includeTypeInfo' configuration option.
+ *
+ * @return whether to include json type information. Commonly used to support polymorphic type deserialization.
+ *
+ * @see https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization
+ *
+ */
+ boolean isIncludeTypeInfo();
+
+ /**
* Gets the 'usePrimitives' configuration option.
*
* @return whether to use primitives (long
, double
@@ -571,4 +581,13 @@ public interface GenerationConfig {
* fully qualified type name (e.g. 'java.net.URI').
*/
Map getFormatTypeMapping();
+
+ /**
+ * If set to true, then the gang of four builder pattern will be used to generate builders on generated classes. Note: This property works
+ * in collaboration with the {@link #isGenerateBuilders()} method. If the {@link #isGenerateBuilders()} is false,
+ * then this property will not do anything.
+ * @return whether to include the gang of four builder patter on the generated classes. The default value for this is false.
+ */
+ default boolean isUseInnerClassBuilders(){ return false;}
+
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Jackson1Annotator.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Jackson1Annotator.java
index cd5720a1a..bc59af115 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Jackson1Annotator.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Jackson1Annotator.java
@@ -20,12 +20,15 @@
import java.util.LinkedHashSet;
import java.util.Set;
+import com.sun.codemodel.JAnnotationUse;
+import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.annotate.JsonAnyGetter;
import org.codehaus.jackson.annotate.JsonAnySetter;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonPropertyOrder;
+import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.annotate.JsonValue;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;
@@ -42,7 +45,7 @@
*
* @see http://jackson.codehaus.org/
*/
-public class Jackson1Annotator extends AbstractAnnotator {
+public class Jackson1Annotator extends AbstractTypeInfoAwareAnnotator {
private final JsonSerialize.Inclusion inclusionLevel;
@@ -140,4 +143,14 @@ public void additionalPropertiesField(JFieldVar field, JDefinedClass clazz, Stri
field.annotate(JsonIgnore.class);
}
+ protected void addJsonTypeInfoAnnotation(JDefinedClass jclass, String propertyName) {
+ JAnnotationUse jsonTypeInfo = jclass.annotate(JsonTypeInfo.class);
+ jsonTypeInfo.param("use", JsonTypeInfo.Id.CLASS);
+ jsonTypeInfo.param("include", JsonTypeInfo.As.PROPERTY);
+
+ // When not provided it will use default provided by "use" attribute
+ if(StringUtils.isNotBlank(propertyName)) {
+ jsonTypeInfo.param("property", propertyName);
+ }
+ }
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Jackson2Annotator.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Jackson2Annotator.java
index 6678e9490..d325e8740 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Jackson2Annotator.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/Jackson2Annotator.java
@@ -22,6 +22,9 @@
import java.util.LinkedHashSet;
import java.util.Set;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.sun.codemodel.JAnnotationUse;
+import org.apache.commons.lang3.StringUtils;
import org.jsonschema2pojo.rules.FormatRule;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
@@ -49,7 +52,7 @@
* @see https://github.com/FasterXML/jackson-annotations
*/
-public class Jackson2Annotator extends AbstractAnnotator {
+public class Jackson2Annotator extends AbstractTypeInfoAwareAnnotator {
private final JsonInclude.Include inclusionLevel;
@@ -213,4 +216,15 @@ public void dateTimeField(JFieldVar field, JDefinedClass clazz, JsonNode node) {
field.annotate(JsonFormat.class).param("shape", JsonFormat.Shape.STRING).param("pattern", pattern).param("timezone", timezone);
}
}
+
+ protected void addJsonTypeInfoAnnotation(JDefinedClass jclass, String propertyName) {
+ JAnnotationUse jsonTypeInfo = jclass.annotate(JsonTypeInfo.class);
+ jsonTypeInfo.param("use", JsonTypeInfo.Id.CLASS);
+ jsonTypeInfo.param("include", JsonTypeInfo.As.PROPERTY);
+
+ // When not provided it will use default provided by "use" attribute
+ if(StringUtils.isNotBlank(propertyName)) {
+ jsonTypeInfo.param("property", propertyName);
+ }
+ }
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/ScalaSingleStreamCodeWriter.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/ScalaSingleStreamCodeWriter.java
index 1f843c845..17f7691a7 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/ScalaSingleStreamCodeWriter.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/ScalaSingleStreamCodeWriter.java
@@ -16,15 +16,14 @@
package org.jsonschema2pojo;
-import java.io.ByteArrayOutputStream;
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
import com.mysema.scalagen.ConversionSettings;
import com.mysema.scalagen.Converter;
import com.sun.codemodel.JPackage;
import com.sun.codemodel.writer.SingleStreamCodeWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
public class ScalaSingleStreamCodeWriter extends SingleStreamCodeWriter {
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/AdditionalPropertiesRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/AdditionalPropertiesRule.java
index 3225252d0..aaddb1a75 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/AdditionalPropertiesRule.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/AdditionalPropertiesRule.java
@@ -19,6 +19,11 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.StreamSupport;
+import org.apache.commons.collections15.CollectionUtils;
import org.jsonschema2pojo.Schema;
import com.fasterxml.jackson.databind.JsonNode;
@@ -160,7 +165,19 @@ private JMethod addGetter(JDefinedClass jclass, JFieldVar field) {
return getter;
}
- private void addBuilder(JDefinedClass jclass, JType propertyType, JFieldVar field) {
+ private JMethod addBuilder(JDefinedClass jclass, JType propertyType, JFieldVar field) {
+
+ JMethod result = null;
+ if(ruleFactory.getGenerationConfig().isUseInnerClassBuilders()) {
+ result = addInnerBuilder(jclass, propertyType, field);
+ } else {
+ result = addLegacyBuilder(jclass, propertyType, field);
+ }
+
+ return result;
+ }
+
+ private JMethod addLegacyBuilder(JDefinedClass jclass, JType propertyType, JFieldVar field) {
JMethod builder = jclass.method(JMod.PUBLIC, jclass, "withAdditionalProperty");
JVar nameParam = builder.param(String.class, "name");
@@ -171,6 +188,32 @@ private void addBuilder(JDefinedClass jclass, JType propertyType, JFieldVar fiel
mapInvocation.arg(nameParam);
mapInvocation.arg(valueParam);
body._return(JExpr._this());
+
+ return builder;
+ }
+
+ private JMethod addInnerBuilder(JDefinedClass jclass, JType propertyType, JFieldVar field) {
+ Optional builderClass = StreamSupport
+ .stream(Spliterators.spliteratorUnknownSize(jclass.classes(), Spliterator.ORDERED), false)
+ .filter(definedClass -> definedClass.name().equals(getBuilderClassName(jclass)))
+ .findFirst();
+
+ JMethod builder = builderClass.get().method(JMod.PUBLIC, builderClass.get(), "withAdditionalProperty");
+
+ JVar nameParam = builder.param(String.class, "name");
+ JVar valueParam = builder.param(propertyType, "value");
+
+ JBlock body = builder.body();
+ JInvocation mapInvocation = body.invoke(JExpr.ref(JExpr.cast(jclass, JExpr._this().ref("instance")), field), "put");
+ mapInvocation.arg(nameParam);
+ mapInvocation.arg(valueParam);
+ body._return(JExpr._this());
+
+ return builder;
+ }
+
+ private String getBuilderClassName(JDefinedClass c) {
+ return ruleFactory.getNameHelper().getBuilderClassName(c);
}
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/BuilderRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/BuilderRule.java
new file mode 100644
index 000000000..7f5095137
--- /dev/null
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/BuilderRule.java
@@ -0,0 +1,121 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jsonschema2pojo.rules;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.sun.codemodel.JAnnotationUse;
+import com.sun.codemodel.JBlock;
+import com.sun.codemodel.JClass;
+import com.sun.codemodel.JClassAlreadyExistsException;
+import com.sun.codemodel.JConditional;
+import com.sun.codemodel.JDefinedClass;
+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.JTypeVar;
+import com.sun.codemodel.JVar;
+import java.util.Objects;
+import org.jsonschema2pojo.Schema;
+import org.jsonschema2pojo.util.ReflectionHelper;
+
+public class BuilderRule implements Rule {
+
+ private RuleFactory ruleFactory;
+ private ReflectionHelper reflectionHelper;
+
+ BuilderRule(RuleFactory ruleFactory, ReflectionHelper reflectionHelper) {
+ this.ruleFactory = ruleFactory;
+ this.reflectionHelper = reflectionHelper;
+ }
+
+ @Override
+ public JDefinedClass apply(String nodeName, JsonNode node, JsonNode parent, JDefinedClass instanceClass, Schema currentSchema) {
+
+ // Create the inner class for the builder
+ JDefinedClass builderClass;
+
+ try {
+ String builderName = ruleFactory.getNameHelper().getBuilderClassName(instanceClass);
+ builderClass = instanceClass._class(JMod.PUBLIC + JMod.STATIC, builderName);
+ } catch (JClassAlreadyExistsException e) {
+ return e.getExistingClass();
+ }
+
+ // Determine which builder (if any) this builder should inherit from
+ JClass parentBuilderClass = null;
+ JClass parentClass = instanceClass._extends();
+ if (!(parentClass.isPrimitive() || reflectionHelper.isFinal(parentClass) || Objects.equals(parentClass.fullName(), "java.lang.Object"))) {
+ parentBuilderClass = reflectionHelper.getBuilderClass(parentClass);
+ }
+
+ // Determine the generic type 'T' that the builder will create instances of
+ JTypeVar instanceType = builderClass.generify("T", instanceClass);
+
+ // For new builders we need to create an instance variable and 'build' method
+ // for inheriting builders we'll receive these from the superType
+ if (parentBuilderClass == null) {
+
+ // Create the instance variable
+ JFieldVar instanceField = builderClass.field(JMod.PROTECTED, instanceType, "instance");
+
+ // Create the actual "build" method
+ JMethod buildMethod = builderClass.method(JMod.PUBLIC, instanceType, "build");
+
+ JBlock body = buildMethod.body();
+ JVar result = body.decl(instanceType, "result");
+ body.assign(result, JExpr._this().ref(instanceField));
+ body.assign(JExpr._this().ref(instanceField), JExpr._null());
+ body._return(result);
+
+ // Create the noargs builder constructor
+ generateNoArgsBuilderConstructor(instanceClass, builderClass);
+ } else {
+ // Declare the inheritance
+ builderClass._extends(parentBuilderClass);
+
+ // Create the noargs builder constructor
+ generateNoArgsBuilderConstructor(instanceClass, builderClass);
+ }
+
+ return builderClass;
+ }
+
+ private void generateNoArgsBuilderConstructor(JDefinedClass instanceClass, JDefinedClass builderClass) {
+ JMethod noargsConstructor = builderClass.constructor(JMod.PUBLIC);
+ JAnnotationUse warningSuppression = noargsConstructor.annotate(SuppressWarnings.class);
+ warningSuppression.param("value", "unchecked");
+
+ JBlock constructorBlock = noargsConstructor.body();
+
+ JFieldVar instanceField = reflectionHelper.searchClassAndSuperClassesForField("instance", builderClass);
+
+ // Determine if we need to invoke the super() method for our parent builder
+ JClass parentClass = builderClass._extends();
+ if (!(parentClass.isPrimitive() || reflectionHelper.isFinal(parentClass) || Objects.equals(parentClass.fullName(), "java.lang.Object"))) {
+ constructorBlock.invoke("super");
+ }
+
+ // Only initialize the instance if the object being constructed is actually this class
+ // if it's a subtype then ignore the instance initialization since the subclass will initialize it
+ constructorBlock.directStatement("// Skip initialization when called from subclass");
+ JInvocation comparison = JExpr._this().invoke("getClass").invoke("equals").arg(JExpr.dotclass(builderClass));
+ JConditional ifNotSubclass = constructorBlock._if(comparison);
+ ifNotSubclass._then().assign(JExpr._this().ref(instanceField), JExpr.cast(instanceField.type(), JExpr._new(instanceClass)));
+ }
+
+}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/ConstructorRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/ConstructorRule.java
new file mode 100644
index 000000000..a1fa614fd
--- /dev/null
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/ConstructorRule.java
@@ -0,0 +1,240 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jsonschema2pojo.rules;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.sun.codemodel.JBlock;
+import com.sun.codemodel.JClass;
+import com.sun.codemodel.JConditional;
+import com.sun.codemodel.JDefinedClass;
+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.JVar;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import org.jsonschema2pojo.GenerationConfig;
+import org.jsonschema2pojo.Schema;
+import org.jsonschema2pojo.util.NameHelper;
+import org.jsonschema2pojo.util.ReflectionHelper;
+
+public class ConstructorRule implements Rule {
+
+ private final RuleFactory ruleFactory;
+ private final ReflectionHelper reflectionHelper;
+
+ ConstructorRule(RuleFactory ruleFactory, ReflectionHelper reflectionHelper) {
+ this.ruleFactory = ruleFactory;
+ this.reflectionHelper = reflectionHelper;
+ }
+
+ @Override
+ public JDefinedClass apply(String nodeName, JsonNode node, JsonNode parent, JDefinedClass instanceClass, Schema currentSchema) {
+
+ GenerationConfig generationConfig = ruleFactory.getGenerationConfig();
+
+ // Determine which properties belong to that class (or its superType/parent)
+ LinkedHashSet classProperties = getConstructorProperties(node, generationConfig.isConstructorsRequiredPropertiesOnly());
+ LinkedHashSet combinedSuperProperties = getSuperTypeConstructorPropertiesRecursive(node, currentSchema, generationConfig.isConstructorsRequiredPropertiesOnly());
+
+ // no properties to put in the constructor => default constructor is good enough.
+ if (classProperties.isEmpty() && combinedSuperProperties.isEmpty()) {
+ return instanceClass;
+ }
+
+ // Generate the no arguments constructor
+ generateNoArgsConstructor(instanceClass);
+
+ // Generate the constructor with the properties which were located
+ JMethod instanceConstructor = generateFieldsConstructor(instanceClass, classProperties, combinedSuperProperties);
+
+ // If we're using InnerClassBuilder implementations then we also need to generate those
+ if (generationConfig.isGenerateBuilders() && generationConfig.isUseInnerClassBuilders()) {
+ JDefinedClass builderClass = ruleFactory.getReflectionHelper().getBuilderClass(instanceClass);
+ generateFieldsBuilderConstructor(builderClass, instanceClass, instanceConstructor);
+ }
+
+ return instanceClass;
+ }
+
+ /**
+ * Retrieve the list of properties to go in the constructor from node. This is all properties listed in node["properties"] if ! onlyRequired, and
+ * only required properties if onlyRequired.
+ */
+ private LinkedHashSet getConstructorProperties(JsonNode node, boolean onlyRequired) {
+
+ if (!node.has("properties")) {
+ return new LinkedHashSet<>();
+ }
+
+ LinkedHashSet rtn = new LinkedHashSet<>();
+ Set draft4RequiredProperties = new HashSet<>();
+
+ // setup the set of required properties for draft4 style "required"
+ if (onlyRequired && node.has("required")) {
+ JsonNode requiredArray = node.get("required");
+ if (requiredArray.isArray()) {
+ for (JsonNode requiredEntry : requiredArray) {
+ if (requiredEntry.isTextual()) {
+ draft4RequiredProperties.add(requiredEntry.asText());
+ }
+ }
+ }
+ }
+
+ NameHelper nameHelper = ruleFactory.getNameHelper();
+ for (Iterator> properties = node.get("properties").fields(); properties.hasNext(); ) {
+ Map.Entry property = properties.next();
+
+ JsonNode propertyObj = property.getValue();
+ if (onlyRequired) {
+ // draft3 style
+ if (propertyObj.has("required") && propertyObj.get("required").asBoolean()) {
+ rtn.add(nameHelper.getPropertyName(property.getKey(), property.getValue()));
+ }
+
+ // draft4 style
+ if (draft4RequiredProperties.contains(property.getKey())) {
+ rtn.add(nameHelper.getPropertyName(property.getKey(), property.getValue()));
+ }
+ } else {
+ rtn.add(nameHelper.getPropertyName(property.getKey(), property.getValue()));
+ }
+ }
+ return rtn;
+ }
+
+ /**
+ * Recursive, walks the schema tree and assembles a list of all properties of this schema's super schemas
+ */
+ private LinkedHashSet getSuperTypeConstructorPropertiesRecursive(JsonNode node, Schema schema, boolean onlyRequired) {
+ Schema superTypeSchema = reflectionHelper.getSuperSchema(node, schema, true);
+
+ if (superTypeSchema == null) {
+ return new LinkedHashSet<>();
+ }
+
+ JsonNode superSchemaNode = superTypeSchema.getContent();
+
+ LinkedHashSet rtn = getConstructorProperties(superSchemaNode, onlyRequired);
+ rtn.addAll(getSuperTypeConstructorPropertiesRecursive(superSchemaNode, superTypeSchema, onlyRequired));
+
+ return rtn;
+ }
+
+ private void generateFieldsBuilderConstructor(JDefinedClass builderClass, JDefinedClass instanceClass, JMethod instanceConstructor) {
+ // Locate the instance field since we'll need it to assign a value
+ JFieldVar instanceField = reflectionHelper.searchClassAndSuperClassesForField("instance", builderClass);
+
+ // Create a new method to be the builder constructor we're defining
+ JMethod builderConstructor = builderClass.constructor(JMod.PUBLIC);
+ builderConstructor.annotate(SuppressWarnings.class).param("value", "unchecked");
+ JBlock constructorBlock = builderConstructor.body();
+
+ // The builder constructor should have the exact same parameters as the instanceConstructor
+ for(JVar param : instanceConstructor.params()) {
+ builderConstructor.param(param.type(), param.name());
+ }
+
+ // Determine if we need to invoke the super() method for our parent builder
+ JClass parentClass = builderClass._extends();
+ if (!(parentClass.isPrimitive() || reflectionHelper.isFinal(parentClass) || Objects.equals(parentClass.fullName(), "java.lang.Object"))) {
+ constructorBlock.invoke("super");
+ }
+
+ // The constructor invocation will also need all the parameters passed through
+ JInvocation instanceConstructorInvocation = JExpr._new(instanceClass);
+ for(JVar param : instanceConstructor.params()) {
+ instanceConstructorInvocation.arg(param);
+ }
+
+ // Only initialize the instance if the object being constructed is actually this class
+ // if it's a subtype then ignore the instance initialization since the subclass will initialize it
+ constructorBlock.directStatement("// Skip initialization when called from subclass");
+
+ JInvocation comparison = JExpr._this().invoke("getClass").invoke("equals").arg(JExpr.dotclass(builderClass));
+ JConditional ifNotSubclass = constructorBlock._if(comparison);
+ ifNotSubclass._then().assign(JExpr._this().ref(instanceField), JExpr.cast(instanceField.type(), instanceConstructorInvocation));
+ }
+
+ private JMethod generateFieldsConstructor(JDefinedClass jclass, LinkedHashSet classProperties, LinkedHashSet combinedSuperProperties) {
+ // add the public constructor with property parameters
+ JMethod fieldsConstructor = jclass.constructor(JMod.PUBLIC);
+ JBlock constructorBody = fieldsConstructor.body();
+ JInvocation superInvocation = constructorBody.invoke("super");
+
+ Map fields = jclass.fields();
+ Map classFieldParams = new HashMap<>();
+
+ for (String property : classProperties) {
+ JFieldVar field = fields.get(property);
+
+ if (field == null) {
+ throw new IllegalStateException("Property " + property + " hasn't been added to JDefinedClass before calling addConstructors");
+ }
+
+ fieldsConstructor.javadoc().addParam(property);
+ JVar param = fieldsConstructor.param(field.type(), field.name());
+ constructorBody.assign(JExpr._this().ref(field), param);
+ classFieldParams.put(property, param);
+ }
+
+ List superConstructorParams = new ArrayList<>();
+
+ for (String property : combinedSuperProperties) {
+ JFieldVar field = reflectionHelper.searchSuperClassesForField(property, jclass);
+
+ if (field == null) {
+ throw new IllegalStateException("Property " + property + " hasn't been added to JDefinedClass before calling addConstructors");
+ }
+
+ JVar param = classFieldParams.get(property);
+
+ if (param == null) {
+ param = fieldsConstructor.param(field.type(), field.name());
+ }
+
+ fieldsConstructor.javadoc().addParam(property);
+ superConstructorParams.add(param);
+ }
+
+ for (JVar param : superConstructorParams) {
+ superInvocation.arg(param);
+ }
+
+ return fieldsConstructor;
+ }
+
+ private void generateNoArgsConstructor(JDefinedClass jclass) {
+ // add a no-args constructor for serialization purposes
+ JMethod noargsConstructor = jclass.constructor(JMod.PUBLIC);
+ noargsConstructor.javadoc().add("No args constructor for use in serialization");
+ }
+
+
+
+
+}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/DigitsRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/DigitsRule.java
new file mode 100644
index 000000000..db2129599
--- /dev/null
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/DigitsRule.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jsonschema2pojo.rules;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.sun.codemodel.JAnnotationUse;
+import com.sun.codemodel.JFieldVar;
+import org.jsonschema2pojo.Schema;
+
+import javax.validation.constraints.Digits;
+import java.util.NoSuchElementException;
+
+public class DigitsRule implements Rule {
+
+ private final RuleFactory ruleFactory;
+
+ protected DigitsRule(RuleFactory ruleFactory) {
+ this.ruleFactory = ruleFactory;
+ }
+
+ @Override
+ public JFieldVar apply(String nodeName, JsonNode node, JsonNode parent, JFieldVar field, Schema currentSchema) {
+
+ if (ruleFactory.getGenerationConfig().isIncludeJsr303Annotations()
+ && node.has("integerDigits") && node.has("fractionalDigits")) {
+
+ JAnnotationUse annotation = field.annotate(Digits.class);
+
+ annotation.param("integer", node.get("integerDigits").asInt());
+ annotation.param("fraction", node.get("fractionalDigits").asInt());
+ }
+
+ return field;
+ }
+
+}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/EnumRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/EnumRule.java
index 256a20e89..7d7bf09ea 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/EnumRule.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/EnumRule.java
@@ -134,6 +134,14 @@ public JType apply(String nodeName, JsonNode node, JsonNode parent, JClassContai
addEnumConstants(node.path("enum"), _enum, node.path("javaEnumNames"), backingType);
addFactoryMethod(_enum, backingType);
+ if (node.has("title")) {
+ ruleFactory.getTitleRule().apply(nodeName, node.get("title"), node, _enum, schema);
+ }
+
+ if (node.has("description")) {
+ ruleFactory.getDescriptionRule().apply(nodeName, node.get("description"), node, _enum, schema);
+ }
+
return _enum;
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/ObjectRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/ObjectRule.java
index 8ec982777..d347b1695 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/ObjectRule.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/ObjectRule.java
@@ -13,13 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.jsonschema2pojo.rules;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import static org.apache.commons.lang3.StringUtils.substringAfter;
+import static org.apache.commons.lang3.StringUtils.substringBefore;
+import static org.jsonschema2pojo.rules.PrimitiveTypes.isPrimitive;
+import static org.jsonschema2pojo.rules.PrimitiveTypes.primitiveType;
+import static org.jsonschema2pojo.util.TypeUtil.resolveType;
+
import com.fasterxml.jackson.databind.JsonNode;
import com.sun.codemodel.ClassType;
-import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JClassAlreadyExistsException;
@@ -29,40 +32,27 @@
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JFieldRef;
import com.sun.codemodel.JFieldVar;
-import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JOp;
import com.sun.codemodel.JPackage;
import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;
-
-import org.jsonschema2pojo.AnnotationStyle;
-import org.jsonschema2pojo.Schema;
-import org.jsonschema2pojo.exception.ClassAlreadyExistsException;
-import org.jsonschema2pojo.exception.GenerationException;
-import org.jsonschema2pojo.util.MakeUniqueClassName;
-import org.jsonschema2pojo.util.NameHelper;
-import org.jsonschema2pojo.util.ParcelableHelper;
-import org.jsonschema2pojo.util.SerializableHelper;
-
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
import java.util.Map;
import java.util.Set;
-import static org.apache.commons.lang3.StringUtils.capitalize;
-import static org.apache.commons.lang3.StringUtils.substringAfter;
-import static org.apache.commons.lang3.StringUtils.substringBefore;
-import static org.jsonschema2pojo.rules.PrimitiveTypes.isPrimitive;
-import static org.jsonschema2pojo.rules.PrimitiveTypes.primitiveType;
-import static org.jsonschema2pojo.util.TypeUtil.resolveType;
+import org.jsonschema2pojo.AnnotationStyle;
+import org.jsonschema2pojo.Annotator;
+import org.jsonschema2pojo.Schema;
+import org.jsonschema2pojo.exception.ClassAlreadyExistsException;
+import org.jsonschema2pojo.exception.GenerationException;
+import org.jsonschema2pojo.util.ParcelableHelper;
+import org.jsonschema2pojo.util.ReflectionHelper;
+import org.jsonschema2pojo.util.SerializableHelper;
/**
* Applies the generation steps required for schemas of type "object".
@@ -74,11 +64,13 @@
public class ObjectRule implements Rule {
private final RuleFactory ruleFactory;
+ private final ReflectionHelper reflectionHelper;
private final ParcelableHelper parcelableHelper;
- protected ObjectRule(RuleFactory ruleFactory, ParcelableHelper parcelableHelper) {
+ protected ObjectRule(RuleFactory ruleFactory, ParcelableHelper parcelableHelper, ReflectionHelper reflectionHelper) {
this.ruleFactory = ruleFactory;
this.parcelableHelper = parcelableHelper;
+ this.reflectionHelper = reflectionHelper;
}
/**
@@ -91,9 +83,8 @@ protected ObjectRule(RuleFactory ruleFactory, ParcelableHelper parcelableHelper)
@Override
public JType apply(String nodeName, JsonNode node, JsonNode parent, JPackage _package, Schema schema) {
- JType superType = getSuperType(nodeName, node, _package, schema);
-
- if (superType.isPrimitive() || isFinal(superType)) {
+ JType superType = reflectionHelper.getSuperType(nodeName, node, _package, schema);
+ if (superType.isPrimitive() || reflectionHelper.isFinal(superType)) {
return superType;
}
@@ -108,10 +99,6 @@ public JType apply(String nodeName, JsonNode node, JsonNode parent, JPackage _pa
schema.setJavaTypeIfEmpty(jclass);
- if (node.has("deserializationClassProperty")) {
- addJsonTypeInfoAnnotation(jclass, node);
- }
-
if (node.has("title")) {
ruleFactory.getTitleRule().apply(nodeName, node.get("title"), node, jclass, schema);
}
@@ -120,6 +107,11 @@ public JType apply(String nodeName, JsonNode node, JsonNode parent, JPackage _pa
ruleFactory.getDescriptionRule().apply(nodeName, node.get("description"), node, jclass, schema);
}
+ // Creates the class definition for the builder
+ if(ruleFactory.getGenerationConfig().isGenerateBuilders() && ruleFactory.getGenerationConfig().isUseInnerClassBuilders()){
+ ruleFactory.getBuilderRule().apply(nodeName, node, parent, jclass, schema);
+ }
+
ruleFactory.getPropertiesRule().apply(nodeName, node.get("properties"), node, jclass, schema);
if (node.has("javaInterfaces")) {
@@ -148,7 +140,8 @@ public JType apply(String nodeName, JsonNode node, JsonNode parent, JPackage _pa
}
if (ruleFactory.getGenerationConfig().isIncludeConstructors()) {
- addConstructors(jclass, node, schema, ruleFactory.getGenerationConfig().isConstructorsRequiredPropertiesOnly());
+ ruleFactory.getConstructorRule().apply(nodeName, node, parent, jclass, schema);
+
}
if (ruleFactory.getGenerationConfig().isSerializable()) {
@@ -173,74 +166,7 @@ private void addParcelSupport(JDefinedClass jclass) {
}
}
- /**
- * Retrieve the list of properties to go in the constructor from node. This
- * is all properties listed in node["properties"] if ! onlyRequired, and
- * only required properties if onlyRequired.
- *
- * @param node
- * @return
- */
- private LinkedHashSet getConstructorProperties(JsonNode node, boolean onlyRequired) {
-
- if (!node.has("properties")) {
- return new LinkedHashSet<>();
- }
-
- LinkedHashSet rtn = new LinkedHashSet<>();
- Set draft4RequiredProperties = new HashSet<>();
-
- // setup the set of required properties for draft4 style "required"
- if (onlyRequired && node.has("required")) {
- JsonNode requiredArray = node.get("required");
- if (requiredArray.isArray()) {
- for (JsonNode requiredEntry: requiredArray) {
- if (requiredEntry.isTextual()) {
- draft4RequiredProperties.add(requiredEntry.asText());
- }
- }
- }
- }
-
- NameHelper nameHelper = ruleFactory.getNameHelper();
- for (Iterator> properties = node.get("properties").fields(); properties.hasNext();) {
- Map.Entry property = properties.next();
-
- JsonNode propertyObj = property.getValue();
- if (onlyRequired) {
- // draft3 style
- if (propertyObj.has("required") && propertyObj.get("required").asBoolean()) {
- rtn.add(nameHelper.getPropertyName(property.getKey(), property.getValue()));
- }
-
- // draft4 style
- if (draft4RequiredProperties.contains(property.getKey())) {
- rtn.add(nameHelper.getPropertyName(property.getKey(), property.getValue()));
- }
- } else {
- rtn.add(nameHelper.getPropertyName(property.getKey(), property.getValue()));
- }
- }
- return rtn;
- }
-
- /**
- * Recursive, walks the schema tree and assembles a list of all properties of this schema's super schemas
- */
- private LinkedHashSet getSuperTypeConstructorPropertiesRecursive(JsonNode node, Schema schema, boolean onlyRequired) {
- Schema superTypeSchema = getSuperSchema(node, schema, true);
-
- if (superTypeSchema == null) {
- return new LinkedHashSet<>();
- }
-
- JsonNode superSchemaNode = superTypeSchema.getContent();
- LinkedHashSet rtn = getConstructorProperties(superSchemaNode, onlyRequired);
- rtn.addAll(getSuperTypeConstructorPropertiesRecursive(superSchemaNode, superTypeSchema, onlyRequired));
-
- return rtn;
- }
/**
* Creates a new Java class that will be generated.
@@ -265,6 +191,8 @@ private JDefinedClass createClass(String nodeName, JsonNode node, JPackage _pack
JDefinedClass newType;
+ Annotator annotator = ruleFactory.getAnnotator();
+
try {
if (node.has("existingJavaType")) {
String fqn = substringBefore(node.get("existingJavaType").asText(), "<");
@@ -277,7 +205,8 @@ private JDefinedClass createClass(String nodeName, JsonNode node, JPackage _pack
throw new ClassAlreadyExistsException(existingClass);
}
- boolean usePolymorphicDeserialization = usesPolymorphicDeserialization(node);
+ boolean usePolymorphicDeserialization = annotator.isPolymorphicDeserializationSupported(node);
+
if (node.has("javaType")) {
String fqn = node.path("javaType").asText();
@@ -301,85 +230,22 @@ private JDefinedClass createClass(String nodeName, JsonNode node, JPackage _pack
}
} else {
if (usePolymorphicDeserialization) {
- newType = _package._class(JMod.PUBLIC, getClassName(nodeName, node, _package), ClassType.CLASS);
+ newType = _package._class(JMod.PUBLIC, ruleFactory.getNameHelper().getUniqueClassName(nodeName, node, _package), ClassType.CLASS);
} else {
- newType = _package._class(getClassName(nodeName, node, _package));
+ newType = _package._class(ruleFactory.getNameHelper().getUniqueClassName(nodeName, node, _package));
}
}
} catch (JClassAlreadyExistsException e) {
throw new ClassAlreadyExistsException(e.getExistingClass());
}
- ruleFactory.getAnnotator().propertyInclusion(newType, node);
+ annotator.typeInfo(newType, node);
+ annotator.propertyInclusion(newType, node);
return newType;
}
- private boolean isFinal(JType superType) {
- try {
- Class> javaClass = Class.forName(superType.fullName());
- return Modifier.isFinal(javaClass.getModifiers());
- } catch (ClassNotFoundException e) {
- return false;
- }
- }
-
- private JType getSuperType(String nodeName, JsonNode node, JPackage jPackage, Schema schema) {
- if (node.has("extends") && node.has("extendsJavaClass")) {
- throw new IllegalStateException("'extends' and 'extendsJavaClass' defined simultaneously");
- }
-
- JType superType = jPackage.owner().ref(Object.class);
- Schema superTypeSchema = getSuperSchema(node, schema, false);
- if (superTypeSchema != null) {
- superType = ruleFactory.getSchemaRule().apply(nodeName + "Parent", node.get("extends"), node, jPackage, superTypeSchema);
- } else if (node.has("extendsJavaClass")) {
- superType = resolveType(jPackage, node.get("extendsJavaClass").asText());
- }
-
- return superType;
- }
-
- private Schema getSuperSchema(JsonNode node, Schema schema, boolean followRefs) {
- if (node.has("extends")) {
- String path;
- if (schema.getId().getFragment() == null) {
- path = "#extends";
- } else {
- path = "#" + schema.getId().getFragment() + "/extends";
- }
-
- Schema superSchema = ruleFactory.getSchemaStore().create(schema, path, ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters());
-
- if (followRefs) {
- superSchema = resolveSchemaRefsRecursive(superSchema);
- }
-
- return superSchema;
- }
- return null;
- }
-
- private Schema resolveSchemaRefsRecursive(Schema schema) {
- JsonNode schemaNode = schema.getContent();
- if (schemaNode.has("$ref")) {
- schema = ruleFactory.getSchemaStore().create(schema, schemaNode.get("$ref").asText(), ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters());
- return resolveSchemaRefsRecursive(schema);
- }
- return schema;
- }
-
- private void addJsonTypeInfoAnnotation(JDefinedClass jclass, JsonNode node) {
- if (ruleFactory.getGenerationConfig().getAnnotationStyle() == AnnotationStyle.JACKSON2) {
- String annotationName = node.get("deserializationClassProperty").asText();
- JAnnotationUse jsonTypeInfo = jclass.annotate(JsonTypeInfo.class);
- jsonTypeInfo.param("use", JsonTypeInfo.Id.CLASS);
- jsonTypeInfo.param("include", JsonTypeInfo.As.PROPERTY);
- jsonTypeInfo.param("property", annotationName);
- }
- }
-
private void addToString(JDefinedClass jclass) {
Map fields = jclass.fields();
JMethod toString = jclass.method(JMod.PUBLIC, String.class, "toString");
@@ -575,98 +441,6 @@ private Map removeFieldsExcludedFromEqualsAndHashCode(Map classProperties = getConstructorProperties(node, onlyRequired);
- LinkedHashSet combinedSuperProperties = getSuperTypeConstructorPropertiesRecursive(node, schema, onlyRequired);
-
- // no properties to put in the constructor => default constructor is good enough.
- if (classProperties.isEmpty() && combinedSuperProperties.isEmpty()) {
- return;
- }
-
- // add a no-args constructor for serialization purposes
- JMethod noargsConstructor = jclass.constructor(JMod.PUBLIC);
- noargsConstructor.javadoc().add("No args constructor for use in serialization");
-
- // add the public constructor with property parameters
- JMethod fieldsConstructor = jclass.constructor(JMod.PUBLIC);
- JBlock constructorBody = fieldsConstructor.body();
- JInvocation superInvocation = constructorBody.invoke("super");
-
- Map fields = jclass.fields();
- Map classFieldParams = new HashMap<>();
-
- for (String property : classProperties) {
- JFieldVar field = fields.get(property);
-
- if (field == null) {
- throw new IllegalStateException("Property " + property + " hasn't been added to JDefinedClass before calling addConstructors");
- }
-
- fieldsConstructor.javadoc().addParam(property);
- JVar param = fieldsConstructor.param(field.type(), field.name());
- constructorBody.assign(JExpr._this().ref(field), param);
- classFieldParams.put(property, param);
- }
-
- List superConstructorParams = new ArrayList<>();
-
-
- for (String property : combinedSuperProperties) {
- JFieldVar field = searchSuperClassesForField(property, jclass);
-
- if (field == null) {
- throw new IllegalStateException("Property " + property + " hasn't been added to JDefinedClass before calling addConstructors");
- }
-
- JVar param = classFieldParams.get(property);
-
- if (param == null) {
- param = fieldsConstructor.param(field.type(), field.name());
- }
-
- fieldsConstructor.javadoc().addParam(property);
- superConstructorParams.add(param);
- }
-
- for (JVar param : superConstructorParams) {
- superInvocation.arg(param);
- }
- }
-
- private static JDefinedClass definedClassOrNullFromType(JType type)
- {
- if (type == null || type.isPrimitive())
- {
- return null;
- }
- JClass fieldClass = type.boxify();
- JPackage jPackage = fieldClass._package();
- return jPackage._getClass(fieldClass.name());
- }
-
- /**
- * This is recursive with searchClassAndSuperClassesForField
- */
- private JFieldVar searchSuperClassesForField(String property, JDefinedClass jclass) {
- JClass superClass = jclass._extends();
- JDefinedClass definedSuperClass = definedClassOrNullFromType(superClass);
- if (definedSuperClass == null) {
- return null;
- }
- return searchClassAndSuperClassesForField(property, definedSuperClass);
- }
-
- private JFieldVar searchClassAndSuperClassesForField(String property, JDefinedClass jclass) {
- Map fields = jclass.fields();
- JFieldVar field = fields.get(property);
- if (field == null) {
- return searchSuperClassesForField(property, jclass);
- }
- return field;
- }
-
private void addEquals(JDefinedClass jclass, JsonNode node) {
Map fields = removeFieldsExcludedFromEqualsAndHashCode(jclass.fields(), node);
@@ -736,45 +510,16 @@ private void addInterfaces(JDefinedClass jclass, JsonNode javaInterfaces) {
}
}
- private String getClassName(String nodeName, JsonNode node, JPackage _package) {
- String prefix = ruleFactory.getGenerationConfig().getClassNamePrefix();
- String suffix = ruleFactory.getGenerationConfig().getClassNameSuffix();
- String fieldName = ruleFactory.getNameHelper().getClassName(nodeName, node);
- String capitalizedFieldName = capitalize(fieldName);
- String fullFieldName = createFullFieldName(capitalizedFieldName, prefix, suffix);
-
- String className = ruleFactory.getNameHelper().replaceIllegalCharacters(fullFieldName);
- String normalizedName = ruleFactory.getNameHelper().normalizeName(className);
- return makeUnique(normalizedName, _package);
- }
-
- private String createFullFieldName(String nodeName, String prefix, String suffix) {
- String returnString = nodeName;
- if (prefix != null) {
- returnString = prefix + returnString;
- }
-
- if (suffix != null) {
- returnString = returnString + suffix;
- }
+ private boolean usesPolymorphicDeserialization(JsonNode node) {
- return returnString;
- }
+ AnnotationStyle annotationStyle = ruleFactory.getGenerationConfig().getAnnotationStyle();
- private String makeUnique(String className, JPackage _package) {
- try {
- JDefinedClass _class = _package._class(className);
- _package.remove(_class);
- return className;
- } catch (JClassAlreadyExistsException e) {
- return makeUnique(MakeUniqueClassName.makeUnique(className), _package);
+ if (annotationStyle == AnnotationStyle.JACKSON
+ || annotationStyle == AnnotationStyle.JACKSON1
+ || annotationStyle == AnnotationStyle.JACKSON2) {
+ return ruleFactory.getGenerationConfig().isIncludeTypeInfo() || node.has("deserializationClassProperty");
}
- }
- private boolean usesPolymorphicDeserialization(JsonNode node) {
- if (ruleFactory.getGenerationConfig().getAnnotationStyle() == AnnotationStyle.JACKSON2) {
- return node.has("deserializationClassProperty");
- }
return false;
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertiesRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertiesRule.java
index 38f817ef2..f58d2009e 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertiesRule.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertiesRule.java
@@ -93,6 +93,7 @@ private void addOverrideBuilders(JDefinedClass jclass, JDefinedClass parentJclas
private void addOverrideBuilder(JDefinedClass thisJDefinedClass, JMethod parentBuilder, JVar parentParam) {
+ // Confirm that this class doesn't already have a builder method matching the same name as the parentBuilder
if (thisJDefinedClass.getMethod(parentBuilder.name(), new JType[] {parentParam.type()}) == null) {
JMethod builder = thisJDefinedClass.method(parentBuilder.mods().getValue(), thisJDefinedClass, parentBuilder.name());
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 d4490677e..ef19403fc 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/PropertyRule.java
@@ -17,12 +17,18 @@
package org.jsonschema2pojo.rules;
import com.fasterxml.jackson.databind.JsonNode;
-import com.sun.codemodel.*;
+import com.sun.codemodel.JBlock;
+import com.sun.codemodel.JDefinedClass;
+import com.sun.codemodel.JDocCommentable;
+import com.sun.codemodel.JExpr;
+import com.sun.codemodel.JFieldVar;
+import com.sun.codemodel.JMethod;
+import com.sun.codemodel.JMod;
+import com.sun.codemodel.JType;
+import com.sun.codemodel.JVar;
import org.jsonschema2pojo.GenerationConfig;
import org.jsonschema2pojo.Schema;
-import static org.apache.commons.lang3.StringUtils.capitalize;
-
/**
* Applies the schema rules that represent a property definition.
@@ -90,7 +96,7 @@ public JDefinedClass apply(String nodeName, JsonNode node, JsonNode parent, JDef
}
if (ruleFactory.getGenerationConfig().isGenerateBuilders()) {
- addBuilder(jclass, field, nodeName, node);
+ addBuilderMethod(jclass, field, nodeName, node);
}
if (node.has("pattern")) {
@@ -105,6 +111,8 @@ public JDefinedClass apply(String nodeName, JsonNode node, JsonNode parent, JDef
ruleFactory.getMinLengthMaxLengthRule().apply(nodeName, node, parent, field, schema);
+ ruleFactory.getDigitsRule().apply(nodeName, node, parent, field, schema);
+
if (isObject(node) || isArray(node)) {
ruleFactory.getValidRule().apply(nodeName, node, parent, field, schema);
}
@@ -112,16 +120,10 @@ public JDefinedClass apply(String nodeName, JsonNode node, JsonNode parent, JDef
return jclass;
}
- private boolean isRequired(String nodeName, JsonNode node, Schema schema) {
- if (node.has("required")) {
- final JsonNode requiredNode = node.get("required");
- return requiredNode.asBoolean();
- }
-
- JsonNode requiredArray = schema.getContent().get("required");
-
- if (requiredArray != null) {
- for (JsonNode requiredNode : requiredArray) {
+ private boolean hasEnumerated(Schema schema, String arrayFieldName, String nodeName) {
+ JsonNode array = schema.getContent().get(arrayFieldName);
+ if (array != null) {
+ for (JsonNode requiredNode : array) {
if (nodeName.equals(requiredNode.asText()))
return true;
}
@@ -130,22 +132,25 @@ private boolean isRequired(String nodeName, JsonNode node, Schema schema) {
return false;
}
- private boolean useOptional(String nodeName, JsonNode node, Schema schema) {
- if (node.has("javaOptional")) {
- final JsonNode requiredNode = node.get("javaOptional");
+ private boolean hasFlag(JsonNode node, String fieldName) {
+ if (node.has(fieldName)) {
+ final JsonNode requiredNode = node.get(fieldName);
return requiredNode.asBoolean();
}
- JsonNode javaOptionalArray = schema.getContent().get("javaOptional");
+ return false;
+ }
- if (javaOptionalArray != null) {
- for (JsonNode requiredNode : javaOptionalArray) {
- if (nodeName.equals(requiredNode.asText()))
- return true;
- }
- }
+ private boolean isDeclaredAs(String type, String nodeName, JsonNode node, Schema schema) {
+ return hasEnumerated(schema, type, nodeName) || hasFlag(node, type);
+ }
- return false;
+ private boolean isRequired(String nodeName, JsonNode node, Schema schema) {
+ return isDeclaredAs("required", nodeName, node, schema);
+ }
+
+ private boolean useOptional(String nodeName, JsonNode node, Schema schema) {
+ return isDeclaredAs("javaOptional", nodeName, node, schema);
}
private void propertyAnnotations(String nodeName, JsonNode node, Schema schema, JDocCommentable generatedJavaConstruct) {
@@ -235,27 +240,54 @@ private JMethod addSetter(JDefinedClass c, JFieldVar field, String jsonPropertyN
return setter;
}
- private JMethod addBuilder(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node) {
- JMethod builder = c.method(JMod.PUBLIC, c, getBuilderName(jsonPropertyName, node));
+ private JMethod addBuilderMethod(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node) {
+ JMethod result = null;
+ if(ruleFactory.getGenerationConfig().isUseInnerClassBuilders()) {
+ result = addInnerBuilderMethod(c, field, jsonPropertyName, node);
+ } else {
+ result = addLegacyBuilder(c, field, jsonPropertyName, node);
+ }
+ return result;
+ }
- JVar param = builder.param(field.type(), field.name());
- JBlock body = builder.body();
- body.assign(JExpr._this().ref(field), param);
- body._return(JExpr._this());
+ private JMethod addLegacyBuilder(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node) {
+ JMethod builder = c.method(JMod.PUBLIC, c, getBuilderName(jsonPropertyName, node));
- return builder;
- }
+ JVar param = builder.param(field.type(), field.name());
+ JBlock body = builder.body();
+ body.assign(JExpr._this().ref(field), param);
+ body._return(JExpr._this());
- private String getBuilderName(String propertyName, JsonNode node) {
- return ruleFactory.getNameHelper().getBuilderName(propertyName, node);
- }
+ return builder;
+ }
- private String getSetterName(String propertyName, JsonNode node) {
- return ruleFactory.getNameHelper().getSetterName(propertyName, node);
- }
+ private JMethod addInnerBuilderMethod(JDefinedClass c, JFieldVar field, String jsonPropertyName, JsonNode node) {
+ JDefinedClass builderClass = ruleFactory.getReflectionHelper().getBuilderClass(c);
- private String getGetterName(String propertyName, JType type, JsonNode node) {
- return ruleFactory.getNameHelper().getGetterName(propertyName, type, node);
- }
+ JMethod builderMethod = builderClass.method(JMod.PUBLIC, builderClass, getBuilderName(jsonPropertyName, node));
+
+ JVar param = builderMethod.param(field.type(), field.name());
+ JBlock body = builderMethod.body();
+ body.assign(JExpr.ref(JExpr.cast(c, JExpr._this().ref("instance")), field), param);
+ body._return(JExpr._this());
+
+ return builderMethod;
+ }
+
+ private String getBuilderClassName(JDefinedClass c) {
+ return ruleFactory.getNameHelper().getBuilderClassName(c);
+ }
+
+ private String getBuilderName(String propertyName, JsonNode node) {
+ return ruleFactory.getNameHelper().getBuilderName(propertyName, node);
+ }
+
+ private String getSetterName(String propertyName, JsonNode node) {
+ return ruleFactory.getNameHelper().getSetterName(propertyName, node);
+ }
+
+ private String getGetterName(String propertyName, JType type, JsonNode node) {
+ return ruleFactory.getNameHelper().getGetterName(propertyName, type, node);
+ }
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/RuleFactory.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/RuleFactory.java
index ca1342e27..d9e904bc4 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/RuleFactory.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/RuleFactory.java
@@ -32,6 +32,8 @@
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JPackage;
import com.sun.codemodel.JType;
+import org.jsonschema2pojo.util.ReflectionHelper;
+import sun.reflect.Reflection;
/**
* Provides factory/creation methods for the code generation rules.
@@ -39,6 +41,7 @@
public class RuleFactory {
private NameHelper nameHelper;
+ private ReflectionHelper reflectionHelper;
private GenerationConfig generationConfig;
private Annotator annotator;
private SchemaStore schemaStore;
@@ -61,6 +64,7 @@ public RuleFactory(GenerationConfig generationConfig, Annotator annotator, Schem
this.annotator = annotator;
this.schemaStore = schemaStore;
this.nameHelper = new NameHelper(generationConfig);
+ this.reflectionHelper = new ReflectionHelper(this);
}
/**
@@ -119,7 +123,17 @@ public Rule getFormatRule() {
* @return a schema rule that can handle the "object" declaration.
*/
public Rule getObjectRule() {
- return new ObjectRule(this, new ParcelableHelper());
+ return new ObjectRule(this, new ParcelableHelper(), reflectionHelper);
+ }
+
+ /**
+ * Provides a rule instance that should be applied to add constructors to a generated type
+ *
+ * @return a schema rule that can handle the "object" declaration.
+ */
+ public Rule getConstructorRule()
+ {
+ return new ConstructorRule(this, reflectionHelper);
}
/**
@@ -258,6 +272,17 @@ public Rule getMinLengthMaxLengthRule() {
return new MinLengthMaxLengthRule(this);
}
+ /**
+ * Provides a rule instance that should be applied when a property
+ * declaration is found in the schema, to assign he digits validation
+ * on that property.
+ *
+ * @return a schema rule that can handle the "digits" declaration.
+ */
+ public Rule getDigitsRule() {
+ return new DigitsRule(this);
+ }
+
/**
* Provides a rule instance that should be applied when a "pattern"
* declaration is found in the schema for a property.
@@ -356,6 +381,11 @@ public NameHelper getNameHelper() {
return nameHelper;
}
+ public ReflectionHelper getReflectionHelper() {
+ return reflectionHelper;
+ }
+
+
/**
* Provides a rule instance that should be applied when a "media"
* declaration is found in the schema.
@@ -374,6 +404,10 @@ public Rule getDynamicPropertiesRule() {
return new DynamicPropertiesRule(this);
}
+ public Rule getBuilderRule(){
+ return new BuilderRule(this, reflectionHelper);
+ }
+
public Rule getJavaNameRule() {
return new JavaNameRule();
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/TypeRule.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/TypeRule.java
index 6a7c9c5a0..92f958cb5 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/TypeRule.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/rules/TypeRule.java
@@ -1,17 +1,14 @@
/**
* Copyright © 2010-2017 Nokia
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
+ * under the License.
*/
package org.jsonschema2pojo.rules;
@@ -33,155 +30,145 @@
/**
* Applies the "type" schema rule.
*
- * @see http:/
- * /tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1
+ * @see http:/ /tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1
*/
public class TypeRule implements Rule {
- private static final String DEFAULT_TYPE_NAME = "any";
-
- private final RuleFactory ruleFactory;
-
- protected TypeRule(RuleFactory ruleFactory) {
- this.ruleFactory = ruleFactory;
+ private static final String DEFAULT_TYPE_NAME = "any";
+
+ private final RuleFactory ruleFactory;
+
+ protected TypeRule(RuleFactory ruleFactory) {
+ this.ruleFactory = ruleFactory;
+ }
+
+ /**
+ * Applies this schema rule to take the required code generation steps.
+ *
+ * When applied, this rule reads the details of the given node to determine the appropriate Java type to return. This may be a newly generated type,
+ * it may be a primitive type or other type such as {@link java.lang.String} or {@link java.lang.Object}.
+ *
+ * JSON schema types and their Java type equivalent:
+ *
+ * - "type":"any" => {@link java.lang.Object}
+ *
- "type":"array" => Either {@link java.util.Set} or
+ * {@link java.util.List}, see {@link ArrayRule}
+ *
- "type":"boolean" =>
boolean
+ * - "type":"integer" =>
int
+ * - "type":"null" => {@link java.lang.Object}
+ *
- "type":"number" =>
double
+ * - "type":"object" => Generated type (see {@link ObjectRule})
+ *
- "type":"string" => {@link java.lang.String} (or alternative based
+ * on presence of "format", see {@link FormatRule})
+ *
+ *
+ * @param nodeName the name of the node for which this "type" rule applies
+ * @param node the node for which this "type" rule applies
+ * @param parent the parent node
+ * @param jClassContainer the package into which any newly generated type may be placed
+ * @return the Java type which, after reading the details of the given schema node, most appropriately matches the "type" specified
+ */
+ @Override
+ public JType apply(String nodeName, JsonNode node, JsonNode parent, JClassContainer jClassContainer, Schema schema) {
+
+ String propertyTypeName = getTypeName(node);
+
+ JType type;
+
+ if (propertyTypeName.equals("object") || node.has("properties") && node.path("properties").size() > 0) {
+
+ type = ruleFactory.getObjectRule().apply(nodeName, node, parent, jClassContainer.getPackage(), schema);
+ } else if (node.has("existingJavaType")) {
+ String typeName = node.path("existingJavaType").asText();
+
+ if (isPrimitive(typeName, jClassContainer.owner())) {
+ type = primitiveType(typeName, jClassContainer.owner());
+ } else {
+ type = resolveType(jClassContainer, typeName);
+ }
+ } else if (propertyTypeName.equals("string")) {
+
+ type = jClassContainer.owner().ref(String.class);
+ } else if (propertyTypeName.equals("number")) {
+
+ type = getNumberType(jClassContainer.owner(), ruleFactory.getGenerationConfig());
+ } else if (propertyTypeName.equals("integer")) {
+
+ type = getIntegerType(jClassContainer.owner(), node, ruleFactory.getGenerationConfig());
+ } else if (propertyTypeName.equals("boolean")) {
+
+ type = unboxIfNecessary(jClassContainer.owner().ref(Boolean.class), ruleFactory.getGenerationConfig());
+ } else if (propertyTypeName.equals("array")) {
+
+ type = ruleFactory.getArrayRule().apply(nodeName, node, parent, jClassContainer.getPackage(), schema);
+ } else {
+
+ type = jClassContainer.owner().ref(Object.class);
}
- /**
- * Applies this schema rule to take the required code generation steps.
- *
- * When applied, this rule reads the details of the given node to determine
- * the appropriate Java type to return. This may be a newly generated type,
- * it may be a primitive type or other type such as {@link java.lang.String}
- * or {@link java.lang.Object}.
- *
- * JSON schema types and their Java type equivalent:
- *
- * - "type":"any" => {@link java.lang.Object}
- *
- "type":"array" => Either {@link java.util.Set} or
- * {@link java.util.List}, see {@link ArrayRule}
- *
- "type":"boolean" =>
boolean
- * - "type":"integer" =>
int
- * - "type":"null" => {@link java.lang.Object}
- *
- "type":"number" =>
double
- * - "type":"object" => Generated type (see {@link ObjectRule})
- *
- "type":"string" => {@link java.lang.String} (or alternative based
- * on presence of "format", see {@link FormatRule})
- *
- *
- * @param nodeName
- * the name of the node for which this "type" rule applies
- * @param node
- * the node for which this "type" rule applies
- * @param parent
- * the parent node
- * @param jClassContainer
- * the package into which any newly generated type may be placed
- * @return the Java type which, after reading the details of the given
- * schema node, most appropriately matches the "type" specified
- */
- @Override
- public JType apply(String nodeName, JsonNode node, JsonNode parent, JClassContainer jClassContainer, Schema schema) {
-
- String propertyTypeName = getTypeName(node);
-
- JType type;
-
- if (propertyTypeName.equals("object") || node.has("properties") && node.path("properties").size() > 0) {
-
- type = ruleFactory.getObjectRule().apply(nodeName, node, parent, jClassContainer.getPackage(), schema);
- } else if (node.has("existingJavaType")) {
- String typeName = node.path("existingJavaType").asText();
-
- if (isPrimitive(typeName, jClassContainer.owner())) {
- type = primitiveType(typeName, jClassContainer.owner());
- } else {
- type = resolveType(jClassContainer, typeName);
- }
- } else if (propertyTypeName.equals("string")) {
-
- type = jClassContainer.owner().ref(String.class);
- } else if (propertyTypeName.equals("number")) {
-
- type = getNumberType(jClassContainer.owner(), ruleFactory.getGenerationConfig());
- } else if (propertyTypeName.equals("integer")) {
-
- type = getIntegerType(jClassContainer.owner(), node, ruleFactory.getGenerationConfig());
- } else if (propertyTypeName.equals("boolean")) {
-
- type = unboxIfNecessary(jClassContainer.owner().ref(Boolean.class), ruleFactory.getGenerationConfig());
- } else if (propertyTypeName.equals("array")) {
-
- type = ruleFactory.getArrayRule().apply(nodeName, node, parent, jClassContainer.getPackage(), schema);
- } else {
-
- type = jClassContainer.owner().ref(Object.class);
- }
-
- if (!node.has("javaType") && !node.has("existingJavaType") && node.has("format")) {
- type = ruleFactory.getFormatRule().apply(nodeName, node.get("format"), node, type, schema);
- } else if (!node.has("javaType") && !node.has("existingJavaType") && propertyTypeName.equals("string") && node.has("media")) {
- type = ruleFactory.getMediaRule().apply(nodeName, node.get("media"), node, type, schema);
- }
-
- return type;
+ if (!node.has("javaType") && !node.has("existingJavaType") && node.has("format")) {
+ type = ruleFactory.getFormatRule().apply(nodeName, node.get("format"), node, type, schema);
+ } else if (!node.has("javaType") && !node.has("existingJavaType") && propertyTypeName.equals("string") && node.has("media")) {
+ type = ruleFactory.getMediaRule().apply(nodeName, node.get("media"), node, type, schema);
}
- private String getTypeName(JsonNode node) {
- if (node.has("type") && node.get("type").isArray() && node.get("type").size() > 0) {
- for (JsonNode jsonNode : node.get("type")) {
- String typeName = jsonNode.asText();
- if (!typeName.equals("null")) {
- return typeName;
- }
- }
- }
+ return type;
+ }
- if (node.has("type") && node.get("type").isTextual()) {
- return node.get("type").asText();
+ private String getTypeName(JsonNode node) {
+ if (node.has("type") && node.get("type").isArray() && node.get("type").size() > 0) {
+ for (JsonNode jsonNode : node.get("type")) {
+ String typeName = jsonNode.asText();
+ if (!typeName.equals("null")) {
+ return typeName;
}
-
- return DEFAULT_TYPE_NAME;
+ }
}
- private JType unboxIfNecessary(JType type, GenerationConfig config) {
- if (config.isUsePrimitives()) {
- return type.unboxify();
- } else {
- return type;
- }
+ if (node.has("type") && node.get("type").isTextual()) {
+ return node.get("type").asText();
}
- /**
- * Returns the JType for an integer field. Handles type lookup and unboxing.
- */
- private JType getIntegerType(JCodeModel owner, JsonNode node, GenerationConfig config) {
-
- if (config.isUseBigIntegers()) {
- return unboxIfNecessary(owner.ref(BigInteger.class), config);
- } else if (config.isUseLongIntegers() ||
- node.has("minimum") && node.get("minimum").isLong() ||
- node.has("maximum") && node.get("maximum").isLong()) {
- return unboxIfNecessary(owner.ref(Long.class), config);
- } else {
- return unboxIfNecessary(owner.ref(Integer.class), config);
- }
+ return DEFAULT_TYPE_NAME;
+ }
+ private JType unboxIfNecessary(JType type, GenerationConfig config) {
+ if (config.isUsePrimitives()) {
+ return type.unboxify();
+ } else {
+ return type;
+ }
+ }
+
+ /**
+ * Returns the JType for an integer field. Handles type lookup and unboxing.
+ */
+ private JType getIntegerType(JCodeModel owner, JsonNode node, GenerationConfig config) {
+
+ if (config.isUseBigIntegers()) {
+ return unboxIfNecessary(owner.ref(BigInteger.class), config);
+ } else if (config.isUseLongIntegers() || node.has("minimum") && node.get("minimum").isLong() || node.has("maximum") && node.get("maximum")
+ .isLong()) {
+ return unboxIfNecessary(owner.ref(Long.class), config);
+ } else {
+ return unboxIfNecessary(owner.ref(Integer.class), config);
}
- /**
- * Returns the JType for a number field. Handles type lookup and unboxing.
- */
- private JType getNumberType(JCodeModel owner, GenerationConfig config) {
-
- if (config.isUseBigDecimals()) {
- return unboxIfNecessary(owner.ref(BigDecimal.class), config);
- } else if (config.isUseDoubleNumbers()) {
- return unboxIfNecessary(owner.ref(Double.class), config);
- } else {
- return unboxIfNecessary(owner.ref(Float.class), config);
- }
+ }
+
+ /**
+ * Returns the JType for a number field. Handles type lookup and unboxing.
+ */
+ private JType getNumberType(JCodeModel owner, GenerationConfig config) {
+ if (config.isUseBigDecimals()) {
+ return unboxIfNecessary(owner.ref(BigDecimal.class), config);
+ } else if (config.isUseDoubleNumbers()) {
+ return unboxIfNecessary(owner.ref(Double.class), config);
+ } else {
+ return unboxIfNecessary(owner.ref(Float.class), config);
}
+ }
+
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/util/NameHelper.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/util/NameHelper.java
index d3a4cb4da..0a519ab36 100644
--- a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/util/NameHelper.java
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/util/NameHelper.java
@@ -16,15 +16,21 @@
package org.jsonschema2pojo.util;
-import static java.lang.Character.*;
-import static javax.lang.model.SourceVersion.*;
-import static org.apache.commons.lang3.StringUtils.*;
-
-import org.apache.commons.lang3.text.WordUtils;
-import org.jsonschema2pojo.GenerationConfig;
+import static java.lang.Character.isDigit;
+import static java.lang.Character.toLowerCase;
+import static javax.lang.model.SourceVersion.isKeyword;
+import static org.apache.commons.lang3.StringUtils.capitalize;
+import static org.apache.commons.lang3.StringUtils.containsAny;
+import static org.apache.commons.lang3.StringUtils.remove;
import com.fasterxml.jackson.databind.JsonNode;
+import com.sun.codemodel.JClass;
+import com.sun.codemodel.JClassAlreadyExistsException;
+import com.sun.codemodel.JDefinedClass;
+import com.sun.codemodel.JPackage;
import com.sun.codemodel.JType;
+import org.apache.commons.lang3.text.WordUtils;
+import org.jsonschema2pojo.GenerationConfig;
public class NameHelper {
@@ -213,4 +219,46 @@ private String getPropertyNameForAccessor(String jsonPropertyName, JsonNode node
jsonPropertyName = capitalizeTrailingWords(jsonPropertyName);
return jsonPropertyName;
}
+
+ public String getBuilderClassName(JClass outterClass) {
+ return outterClass.name() + "Builder";
+ }
+
+ public String getUniqueClassName(String nodeName, JsonNode node, JPackage _package) {
+ return makeUnique(getClassName(nodeName, node, _package), _package);
+ }
+
+ public String getClassName(String nodeName, JsonNode node, JPackage _package) {
+ String prefix = generationConfig.getClassNamePrefix();
+ String suffix = generationConfig.getClassNameSuffix();
+ String fieldName = getClassName(nodeName, node);
+ String capitalizedFieldName = capitalize(fieldName);
+ String fullFieldName = createFullFieldName(capitalizedFieldName, prefix, suffix);
+
+ String className = replaceIllegalCharacters(fullFieldName);
+ return normalizeName(className);
+ }
+
+ private String createFullFieldName(String nodeName, String prefix, String suffix) {
+ String returnString = nodeName;
+ if (prefix != null) {
+ returnString = prefix + returnString;
+ }
+
+ if (suffix != null) {
+ returnString = returnString + suffix;
+ }
+
+ return returnString;
+ }
+
+ private String makeUnique(String className, JPackage _package) {
+ try {
+ JDefinedClass _class = _package._class(className);
+ _package.remove(_class);
+ return className;
+ } catch (JClassAlreadyExistsException e) {
+ return makeUnique(MakeUniqueClassName.makeUnique(className), _package);
+ }
+ }
}
diff --git a/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/util/ReflectionHelper.java b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/util/ReflectionHelper.java
new file mode 100644
index 000000000..4fff8313e
--- /dev/null
+++ b/jsonschema2pojo-core/src/main/java/org/jsonschema2pojo/util/ReflectionHelper.java
@@ -0,0 +1,162 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jsonschema2pojo.util;
+
+import static org.jsonschema2pojo.util.TypeUtil.resolveType;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.sun.codemodel.JClass;
+import com.sun.codemodel.JDefinedClass;
+import com.sun.codemodel.JFieldVar;
+import com.sun.codemodel.JPackage;
+import com.sun.codemodel.JType;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.StreamSupport;
+import org.jsonschema2pojo.Schema;
+import org.jsonschema2pojo.rules.RuleFactory;
+
+public class ReflectionHelper {
+
+ private RuleFactory ruleFactory;
+
+ public ReflectionHelper(RuleFactory ruleFactory) {
+ this.ruleFactory = ruleFactory;
+ }
+
+ public JType getSuperType(String nodeName, JsonNode node, JPackage jPackage, Schema schema) {
+ if (node.has("extends") && node.has("extendsJavaClass")) {
+ throw new IllegalStateException("'extends' and 'extendsJavaClass' defined simultaneously");
+ }
+
+ JType superType = jPackage.owner().ref(Object.class);
+ Schema superTypeSchema = getSuperSchema(node, schema, false);
+ if (superTypeSchema != null) {
+ superType = ruleFactory.getSchemaRule().apply(nodeName + "Parent", node.get("extends"), node, jPackage, superTypeSchema);
+ } else if (node.has("extendsJavaClass")) {
+ superType = resolveType(jPackage, node.get("extendsJavaClass").asText());
+ }
+
+ return superType;
+ }
+
+ public Schema getSuperSchema(JsonNode node, Schema schema, boolean followRefs) {
+ if (node.has("extends")) {
+ String path;
+ if (schema.getId().getFragment() == null) {
+ path = "#extends";
+ } else {
+ path = "#" + schema.getId().getFragment() + "/extends";
+ }
+
+ Schema superSchema = ruleFactory.getSchemaStore().create(schema, path, ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters());
+
+ if (followRefs) {
+ superSchema = resolveSchemaRefsRecursive(superSchema);
+ }
+
+ return superSchema;
+ }
+ return null;
+ }
+
+ /**
+ * This is recursive with searchClassAndSuperClassesForField
+ */
+ public JFieldVar searchSuperClassesForField(String property, JDefinedClass jclass) {
+ JClass superClass = jclass._extends();
+ JDefinedClass definedSuperClass = definedClassOrNullFromType(superClass);
+ if (definedSuperClass == null) {
+ return null;
+ }
+ return searchClassAndSuperClassesForField(property, definedSuperClass);
+ }
+
+ public JDefinedClass getBuilderClass(JDefinedClass target) {
+ String builderClassname = ruleFactory.getNameHelper().getBuilderClassName(target);
+
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(target.classes(), Spliterator.ORDERED), false)
+ .filter(definedClass -> definedClass.name().equals(builderClassname)).findFirst().orElse(null);
+ }
+
+ public JDefinedClass getBuilderClass(JClass target) {
+ String builderClassname = ruleFactory.getNameHelper().getBuilderClassName(target);
+ return getAllPackageClasses(target._package()).stream().filter(definedClass -> definedClass.name().equals(builderClassname)).findFirst()
+ .orElse(null);
+ }
+
+ public boolean isFinal(JType superType) {
+ try {
+ Class> javaClass = Class.forName(superType.fullName());
+ return Modifier.isFinal(javaClass.getModifiers());
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
+ public JFieldVar searchClassAndSuperClassesForField(String property, JDefinedClass jclass) {
+ Map fields = jclass.fields();
+ JFieldVar field = fields.get(property);
+ if (field == null) {
+ return searchSuperClassesForField(property, jclass);
+ }
+ return field;
+ }
+
+ private JDefinedClass definedClassOrNullFromType(JType type) {
+ if (type == null || type.isPrimitive()) {
+ return null;
+ }
+ JClass fieldClass = type.boxify();
+ JPackage jPackage = fieldClass._package();
+ return this._getClass(fieldClass.name(), jPackage);
+ }
+
+ private JDefinedClass _getClass(String name, JPackage _package) {
+ return getAllPackageClasses(_package).stream().filter(definedClass -> definedClass.name().equals(name)).findFirst()
+ .orElseThrow(() -> new NoClassDefFoundError(name));
+ }
+
+ private Collection getAllPackageClasses(JPackage _package) {
+ LinkedList result = new LinkedList<>();
+ StreamSupport.stream(Spliterators.spliteratorUnknownSize(_package.classes(), Spliterator.ORDERED), false)
+ .forEach(_class -> result.addAll(getAllClassClasses(_class)));
+ return result;
+ }
+
+ private Collection getAllClassClasses(JDefinedClass _class) {
+ LinkedList result = new LinkedList<>();
+ result.add(_class);
+
+ _class.classes().forEachRemaining(result::add);
+ return result;
+ }
+
+ private Schema resolveSchemaRefsRecursive(Schema schema) {
+ JsonNode schemaNode = schema.getContent();
+ if (schemaNode.has("$ref")) {
+ schema = ruleFactory.getSchemaStore()
+ .create(schema, schemaNode.get("$ref").asText(), ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters());
+ return resolveSchemaRefsRecursive(schema);
+ }
+ return schema;
+ }
+
+}
diff --git a/jsonschema2pojo-core/src/test/java/org/jsonschema2pojo/rules/PropertyRuleTest.java b/jsonschema2pojo-core/src/test/java/org/jsonschema2pojo/rules/PropertyRuleTest.java
new file mode 100755
index 000000000..6187cbc19
--- /dev/null
+++ b/jsonschema2pojo-core/src/test/java/org/jsonschema2pojo/rules/PropertyRuleTest.java
@@ -0,0 +1,131 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jsonschema2pojo.rules;
+
+import static org.hamcrest.MatcherAssert.*;
+import static org.hamcrest.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.BooleanNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.sun.codemodel.JClassAlreadyExistsException;
+import com.sun.codemodel.JCodeModel;
+import com.sun.codemodel.JDefinedClass;
+import com.sun.codemodel.JType;
+import org.jsonschema2pojo.GenerationConfig;
+import org.jsonschema2pojo.NoopAnnotator;
+import org.jsonschema2pojo.Schema;
+import org.jsonschema2pojo.SchemaStore;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PropertyRuleTest {
+ private static final String TARGET_CLASS_NAME = PropertyRuleTest.class.getName() + ".DummyClass";
+
+ private static final String internalFieldName = "internalRequired";
+ private static final String targetFieldName = "requiredFoo";
+
+ private final GenerationConfig config = mock(GenerationConfig.class);
+ private final PropertyRule rule = new PropertyRule(new RuleFactory(config, new NoopAnnotator(), new SchemaStore()));
+
+ private ObjectMapper mapper;
+
+ @Before
+ public void setup() {
+ mapper = new ObjectMapper();
+
+ when(config.isIncludeGetters()).thenReturn(true);
+ when(config.isUseOptionalForGetters()).thenReturn(true);
+ }
+
+ private String getGeneratedMethodTypeName(JDefinedClass jclass) {
+ return jclass.getMethod("getRequiredFoo", new JType[] {}).type().name();
+ }
+
+ private Schema getMockedSchema(ObjectNode parentNode) {
+ Schema schema = mock(Schema.class);
+ when(schema.getContent()).thenReturn(parentNode);
+ when(schema.deriveChildSchema(any())).thenReturn(schema);
+ return schema;
+ }
+
+ private JDefinedClass applyRule(ObjectNode propertyNode, ObjectNode parentNode) throws JClassAlreadyExistsException {
+ JDefinedClass jclass = new JCodeModel()._class(TARGET_CLASS_NAME);
+ return rule.apply(targetFieldName, propertyNode, parentNode, jclass, getMockedSchema(parentNode));
+ }
+
+ @Test
+ public void applyRequiredByTopArray() throws JClassAlreadyExistsException {
+ ObjectNode propertyNode = mapper.createObjectNode();
+ propertyNode.set("required", mapper.createArrayNode().add(internalFieldName));
+ propertyNode.set("properties", mapper.createObjectNode().set(internalFieldName, mapper.createObjectNode()));
+
+ ObjectNode parentNode = mapper.createObjectNode();
+ parentNode.set("required", mapper.createArrayNode().add(targetFieldName));
+ parentNode.set("properties", mapper.createObjectNode().set(targetFieldName, propertyNode));
+
+ JDefinedClass jclass = applyRule(propertyNode, parentNode);
+
+ assertThat(jclass, notNullValue());
+ assertThat(getGeneratedMethodTypeName(jclass), is("RequiredFoo"));
+ }
+
+ @Test
+ public void applyNotRequiredByTopArray() throws JClassAlreadyExistsException {
+ ObjectNode propertyNode = mapper.createObjectNode();
+ propertyNode.set("required", mapper.createArrayNode().add(internalFieldName));
+ propertyNode.set("properties", mapper.createObjectNode().set(internalFieldName, mapper.createObjectNode()));
+
+ ObjectNode parentNode = mapper.createObjectNode();
+ parentNode.set("properties", mapper.createObjectNode().set(targetFieldName, propertyNode));
+
+ JDefinedClass jclass = applyRule(propertyNode, parentNode);
+
+ assertThat(jclass, notNullValue());
+ assertThat(getGeneratedMethodTypeName(jclass), is("Optional"));
+ }
+
+ @Test
+ public void applyRequiredByFlag() throws JClassAlreadyExistsException {
+ ObjectNode propertyNode = mapper.createObjectNode();
+ propertyNode.set("required", BooleanNode.TRUE);
+ propertyNode.set("properties", mapper.createObjectNode().set(internalFieldName, mapper.createObjectNode()));
+
+ ObjectNode parentNode = mapper.createObjectNode();
+ parentNode.set("properties", mapper.createObjectNode().set(targetFieldName, propertyNode));
+
+ JDefinedClass jclass = applyRule(propertyNode, parentNode);
+
+ assertThat(jclass, notNullValue());
+ assertThat(getGeneratedMethodTypeName(jclass), is("RequiredFoo"));
+ }
+
+ @Test
+ public void applyNotRequiredByFlag() throws JClassAlreadyExistsException {
+ ObjectNode propertyNode = mapper.createObjectNode();
+ propertyNode.set("properties", mapper.createObjectNode().set(internalFieldName, mapper.createObjectNode()));
+
+ ObjectNode parentNode = mapper.createObjectNode();
+ parentNode.set("properties", mapper.createObjectNode().set(targetFieldName, propertyNode));
+
+ JDefinedClass jclass = applyRule(propertyNode, parentNode);
+
+ assertThat(jclass, notNullValue());
+ assertThat(getGeneratedMethodTypeName(jclass), is("Optional"));
+ }
+}
diff --git a/jsonschema2pojo-core/src/test/java/org/jsonschema2pojo/rules/RuleFactoryImplTest.java b/jsonschema2pojo-core/src/test/java/org/jsonschema2pojo/rules/RuleFactoryImplTest.java
index 8c3249618..76a9899b9 100644
--- a/jsonschema2pojo-core/src/test/java/org/jsonschema2pojo/rules/RuleFactoryImplTest.java
+++ b/jsonschema2pojo-core/src/test/java/org/jsonschema2pojo/rules/RuleFactoryImplTest.java
@@ -68,6 +68,8 @@ public void factoryMethodsCreateRules() {
assertThat(ruleFactory.getValidRule(), notNullValue());
+ assertThat(ruleFactory.getDigitsRule(), notNullValue());
+
}
@Test
diff --git a/jsonschema2pojo-core/src/test/resources/schema/child.json b/jsonschema2pojo-core/src/test/resources/schema/child.json
new file mode 100644
index 000000000..7c8c259bc
--- /dev/null
+++ b/jsonschema2pojo-core/src/test/resources/schema/child.json
@@ -0,0 +1,15 @@
+{
+ "$id": "https://example.com/child.schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "description" : "A schema definition for an object which can be inherited",
+ "javaType" : "com.example.package.GeneratedChildType",
+ "type" : "object",
+ "extends" : {
+ "$ref" : "parent.json"
+ },
+ "properties" : {
+ "childProperty" : { "type" : "string" }
+ },
+ "dependencies" : {
+ }
+}
\ No newline at end of file
diff --git a/jsonschema2pojo-core/src/test/resources/schema/parent.json b/jsonschema2pojo-core/src/test/resources/schema/parent.json
new file mode 100644
index 000000000..f2a9b7d78
--- /dev/null
+++ b/jsonschema2pojo-core/src/test/resources/schema/parent.json
@@ -0,0 +1,12 @@
+{
+ "$id": "https://example.com/address.schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "description" : "A schema definition for an object which can be inherited",
+ "javaType" : "com.example.package.GeneratedParentType",
+ "type" : "object",
+ "properties" : {
+ "parentProperty" : { "type" : "string" }
+ },
+ "dependencies" : {
+ }
+}
\ No newline at end of file
diff --git a/jsonschema2pojo-gradle-plugin/pom.xml b/jsonschema2pojo-gradle-plugin/pom.xml
index 7eea26783..f32cc8f02 100644
--- a/jsonschema2pojo-gradle-plugin/pom.xml
+++ b/jsonschema2pojo-gradle-plugin/pom.xml
@@ -5,7 +5,7 @@
jsonschema2pojo
org.jsonschema2pojo
- 1.0.0-beta2-SNAPSHOT
+ 1.0.2-SNAPSHOT
jsonschema2pojo-gradle-plugin
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 55c68b790..6b2866145 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
@@ -45,6 +45,8 @@ public class JsonSchemaExtension implements GenerationConfig {
Class extends Annotator> customAnnotator
Class extends RuleFactory> customRuleFactory
boolean generateBuilders
+ boolean includeJsonTypeInfoAnnotation
+ boolean useInnerClassBuilders
boolean includeGetters
boolean includeSetters
boolean includeAdditionalProperties
@@ -95,6 +97,8 @@ public class JsonSchemaExtension implements GenerationConfig {
public JsonSchemaExtension() {
// See DefaultGenerationConfig
generateBuilders = false
+ includeJsonTypeInfoAnnotation = false
+ useInnerClassBuilders = false
usePrimitives = false
sourceFiles = []
targetPackage = ''
@@ -148,6 +152,11 @@ public class JsonSchemaExtension implements GenerationConfig {
formatTypeMapping = Collections.emptyMap()
}
+ @Override
+ boolean isIncludeTypeInfo() {
+ return includeJsonTypeInfoAnnotation
+ }
+
@Override
public Iterator getSource() {
def urlList = []
@@ -201,6 +210,7 @@ public class JsonSchemaExtension implements GenerationConfig {
@Override
public String toString() {
"""|generateBuilders = ${generateBuilders}
+ |includeJsonTypeInfoAnnotation = ${includeJsonTypeInfoAnnotation}
|usePrimitives = ${usePrimitives}
|source = ${sourceFiles}
|targetDirectory = ${targetDirectory}
@@ -254,11 +264,12 @@ public class JsonSchemaExtension implements GenerationConfig {
|sourceSortOrder = ${sourceSortOrder}
|targetLanguage = ${targetLanguage}
|formatTypeMapping = ${formatTypeMapping}
+ |useInnerClassBuilders = ${useInnerClassBuilders}
""".stripMargin()
}
public boolean isFormatDateTimes() {
- return formatDateTimes;
+ return formatDateTimes
}
}
diff --git a/jsonschema2pojo-integration-tests/pom.xml b/jsonschema2pojo-integration-tests/pom.xml
index 2b911cd19..5275f830c 100644
--- a/jsonschema2pojo-integration-tests/pom.xml
+++ b/jsonschema2pojo-integration-tests/pom.xml
@@ -5,7 +5,7 @@
jsonschema2pojo
org.jsonschema2pojo
- 1.0.0-beta2-SNAPSHOT
+ 1.0.2-SNAPSHOT
jsonschema2pojo-integration-tests
diff --git a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/DescriptionEnumIT.java b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/DescriptionEnumIT.java
new file mode 100644
index 000000000..6d8c08b28
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/DescriptionEnumIT.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jsonschema2pojo.integration;
+
+import com.thoughtworks.qdox.JavaDocBuilder;
+import com.thoughtworks.qdox.model.JavaClass;
+import org.jsonschema2pojo.integration.util.Jsonschema2PojoRule;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+/*
+ Enums are treated differently to schemas of type object and we want to ensure that a description
+ added to root-level enums is added to the javadoc.
+ */
+public class DescriptionEnumIT {
+
+ @ClassRule public static Jsonschema2PojoRule schemaRule = new Jsonschema2PojoRule();
+
+ private static JavaClass classWithDescription;
+
+ @BeforeClass
+ public static void generateClasses() throws IOException {
+
+ schemaRule.generateAndCompile("/schema/description/descriptionEnum.json", "com.example");
+ File generatedJavaFile = schemaRule.generated("com/example/DescriptionEnum.java");
+
+ JavaDocBuilder javaDocBuilder = new JavaDocBuilder();
+ javaDocBuilder.addSource(generatedJavaFile);
+
+ classWithDescription = javaDocBuilder.getClassByName("com.example.DescriptionEnum");
+ }
+
+ @Test
+ public void descriptionAppearsInEnumJavadoc() {
+
+ String javaDocComment = classWithDescription.getComment();
+
+ assertThat(javaDocComment, containsString("A description for this enum"));
+
+ }
+
+}
diff --git a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/PolymorphicIT.java b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/PolymorphicIT.java
index ea7e49960..8381242d9 100644
--- a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/PolymorphicIT.java
+++ b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/PolymorphicIT.java
@@ -32,7 +32,10 @@
package org.jsonschema2pojo.integration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
+import static org.jsonschema2pojo.integration.util.CodeGenerationHelper.config;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import org.jsonschema2pojo.integration.util.Jsonschema2PojoRule;
import org.junit.Rule;
@@ -46,7 +49,7 @@ public class PolymorphicIT {
@Rule public Jsonschema2PojoRule schemaRule = new Jsonschema2PojoRule();
@Test
- public void extendsWithPolymorphicDeserialization() throws ClassNotFoundException {
+ public void extendsWithPolymorphicDeserializationWithDefaultAnnotationStyle() throws ClassNotFoundException {
ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema/polymorphic/extendsSchema.json", "com.example");
@@ -54,6 +57,32 @@ public void extendsWithPolymorphicDeserialization() throws ClassNotFoundExceptio
Class> supertype = subtype.getSuperclass();
assertNotNull(supertype.getAnnotation(JsonTypeInfo.class));
+ assertNull(supertype.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+ }
+
+ @Test
+ public void extendsWithPolymorphicDeserializationWithJackson2() throws ClassNotFoundException {
+
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema/polymorphic/extendsSchema.json", "com.example",
+ config("annotationStyle", "JACKSON2"));
+
+ Class> subtype = resultsClassLoader.loadClass("com.example.ExtendsSchema");
+ Class> supertype = subtype.getSuperclass();
+
+ assertNotNull(supertype.getAnnotation(JsonTypeInfo.class));
+ assertNull(supertype.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+ }
+
+ @Test
+ public void extendsWithPolymorphicDeserializationWithJackson1() throws ClassNotFoundException {
+
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema/polymorphic/extendsSchema.json", "com.example",
+ config("annotationStyle", "JACKSON1"));
+
+ Class> subtype = resultsClassLoader.loadClass("com.example.ExtendsSchema");
+ Class> supertype = subtype.getSuperclass();
+ assertNotNull(supertype.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+ assertNull(supertype.getAnnotation(JsonTypeInfo.class));
}
}
diff --git a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/TitleEnumIT.java b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/TitleEnumIT.java
new file mode 100644
index 000000000..579684260
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/TitleEnumIT.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jsonschema2pojo.integration;
+
+import com.thoughtworks.qdox.JavaDocBuilder;
+import com.thoughtworks.qdox.model.JavaClass;
+import org.jsonschema2pojo.integration.util.Jsonschema2PojoRule;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+/*
+ Enums are treated differently to schemas of type object and we want to ensure that a title
+ added to root-level enums is added to the javadoc.
+ */
+public class TitleEnumIT {
+ @ClassRule public static Jsonschema2PojoRule classSchemaRule = new Jsonschema2PojoRule();
+
+ private static JavaClass classWithTitle;
+
+ @BeforeClass
+ public static void generateClasses() throws IOException {
+
+ classSchemaRule.generateAndCompile("/schema/title/titleEnum.json", "com.example");
+ File generatedJavaFile = classSchemaRule.generated("com/example/TitleEnum.java");
+
+ JavaDocBuilder javaDocBuilder = new JavaDocBuilder();
+ javaDocBuilder.addSource(generatedJavaFile);
+
+ classWithTitle = javaDocBuilder.getClassByName("com.example.TitleEnum");
+ }
+
+ @Test
+ public void descriptionAppearsInEnumJavadoc() {
+
+ String javaDocComment = classWithTitle.getComment();
+
+ assertThat(javaDocComment, containsString("A title for this enum"));
+
+ }
+}
diff --git a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/CustomAnnotatorIT.java b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/CustomAnnotatorIT.java
index a38f969ec..993c12921 100644
--- a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/CustomAnnotatorIT.java
+++ b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/CustomAnnotatorIT.java
@@ -111,6 +111,11 @@ public void invalidCustomAnnotatorClassCausesMojoException() {
*/
public static class DeprecatingAnnotator implements Annotator {
+ @Override
+ public void typeInfo(JDefinedClass clazz, JsonNode schema) {
+
+ }
+
@Override
public void propertyOrder(JDefinedClass clazz, JsonNode propertiesNode) {
clazz.annotate(Deprecated.class);
@@ -172,6 +177,11 @@ public void additionalPropertiesField(JFieldVar field,
}
+ @Override
+ public boolean isPolymorphicDeserializationSupported(JsonNode node) {
+ return false;
+ }
+
@Override
public void dateField(JFieldVar field, JDefinedClass clazz, JsonNode propertyNode) {
field.annotate(Deprecated.class);
diff --git a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/IncludeJsr303AnnotationsIT.java b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/IncludeJsr303AnnotationsIT.java
index dda9891aa..1944130e6 100644
--- a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/IncludeJsr303AnnotationsIT.java
+++ b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/IncludeJsr303AnnotationsIT.java
@@ -25,6 +25,7 @@
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -223,6 +224,46 @@ public void jsr303SizeValidationIsAddedForSchemaRuleMaxLength() throws ClassNotF
assertNumberOfConstraintViolationsOn(invalidInstance, is(1));
}
+ @Test
+ public void jsr303DigitsValidationIsAddedForSchemaRuleDigits() throws ClassNotFoundException {
+
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema/jsr303/digits.json", "com.example",
+ config("includeJsr303Annotations", true, "useBigDecimals", true));
+
+ Class generatedType = resultsClassLoader.loadClass("com.example.Digits");
+
+ // positive value
+ Object validInstance = createInstanceWithPropertyValue(generatedType, "decimal", new BigDecimal("12345.1234567890"));
+
+ assertNumberOfConstraintViolationsOn(validInstance, is(0));
+
+ // negative value
+ validInstance = createInstanceWithPropertyValue(generatedType, "decimal", new BigDecimal("-12345.0123456789"));
+
+ assertNumberOfConstraintViolationsOn(validInstance, is(0));
+
+ // zero value
+ validInstance = createInstanceWithPropertyValue(generatedType, "decimal", new BigDecimal("0.0"));
+
+ assertNumberOfConstraintViolationsOn(validInstance, is(0));
+
+ // too many integer digits
+ Object invalidInstance = createInstanceWithPropertyValue(generatedType, "decimal", new BigDecimal("123456.0123456789"));
+
+ assertNumberOfConstraintViolationsOn(invalidInstance, is(1));
+
+ // too many fractional digits
+ invalidInstance = createInstanceWithPropertyValue(generatedType, "decimal", new BigDecimal("12345.12345678901"));
+
+ assertNumberOfConstraintViolationsOn(invalidInstance, is(1));
+
+ // too many integer & fractional digits
+ invalidInstance = createInstanceWithPropertyValue(generatedType, "decimal", new BigDecimal("123456.12345678901"));
+
+ assertNumberOfConstraintViolationsOn(invalidInstance, is(1));
+
+ }
+
@Test
public void jsr303ValidAnnotationIsAddedForObject() throws ClassNotFoundException {
ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema/jsr303/validObject.json", "com.example",
diff --git a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/IncludeTypeInfoIT.java b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/IncludeTypeInfoIT.java
new file mode 100644
index 000000000..bfaa93160
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/IncludeTypeInfoIT.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jsonschema2pojo.integration.config;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.jsonschema2pojo.integration.util.Jsonschema2PojoRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.jsonschema2pojo.integration.util.CodeGenerationHelper.config;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
+
+public class IncludeTypeInfoIT
+{
+ @Rule
+ public Jsonschema2PojoRule schemaRule = new Jsonschema2PojoRule();
+
+ @Test
+ public void defaultConfig() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfo.json", "com.example");
+
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfo");
+
+ assertNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+ }
+
+ @Test
+ public void defaultJackson1() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfo.json", "com.example",
+ config("annotationStyle", "JACKSON1"));
+
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfo");
+
+ assertNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+ }
+
+ @Test
+ public void defaultJackson1WithSchemaProperty() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfoWithSchemaProperty.json", "com.example",
+ config("annotationStyle", "JACKSON1"));
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfoWithSchemaProperty");
+
+ assertNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNotNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+
+ org.codehaus.jackson.annotate.JsonTypeInfo jsonTypeInfo = classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class);
+ assertThat(jsonTypeInfo.use(), is(org.codehaus.jackson.annotate.JsonTypeInfo.Id.CLASS));
+ assertThat(jsonTypeInfo.include(), is(org.codehaus.jackson.annotate.JsonTypeInfo.As.PROPERTY));
+ assertThat(jsonTypeInfo.property(), is("@clazz"));
+ }
+
+ @Test
+ public void defaultWithSchemaProperty() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfoWithSchemaProperty.json", "com.example");
+
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfoWithSchemaProperty");
+
+ assertNotNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+
+ JsonTypeInfo jsonTypeInfo = classWithTypeInfo.getAnnotation(JsonTypeInfo.class);
+ assertThat(jsonTypeInfo.use(), is(JsonTypeInfo.Id.CLASS));
+ assertThat(jsonTypeInfo.include(), is(JsonTypeInfo.As.PROPERTY));
+ assertThat(jsonTypeInfo.property(), is("@clazz"));
+ }
+
+ @Test
+ public void disabled() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfo.json", "com.example",
+ config("includeTypeInfo", false));
+
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfo");
+
+ assertNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+ }
+
+ @Test
+ public void disabledJackson1() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfo.json", "com.example",
+ config("annotationStyle", "JACKSON1",
+ "includeTypeInfo", false));
+
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfo");
+
+ assertNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+ }
+
+ @Test
+ public void disabledJackson1WithSchemaProperty() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfoWithSchemaProperty.json", "com.example",
+ config("annotationStyle", "JACKSON1",
+ "includeTypeInfo", false));
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfoWithSchemaProperty");
+
+ assertNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNotNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+
+ org.codehaus.jackson.annotate.JsonTypeInfo jsonTypeInfo = classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class);
+ assertThat(jsonTypeInfo.use(), is(org.codehaus.jackson.annotate.JsonTypeInfo.Id.CLASS));
+ assertThat(jsonTypeInfo.include(), is(org.codehaus.jackson.annotate.JsonTypeInfo.As.PROPERTY));
+ assertThat(jsonTypeInfo.property(), is("@clazz"));
+ }
+
+ @Test
+ public void disabledWithSchemaProperty() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfoWithSchemaProperty.json", "com.example",
+ config("includeTypeInfo", false));
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfoWithSchemaProperty");
+
+ assertNotNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+
+ JsonTypeInfo jsonTypeInfo = classWithTypeInfo.getAnnotation(JsonTypeInfo.class);
+ assertThat(jsonTypeInfo.use(), is(JsonTypeInfo.Id.CLASS));
+ assertThat(jsonTypeInfo.include(), is(JsonTypeInfo.As.PROPERTY));
+ assertThat(jsonTypeInfo.property(), is("@clazz"));
+ }
+
+ @Test
+ public void enabled() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfo.json", "com.example",
+ config("includeTypeInfo", true));
+
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfo");
+
+ assertNotNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+
+ JsonTypeInfo jsonTypeInfo = classWithTypeInfo.getAnnotation(JsonTypeInfo.class);
+ assertThat(jsonTypeInfo.use(), is(JsonTypeInfo.Id.CLASS));
+ assertThat(jsonTypeInfo.include(), is(JsonTypeInfo.As.PROPERTY));
+ assertThat(jsonTypeInfo.property(), is("@class"));
+ }
+
+ @Test
+ public void enabledJackson1() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfo.json", "com.example",
+ config("annotationStyle", "JACKSON1",
+ "includeTypeInfo", true));
+
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfo");
+
+ assertNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNotNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+
+ org.codehaus.jackson.annotate.JsonTypeInfo jsonTypeInfo = classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class);
+ assertThat(jsonTypeInfo.use(), is(org.codehaus.jackson.annotate.JsonTypeInfo.Id.CLASS));
+ assertThat(jsonTypeInfo.include(), is(org.codehaus.jackson.annotate.JsonTypeInfo.As.PROPERTY));
+ assertThat(jsonTypeInfo.property(), is("@class"));
+ }
+
+ @Test
+ public void enabledJackson1WithSchemaProperty() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfoWithSchemaProperty.json", "com.example",
+ config("annotationStyle", "JACKSON1",
+ "includeTypeInfo", true));
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfoWithSchemaProperty");
+
+ assertNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNotNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+
+ org.codehaus.jackson.annotate.JsonTypeInfo jsonTypeInfo = classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class);
+ assertThat(jsonTypeInfo.use(), is(org.codehaus.jackson.annotate.JsonTypeInfo.Id.CLASS));
+ assertThat(jsonTypeInfo.include(), is(org.codehaus.jackson.annotate.JsonTypeInfo.As.PROPERTY));
+ assertThat(jsonTypeInfo.property(), is("@clazz"));
+ }
+
+ @Test
+ public void enabledWithSchemaProperty() throws ClassNotFoundException
+ {
+
+ ClassLoader classLoader = schemaRule.generateAndCompile("/schema/typeInfo/typeInfoWithSchemaProperty.json", "com.example",
+ config("includeTypeInfo", true));
+ Class> classWithTypeInfo = classLoader.loadClass("com.example.TypeInfoWithSchemaProperty");
+
+ assertNotNull(classWithTypeInfo.getAnnotation(JsonTypeInfo.class));
+ assertNull(classWithTypeInfo.getAnnotation(org.codehaus.jackson.annotate.JsonTypeInfo.class));
+
+ JsonTypeInfo jsonTypeInfo = classWithTypeInfo.getAnnotation(JsonTypeInfo.class);
+ assertThat(jsonTypeInfo.use(), is(JsonTypeInfo.Id.CLASS));
+ assertThat(jsonTypeInfo.include(), is(JsonTypeInfo.As.PROPERTY));
+ assertThat(jsonTypeInfo.property(), is("@clazz"));
+ }
+}
diff --git a/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/UseInnerClassBuildersIT.java b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/UseInnerClassBuildersIT.java
new file mode 100644
index 000000000..680fd2fb5
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/java/org/jsonschema2pojo/integration/config/UseInnerClassBuildersIT.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright © 2010-2017 Nokia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jsonschema2pojo.integration.config;
+
+import static org.hamcrest.Matchers.not;
+import static org.jsonschema2pojo.integration.util.CodeGenerationHelper.config;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.stream.Stream;
+import org.apache.commons.lang.StringUtils;
+import org.hamcrest.Matcher;
+import org.jsonschema2pojo.integration.util.FileSearchMatcher;
+import org.jsonschema2pojo.integration.util.Jsonschema2PojoRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+@SuppressWarnings("rawtypes")
+public class UseInnerClassBuildersIT {
+
+ @Rule
+ public Jsonschema2PojoRule schemaRule = new Jsonschema2PojoRule();
+
+ private static Matcher containsText(String searchText) {
+ return new FileSearchMatcher(searchText);
+ }
+
+ /**
+ * This test asserts that no methods containing 'with' appear in the generated code using the default configuration
+ */
+ @Test
+ public void noBuilderMethodsByDefault() {
+ File outputDirectory = schemaRule.generate("/schema.useInnerClassBuilders/child.json", "com.example", config());
+
+ assertThat(outputDirectory, not(containsText("with")));
+ }
+
+ /**
+ * This method confirms that if you choose to generate builders, but don't indicate that useInnerBuilders is true, they will be generated using the
+ * chaining setters instead of the inner classes
+ */
+ @Test(expected = ClassNotFoundException.class)
+ public void defaultBuilderIsChainedSetters() throws ClassNotFoundException {
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema.useInnerClassBuilders/child.json", "com.example",
+ config("generateBuilders", true));
+
+ Class> childClass = resultsClassLoader.loadClass("com.example.Child");
+ boolean containsWithMethod = Stream.of(childClass.getMethods())
+ .map(Method::getName)
+ .anyMatch(methodName -> StringUtils.contains(methodName, "with"));
+
+ assertTrue("Generated class missing any builders at all", containsWithMethod);
+
+ resultsClassLoader.loadClass("com.example.Child.ChildBuilder");
+ }
+
+ /**
+ * This method confirms that if you choose to use inner class builders then the chaining setters will be removed from the generated class
+ */
+ @Test
+ public void innerBuildersRemoveChainedSetters() throws ClassNotFoundException {
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema.useInnerClassBuilders/child.json", "com.example",
+ config("generateBuilders", true, "useInnerClassBuilders", true));
+
+ Class> childClass = resultsClassLoader.loadClass("com.example.Child");
+ boolean containsWithMethod = Stream.of(childClass.getMethods())
+ .map(Method::getName)
+ .anyMatch(methodName -> StringUtils.contains(methodName, "with"));
+
+ assertFalse("Generated contains unexpected builders", containsWithMethod);
+
+ assertNotNull(resultsClassLoader.loadClass("com.example.Child$ChildBuilder"));
+ }
+
+ /**
+ * This methods confirms that the builders can be constructed using the empty constructor and possess a 'build' method that will return a non-null
+ * object
+ */
+ @Test
+ public void innerBuildersInvokeBuild()
+ throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema.useInnerClassBuilders/child.json", "com.example",
+ config("generateBuilders", true, "useInnerClassBuilders", true));
+
+ Class> builderClass = resultsClassLoader.loadClass("com.example.Child$ChildBuilder");
+ Method buildMethod = builderClass.getMethod("build");
+
+ Object builder = builderClass.newInstance();
+ assertNotNull(builder);
+
+ assertNotNull(buildMethod.invoke(builder));
+ }
+
+ /**
+ * This method walks through invoking the various incremental 'with' methods to build out an entire object, then invokes build on the constructed
+ * object and confirms all values on the object match those provided to the with methods
+ */
+ @Test
+ public void innerBuildersBuildObjectIncrementally()
+ throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema.useInnerClassBuilders/child.json", "com.example",
+ config("generateBuilders", true, "useInnerClassBuilders", true));
+
+ Class> builderClass = resultsClassLoader.loadClass("com.example.Child$ChildBuilder");
+ Method buildMethod = builderClass.getMethod("build");
+ Method withChildProperty = builderClass.getMethod("withChildProperty", Integer.class);
+ Method withParentProperty = builderClass.getMethod("withParentProperty", String.class);
+ Method withSharedProperty = builderClass.getMethod("withSharedProperty", String.class);
+
+ int childProperty = 1;
+ String parentProperty = "parentProperty";
+ String sharedProperty = "sharedProperty";
+
+ Object builder = builderClass.newInstance();
+ withChildProperty.invoke(builder, childProperty);
+ withParentProperty.invoke(builder, parentProperty);
+ withSharedProperty.invoke(builder, sharedProperty);
+ Object childObject = buildMethod.invoke(builder);
+
+ Class> childClass = resultsClassLoader.loadClass("com.example.Child");
+ Method getChildProperty = childClass.getMethod("getChildProperty");
+ Method getParentProperty = childClass.getMethod("getParentProperty");
+ Method getSharedProperty = childClass.getMethod("getSharedProperty");
+
+ assertEquals(childProperty, getChildProperty.invoke(childObject));
+ assertEquals(parentProperty, getParentProperty.invoke(childObject));
+ assertEquals(sharedProperty, getSharedProperty.invoke(childObject));
+ }
+
+ /**
+ * This method confirms that by default the only constructor available to a builder is the empty argument constructor
+ */
+ @Test
+ public void innerBuilderExtraConstructorsRequireConfig() throws ClassNotFoundException {
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema.useInnerClassBuilders/child.json", "com.example",
+ config("generateBuilders", true, "useInnerClassBuilders", true));
+
+ Class> builderClass = resultsClassLoader.loadClass("com.example.Child$ChildBuilder");
+ assertEquals(1, builderClass.getConstructors().length);
+
+ Constructor> constructor = builderClass.getConstructors()[0];
+ assertEquals(0, constructor.getParameterCount());
+ }
+
+ /**
+ * This method confirms that if constructors are enabled then a builder constructor which takes all properties will be created
+ */
+ @Test
+ public void innerBuilderWithAllPropertyConstructor()
+ throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema.useInnerClassBuilders/child.json", "com.example",
+ config("generateBuilders", true, "useInnerClassBuilders", true, "includeConstructors", true));
+
+ Class> builderClass = resultsClassLoader.loadClass("com.example.Child$ChildBuilder");
+ Constructor> constructor = builderClass.getConstructor(Integer.class, String.class, String.class);
+ Method buildMethod = builderClass.getMethod("build");
+
+ int childProperty = 1;
+ String parentProperty = "parentProperty";
+ String sharedProperty = "sharedProperty";
+
+ Object builder = constructor.newInstance(childProperty, sharedProperty, parentProperty);
+ Object childObject = buildMethod.invoke(builder);
+
+ Class> childClass = resultsClassLoader.loadClass("com.example.Child");
+ Method getChildProperty = childClass.getMethod("getChildProperty");
+ Method getParentProperty = childClass.getMethod("getParentProperty");
+ Method getSharedProperty = childClass.getMethod("getSharedProperty");
+
+ assertEquals(childProperty, getChildProperty.invoke(childObject));
+ assertEquals(parentProperty, getParentProperty.invoke(childObject));
+ assertEquals(sharedProperty, getSharedProperty.invoke(childObject));
+ }
+
+ /**
+ * This method confirms that if constructors are enabled and constructorsRequiredPropertiesOnly is set to true then a only a builder constructor
+ * with the required properties will be created
+ */
+ @Test
+ public void innerBuilderWithRequiredPropertyConstructor()
+ throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
+ ClassLoader resultsClassLoader = schemaRule.generateAndCompile("/schema.useInnerClassBuilders/child.json", "com.example",
+ config("generateBuilders", true, "useInnerClassBuilders", true, "includeConstructors", true, "constructorsRequiredPropertiesOnly", true));
+
+ Class> builderClass = resultsClassLoader.loadClass("com.example.Child$ChildBuilder");
+ Constructor> constructor = builderClass.getConstructor(String.class);
+ Method buildMethod = builderClass.getMethod("build");
+ Method withChildProperty = builderClass.getMethod("withChildProperty", Integer.class);
+ Method withSharedProperty = builderClass.getMethod("withSharedProperty", String.class);
+
+ int childProperty = 1;
+ String parentProperty = "parentProperty";
+ String sharedProperty = "sharedProperty";
+
+ Object builder = constructor.newInstance(parentProperty);
+ withChildProperty.invoke(builder, childProperty);
+ withSharedProperty.invoke(builder, sharedProperty);
+ Object childObject = buildMethod.invoke(builder);
+
+ Class> childClass = resultsClassLoader.loadClass("com.example.Child");
+ Method getChildProperty = childClass.getMethod("getChildProperty");
+ Method getParentProperty = childClass.getMethod("getParentProperty");
+ Method getSharedProperty = childClass.getMethod("getSharedProperty");
+
+ assertEquals(childProperty, getChildProperty.invoke(childObject));
+ assertEquals(parentProperty, getParentProperty.invoke(childObject));
+ assertEquals(sharedProperty, getSharedProperty.invoke(childObject));
+ }
+}
diff --git a/jsonschema2pojo-integration-tests/src/test/resources/schema.useInnerClassBuilders/child.json b/jsonschema2pojo-integration-tests/src/test/resources/schema.useInnerClassBuilders/child.json
new file mode 100644
index 000000000..1a71d461e
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/resources/schema.useInnerClassBuilders/child.json
@@ -0,0 +1,10 @@
+{
+ "type" : "object",
+ "extends" : {
+ "$ref" : "parent.json"
+ },
+ "properties" : {
+ "childProperty" : { "type" : "integer"},
+ "sharedProperty" : { "type" : "string" }
+ }
+}
\ No newline at end of file
diff --git a/jsonschema2pojo-integration-tests/src/test/resources/schema.useInnerClassBuilders/parent.json b/jsonschema2pojo-integration-tests/src/test/resources/schema.useInnerClassBuilders/parent.json
new file mode 100644
index 000000000..99779bab6
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/resources/schema.useInnerClassBuilders/parent.json
@@ -0,0 +1,8 @@
+{
+ "type" : "object",
+ "properties" : {
+ "parentProperty" : { "type" : "string" },
+ "sharedProperty" : { "type" : "string" }
+ },
+ "required" : ["parentProperty"]
+}
\ No newline at end of file
diff --git a/jsonschema2pojo-integration-tests/src/test/resources/schema/description/descriptionEnum.json b/jsonschema2pojo-integration-tests/src/test/resources/schema/description/descriptionEnum.json
new file mode 100644
index 000000000..dda38b1e3
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/resources/schema/description/descriptionEnum.json
@@ -0,0 +1,5 @@
+{
+ "description" : "A description for this enum",
+ "type":"string",
+ "enum": ["one", "two"]
+}
\ No newline at end of file
diff --git a/jsonschema2pojo-integration-tests/src/test/resources/schema/jsr303/digits.json b/jsonschema2pojo-integration-tests/src/test/resources/schema/jsr303/digits.json
new file mode 100644
index 000000000..22791f285
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/resources/schema/jsr303/digits.json
@@ -0,0 +1,10 @@
+{
+ "type": "object",
+ "properties": {
+ "decimal": {
+ "type": "number",
+ "integerDigits": 5,
+ "fractionalDigits": 10
+ }
+ }
+}
\ No newline at end of file
diff --git a/jsonschema2pojo-integration-tests/src/test/resources/schema/title/titleEnum.json b/jsonschema2pojo-integration-tests/src/test/resources/schema/title/titleEnum.json
new file mode 100644
index 000000000..305861d5e
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/resources/schema/title/titleEnum.json
@@ -0,0 +1,5 @@
+{
+ "title" : "A title for this enum",
+ "type":"string",
+ "enum": ["one", "two"]
+}
\ No newline at end of file
diff --git a/jsonschema2pojo-integration-tests/src/test/resources/schema/typeInfo/typeInfo.json b/jsonschema2pojo-integration-tests/src/test/resources/schema/typeInfo/typeInfo.json
new file mode 100644
index 000000000..5c649ee45
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/resources/schema/typeInfo/typeInfo.json
@@ -0,0 +1,4 @@
+{
+ "type" : "object",
+ "properties" : {}
+}
\ No newline at end of file
diff --git a/jsonschema2pojo-integration-tests/src/test/resources/schema/typeInfo/typeInfoWithSchemaProperty.json b/jsonschema2pojo-integration-tests/src/test/resources/schema/typeInfo/typeInfoWithSchemaProperty.json
new file mode 100644
index 000000000..b51c7b3a7
--- /dev/null
+++ b/jsonschema2pojo-integration-tests/src/test/resources/schema/typeInfo/typeInfoWithSchemaProperty.json
@@ -0,0 +1,5 @@
+{
+ "type" : "object",
+ "deserializationClassProperty": "@clazz",
+ "properties" : {}
+}
\ No newline at end of file
diff --git a/jsonschema2pojo-maven-plugin/pom.xml b/jsonschema2pojo-maven-plugin/pom.xml
index 3092044f5..48f3b56e5 100644
--- a/jsonschema2pojo-maven-plugin/pom.xml
+++ b/jsonschema2pojo-maven-plugin/pom.xml
@@ -5,7 +5,7 @@
jsonschema2pojo
org.jsonschema2pojo
- 1.0.0-beta2-SNAPSHOT
+ 1.0.2-SNAPSHOT
jsonschema2pojo-maven-plugin
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 b049cd4aa..755773163 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
@@ -112,6 +112,17 @@ public class Jsonschema2PojoMojo extends AbstractMojo implements GenerationConfi
*/
private boolean generateBuilders = false;
+ /**
+ * Whether to include json type information; often required to support polymorphic type handling.
+ *
+ * By default the type information is stored in the @class property, this can be overridden in the deserializationClassProperty
+ * of the schema.
+ *
+ * @parameter property="jsonschema2pojo.includeTypeInfo"
+ * default-value="false"
+ * @since 1.0.2
+ */
+ private boolean includeTypeInfo = false;
/**
* Whether to use primitives (long
, double
,
* boolean
) instead of wrapper types where possible when
@@ -745,6 +756,13 @@ public class Jsonschema2PojoMojo extends AbstractMojo implements GenerationConfi
*/
private Map formatTypeMapping = new HashMap<>();
+ /**
+ * @parameter property="jsonschema2pojo.useInnerClassBuilders"
+ * default-value="false"
+ * @since 1.0.0
+ */
+ private boolean useInnerClassBuilders = false;
+
/**
* Executes the plugin, to read the given source and behavioural properties
* and generate POJOs. The current implementation acts as a wrapper around
@@ -844,6 +862,12 @@ public boolean isGenerateBuilders() {
return generateBuilders;
}
+ @Override
+ public boolean isIncludeTypeInfo()
+ {
+ return includeTypeInfo;
+ }
+
@Override
public File getTargetDirectory() {
return outputDirectory;
@@ -1159,4 +1183,9 @@ public Language getTargetLanguage() {
public Map getFormatTypeMapping() {
return formatTypeMapping;
}
+
+ @Override
+ public boolean isUseInnerClassBuilders() {
+ return useInnerClassBuilders;
+ }
}
diff --git a/jsonschema2pojo-maven-plugin/src/test/resources/example/pom.xml b/jsonschema2pojo-maven-plugin/src/test/resources/example/pom.xml
index 5d4fca6d0..2849b96b2 100644
--- a/jsonschema2pojo-maven-plugin/src/test/resources/example/pom.xml
+++ b/jsonschema2pojo-maven-plugin/src/test/resources/example/pom.xml
@@ -40,7 +40,7 @@
com.fasterxml.jackson.core
jackson-databind
- 2.9.7
+ 2.9.8
diff --git a/jsonschema2pojo-maven-plugin/src/test/resources/filtered/pom.xml b/jsonschema2pojo-maven-plugin/src/test/resources/filtered/pom.xml
index 4cf290f47..3caf0d30d 100644
--- a/jsonschema2pojo-maven-plugin/src/test/resources/filtered/pom.xml
+++ b/jsonschema2pojo-maven-plugin/src/test/resources/filtered/pom.xml
@@ -43,7 +43,7 @@
com.fasterxml.jackson.core
jackson-databind
- 2.9.7
+ 2.9.8
diff --git a/jsonschema2pojo-scalagen/pom.xml b/jsonschema2pojo-scalagen/pom.xml
index 0dc40eb61..8ff8b81a3 100644
--- a/jsonschema2pojo-scalagen/pom.xml
+++ b/jsonschema2pojo-scalagen/pom.xml
@@ -6,12 +6,12 @@
jsonschema2pojo
org.jsonschema2pojo
- 1.0.0-beta2-SNAPSHOT
+ 1.0.2-SNAPSHOT
org.jsonschema2pojo
jsonschema2pojo-scalagen
- 1.0.0-beta2-SNAPSHOT
+ 1.0.2-SNAPSHOT
4.01
diff --git a/pom.xml b/pom.xml
index 199bc9196..3f091283f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
org.jsonschema2pojo
jsonschema2pojo
- 1.0.0-beta2-SNAPSHOT
+ 1.0.2-SNAPSHOT
pom
jsonschema2pojo
@@ -54,8 +54,8 @@
1.6
2.5
1.5.0
- 2.9.7
- 2.11.6
+ 2.9.8
+ 2.11.12