/** * Applies this schema rule to take the required code generation steps. * <p> * At the root of a schema document this rule should be applied (schema * documents contain a schema), but also in many places within the document. * Each property of type "object" is itself defined by a schema, the items * attribute of an array is a schema, the additionalProperties attribute of * a schema is also a schema. * <p> * Where the schema value is a $ref, the ref URI is assumed to be applicable * as a URL (from which content will be read). Where the ref URI has been * encountered before, the root Java type created by that schema will be * re-used (generation steps won't be repeated). * * @param schema * the schema within which this schema rule is being applied */ @Override public JType apply(String nodeName, JsonNode schemaNode, JClassContainer generatableType, Schema schema) { if (schemaNode.has("$ref")) { schema = ruleFactory.getSchemaStore().create(schema, schemaNode.get("$ref").asText(), ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters()); schemaNode = schema.getContent(); if (schema.isGenerated()) { return schema.getJavaType(); } return apply(nodeName, schemaNode, generatableType, schema); } JType javaType; if (schemaNode.has("enum")) { javaType = ruleFactory.getEnumRule().apply(nodeName, schemaNode, generatableType, schema); } else { javaType = ruleFactory.getTypeRule().apply(nodeName, schemaNode, generatableType.getPackage(), schema); } schema.setJavaTypeIfEmpty(javaType); return javaType; }
/** * Applies this schema rule to take the required code generation steps. * <p> * At the root of a schema document this rule should be applied (schema * documents contain a schema), but also in many places within the document. * Each property of type "object" is itself defined by a schema, the items * attribute of an array is a schema, the additionalProperties attribute of * a schema is also a schema. * <p> * Where the schema value is a $ref, the ref URI is assumed to be applicable * as a URL (from which content will be read). Where the ref URI has been * encountered before, the root Java type created by that schema will be * re-used (generation steps won't be repeated). * * @param schema * the schema within which this schema rule is being applied */ @Override public JType apply(String nodeName, JsonNode schemaNode, JClassContainer generatableType, Schema schema) { if (schemaNode.has("$ref")) { schema = ruleFactory.getSchemaStore().create(schema, schemaNode.get("$ref").asText()); schemaNode = schema.getContent(); if (schema.isGenerated()) { return schema.getJavaType(); } return apply(nodeName, schemaNode, generatableType, schema); } JType javaType; if (schemaNode.has("enum")) { javaType = ruleFactory.getEnumRule().apply(nodeName, schemaNode, generatableType, schema); } else { javaType = ruleFactory.getTypeRule().apply(nodeName, schemaNode, generatableType.getPackage(), schema); } schema.setJavaTypeIfEmpty(javaType); return javaType; }
private String getEnumName(String nodeName, JsonNode node, JClassContainer container) { String fieldName = ruleFactory.getNameHelper().getFieldName(nodeName, node); String className = ruleFactory.getNameHelper().replaceIllegalCharacters(capitalize(fieldName)); String normalizedName = ruleFactory.getNameHelper().normalizeName(className); Collection<String> existingClassNames = new ArrayList<String>(); for (Iterator<JDefinedClass> classes = container.classes(); classes.hasNext();) { existingClassNames.add(classes.next().name()); } return makeUnique(normalizedName, existingClassNames); }
public static JClass resolveType(JClassContainer _package, String typeDefinition) { try { FieldDeclaration fieldDeclaration = (FieldDeclaration) JavaParser.parseBodyDeclaration(typeDefinition + " foo;"); ClassOrInterfaceType c = (ClassOrInterfaceType) ((ReferenceType) fieldDeclaration.getType()).getType(); return buildClass(_package, c, 0); } catch (ParseException e) { throw new GenerationException(e); } }
private static JClass buildClass(JClassContainer _package, ClassOrInterfaceType c, int arrayCount) { final String packagePrefix = (c.getScope() != null) ? c.getScope().toString() + "." : ""; JClass _class; try { _class = _package.owner().ref(Thread.currentThread().getContextClassLoader().loadClass(packagePrefix + c.getName())); } catch (ClassNotFoundException e) { _class = _package.owner().ref(packagePrefix + c.getName()); } for (int i=0; i<arrayCount; i++) { _class = _class.array(); } List<Type> typeArgs = c.getTypeArgs(); if (typeArgs != null && typeArgs.size() > 0) { JClass[] genericArgumentClasses = new JClass[typeArgs.size()]; for (int i=0; i<typeArgs.size(); i++) { genericArgumentClasses[i] = buildClass(_package, (ClassOrInterfaceType) ((ReferenceType) typeArgs.get(i)).getType(), ((ReferenceType) typeArgs.get(i)).getArrayCount()); } _class = _class.narrow(genericArgumentClasses); } return _class; }
private JType getSuperType(String nodeName, JsonNode node, JClassContainer jClassContainer, Schema schema) { JType superType = jClassContainer.owner().ref(Object.class); if (node.has("extends")) { superType = ruleFactory.getSchemaRule().apply(nodeName + "Parent", node.get("extends"), jClassContainer, schema); } return superType; }
public static JDefinedClass getOrCreateClass(JClassContainer container, int flags, String name) { try { return container._class(flags, name); } catch (JClassAlreadyExistsException jcaeex) { return jcaeex.getExistingClass(); } }
/** * Applies this schema rule to take the required code generation steps. * <p> * 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}. * <p> * JSON schema types and their Java type equivalent: * <ul> * <li>"type":"any" => {@link java.lang.Object} * <li>"type":"array" => Either {@link java.util.Set} or * <li>"type":"boolean" => <code>boolean</code> * <li>"type":"integer" => <code>int</code> * <li>"type":"null" => {@link java.lang.Object} * <li>"type":"number" => <code>double</code> * <li>"type":"object" => Generated type (see {@link ObjectRule}) * {@link java.util.List}, see {@link ArrayRule} * <li>"type":"string" => {@link java.lang.String} (or alternative based on * presence of "format", see {@link FormatRule}) * </ul> * * @param nodeName * the name of the node for which this "type" rule applies * @param node * the node for which this "type" rule applies * @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, JClassContainer jClassContainer, Schema schema) { String propertyTypeName = getTypeName(node); JType type; if (propertyTypeName.equals("string")) { type = jClassContainer.owner().ref(String.class); } else if (propertyTypeName.equals("number")) { type = unboxIfNecessary(jClassContainer.owner().ref(Double.class), ruleFactory.getGenerationConfig()); } else if (propertyTypeName.equals("integer")) { JType typeToUseForIntegers = getIntegerType(jClassContainer.owner(), ruleFactory.getGenerationConfig()); type = unboxIfNecessary(typeToUseForIntegers, ruleFactory.getGenerationConfig()); } else if (propertyTypeName.equals("boolean")) { type = unboxIfNecessary(jClassContainer.owner().ref(Boolean.class), ruleFactory.getGenerationConfig()); } else if (propertyTypeName.equals("object")) { type = ruleFactory.getObjectRule().apply(nodeName, node, jClassContainer.getPackage(), schema); } else if (propertyTypeName.equals("array")) { type = ruleFactory.getArrayRule().apply(nodeName, node, jClassContainer.getPackage(), schema); } else { type = jClassContainer.owner().ref(Object.class); } if (node.has("format")) { type = ruleFactory.getFormatRule().apply(nodeName, node.get("format"), type, schema); } return type; }
/** * Applies this schema rule to take the required code generation steps. * <p> * A Java {@link Enum} is created, with constants for each of the enum * values present in the schema. The enum name is derived from the nodeName, * and the enum type itself is created as an inner class of the owning type. * In the rare case that no owning type exists (the enum is the root of the * schema), then the enum becomes a public class in its own right. * <p> * The actual JSON value for each enum constant is held in a property called * "value" in the generated type. A static factory method * <code>fromValue(String)</code> is added to the generated enum, and the * methods are annotated to allow Jackson to marshal/unmarshal values * correctly. * * @param nodeName * the name of the property which is an "enum" * @param node * the enum node * @param container * the class container (class or package) to which this enum * should be added * @return the newly generated Java type that was created to represent the * given enum */ @Override public JType apply(String nodeName, JsonNode node, JClassContainer container, Schema schema) { JDefinedClass _enum; try { _enum = createEnum(node, nodeName, container); } catch (ClassAlreadyExistsException e) { return e.getExistingClass(); } schema.setJavaTypeIfEmpty(_enum); if (node.has("javaInterfaces")) { addInterfaces(_enum, node.get("javaInterfaces")); } // copy our node; remove the javaType as it will throw off the TypeRule for our case ObjectNode typeNode = (ObjectNode)node.deepCopy(); typeNode.remove("javaType"); // If type is specified on the enum, get a type rule for it. Otherwise, we're a string. // (This is different from the default of Object, which is why we don't do this for every case.) JType backingType = node.has("type") ? ruleFactory.getTypeRule().apply(nodeName, typeNode, container, schema) : container.owner().ref(String.class); JFieldVar valueField = addValueField(_enum, backingType); // override toString only if we have a sensible string to return if(isString(backingType)){ addToString(_enum, valueField); } addValueMethod(_enum, valueField); addEnumConstants(node.path("enum"), _enum, node.path("javaEnumNames"), backingType); addFactoryMethod(_enum, backingType); return _enum; }
/** * Applies this schema rule to take the required code generation steps. * <p> * 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}. * <p> * JSON schema types and their Java type equivalent: * <ul> * <li>"type":"any" => {@link java.lang.Object} * <li>"type":"array" => Either {@link java.util.Set} or * {@link java.util.List}, see {@link ArrayRule} * <li>"type":"boolean" => <code>boolean</code> * <li>"type":"integer" => <code>int</code> * <li>"type":"null" => {@link java.lang.Object} * <li>"type":"number" => <code>double</code> * <li>"type":"object" => Generated type (see {@link ObjectRule}) * <li>"type":"string" => {@link java.lang.String} (or alternative based * on presence of "format", see {@link FormatRule}) * </ul> * * @param nodeName * the name of the node for which this "type" rule applies * @param node * the node for which this "type" rule applies * @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, 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, jClassContainer.getPackage(), schema); } else if (node.has("javaType")) { String typeName = node.path("javaType").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, jClassContainer.getPackage(), schema); } else { type = jClassContainer.owner().ref(Object.class); } if (!node.has("javaType") && node.has("format")) { type = ruleFactory.getFormatRule().apply(nodeName, node.get("format"), type, schema); } else if (!node.has("javaType") && propertyTypeName.equals("string") && node.has("media")) { type = ruleFactory.getMediaRule().apply(nodeName, node.get("media"), type, schema); } return type; }
@Override public Rule<JClassContainer, JType> getTypeRule() { return new SoeTypeRule(this); }
/** * Applies this schema rule to take the required code generation steps. * <p> * 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}. * <p> * JSON schema types and their Java type equivalent: * <ul> * <li>"type":"any" => {@link java.lang.Object} * <li>"type":"array" => Either {@link java.util.Set} or * <li>"type":"boolean" => <code>boolean</code> * <li>"type":"integer" => <code>int</code> * <li>"type":"null" => {@link java.lang.Object} * <li>"type":"number" => <code>double</code> * <li>"type":"object" => Generated type (see {@link org.jsonschema2pojo.rules.ObjectRule}) * {@link java.util.List}, see {@link org.jsonschema2pojo.rules.ArrayRule} * <li>"type":"string" => {@link java.lang.String} (or alternative based on * presence of "format", see {@link org.jsonschema2pojo.rules.FormatRule}) * </ul> * * @param nodeName * the name of the node for which this "type" rule applies * @param node * the node for which this "type" rule applies * @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, JClassContainer jClassContainer, Schema schema) { String propertyTypeName = getTypeName(node); JType type; if (propertyTypeName.equals("string")) { type = jClassContainer.owner().ref(String.class); } else if (propertyTypeName.equals("number")) { JType typeToUseForNumbers = getNumberType(jClassContainer.owner(), ruleFactory.getGenerationConfig()); type = unboxIfNecessary(typeToUseForNumbers, ruleFactory.getGenerationConfig()); } else if (propertyTypeName.equals("integer")) { JType typeToUseForIntegers = getIntegerType(jClassContainer.owner(), ruleFactory.getGenerationConfig()); type = unboxIfNecessary(typeToUseForIntegers, ruleFactory.getGenerationConfig()); } else if (propertyTypeName.equals("short")) { JType typeToUseForShorts = jClassContainer.owner().ref(Short.class); type = unboxIfNecessary(typeToUseForShorts, ruleFactory.getGenerationConfig()); } else if (propertyTypeName.equals("byte")) { JType typeToUseForBytes = jClassContainer.owner().ref(Byte.class); type = unboxIfNecessary(typeToUseForBytes, ruleFactory.getGenerationConfig()); } else if (propertyTypeName.equals("boolean")) { type = unboxIfNecessary(jClassContainer.owner().ref(Boolean.class), ruleFactory.getGenerationConfig()); } else if (propertyTypeName.equals("object") || (node.has("properties") && node.path("properties").size() > 0)) { type = ruleFactory.getObjectRule().apply(nodeName, node, jClassContainer.getPackage(), schema); } else if (propertyTypeName.equals("array")) { type = ruleFactory.getArrayRule().apply(nodeName, node, jClassContainer.getPackage(), schema); } else { type = jClassContainer.owner().ref(Object.class); } if (node.has("format")) { type = ruleFactory.getFormatRule().apply(nodeName, node.get("format"), type, schema); } else if(propertyTypeName.equals("string") && node.has("media")) { type = ruleFactory.getMediaRule().apply(nodeName, node.get("media"), type, schema); } return type; }
/** * Applies this schema rule to take the required code generation steps. * <p> * A Java {@link Enum} is created, with constants for each of the enum * values present in the schema. The enum name is derived from the nodeName, * and the enum type itself is created as an inner class of the owning type. * In the rare case that no owning type exists (the enum is the root of the * schema), then the enum becomes a public class in its own right. * <p> * The actual JSON value for each enum constant is held in a property called * "value" in the generated type. A static factory method * <code>fromValue(String)</code> is added to the generated enum, and the * methods are annotated to allow Jackson to marshal/unmarshal values * correctly. * * @param nodeName * the name of the property which is an "enum" * @param node * the enum node * @param container * the class container (class or package) to which this enum * should be added * @return the newly generated Java type that was created to represent the * given enum */ @Override public JType apply(String nodeName, JsonNode node, JClassContainer container, Schema schema) { JDefinedClass _enum; try { _enum = createEnum(node, nodeName, container); } catch (ClassAlreadyExistsException e) { return e.getExistingClass(); } schema.setJavaTypeIfEmpty(_enum); addGeneratedAnnotation(_enum); JFieldVar valueField = addValueField(_enum); addToString(_enum, valueField); addEnumConstants(node.path("enum"), _enum); addFactoryMethod(node.path("enum"), _enum); return _enum; }
/** * Provides a rule instance that should be applied when an "enum" * declaration is found in the schema. * * @return a schema rule that can handle the "enum" declaration. */ public Rule<JClassContainer, JType> getEnumRule() { return new EnumRule(this); }
/** * Provides a rule instance that should be applied to a node to find its * equivalent Java type. Typically invoked for properties, arrays, etc for * which a Java type must be found/generated. * * @return a schema rule that can find/generate the relevant Java type for a * given schema node. */ public Rule<JClassContainer, JType> getTypeRule() { return new TypeRule(this); }
/** * Provides a rule instance that should be applied when a schema declaration * is found in the schema. * * @return a schema rule that can handle a schema declaration. */ public Rule<JClassContainer, JType> getSchemaRule() { return new SchemaRule(this); }