All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.jsonschema2pojo.rules.ObjectRule Maven / Gradle / Ivy

There is a newer version: 0.3.7
Show newest version
/**
 * Copyright © 2010-2011 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 com.googlecode.jsonschema2pojo.rules;

import static com.googlecode.jsonschema2pojo.rules.PrimitiveTypes.*;
import static org.apache.commons.lang.StringUtils.*;

import java.io.Serializable;
import java.lang.reflect.Modifier;

import javax.annotation.Generated;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.annotate.JsonSerialize;

import com.googlecode.jsonschema2pojo.Schema;
import com.googlecode.jsonschema2pojo.SchemaMapper;
import com.googlecode.jsonschema2pojo.exception.ClassAlreadyExistsException;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JClassAlreadyExistsException;
import com.sun.codemodel.JClassContainer;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JPackage;
import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;

/**
 * Applies the generation steps required for schemas of type "object".
 * 
 * @see http://tools.ietf.org/html/draft-zyp-json-schema-02#section-5.1
 */
public class ObjectRule implements SchemaRule {

    private static final String ILLEGAL_CHARACTER_REGEX = "[^0-9a-zA-Z]";

    private final RuleFactory ruleFactory;
    
    protected ObjectRule(RuleFactory ruleFactory) {
        this.ruleFactory = ruleFactory;
    }

    /**
     * Applies this schema rule to take the required code generation steps.
     * 

* When this rule is applied for schemas of type object, the properties of * the schema are used to generate a new Java class and determine its * characteristics. See other implementers of {@link SchemaRule} for * details. *

* A new Java type will be created when this rule is applied, it is * annotated as {@link Generated}, it is given equals, * hashCode and toString methods and implements * {@link Serializable}. */ @Override public JType apply(String nodeName, JsonNode node, JPackage _package, Schema schema) { JType superType = getSuperType(nodeName, node, _package, schema); if (superType.isPrimitive() || isFinal(superType)) { return superType; } JDefinedClass jclass; try { jclass = createClass(nodeName, node, _package); } catch (ClassAlreadyExistsException e) { return e.getExistingClass(); } jclass._extends((JClass) superType); schema.setJavaTypeIfEmpty(jclass); addGeneratedAnnotation(jclass); addSerializable(jclass); if (node.has("title")) { ruleFactory.getTitleRule().apply(nodeName, node.get("title"), jclass, schema); } if (node.has("description")) { ruleFactory.getDescriptionRule().apply(nodeName, node.get("description"), jclass, schema); } if (node.has("properties")) { ruleFactory.getPropertiesRule().apply(nodeName, node.get("properties"), jclass, schema); } addToString(jclass); addHashCode(jclass); addEquals(jclass); ruleFactory.getAdditionalPropertiesRule().apply(nodeName, node.get("additionalProperties"), jclass, schema); return jclass; } /** * Creates a new Java class that will be generated. * * @param nodeName * the node name which may be used to dictate the new class name * @param node * the node representing the schema that caused the need for a * new class. This node may include a 'javaType' property which * if present will override the fully qualified name of the newly * generated class. * @param _package * the package which may contain a new class after this method * call * @return a reference to a newly created class * @throws ClassAlreadyExistsException * if the given arguments cause an attempt to create a class * that already exists, either on the classpath or in the * current map of classes to be generated. */ private JDefinedClass createClass(String nodeName, JsonNode node, JPackage _package) throws ClassAlreadyExistsException { JDefinedClass newType; try { if (node.has("javaType")) { String fqn = node.get("javaType").getTextValue(); if (isPrimitive(fqn, _package.owner())) { throw new ClassAlreadyExistsException(primitiveType(fqn, _package.owner())); } try { Class existingClass = Thread.currentThread().getContextClassLoader().loadClass(fqn); throw new ClassAlreadyExistsException(_package.owner().ref(existingClass)); } catch (ClassNotFoundException e) { newType = _package.owner()._class(fqn); } } else { newType = _package._class(getClassName(nodeName)); } } catch (JClassAlreadyExistsException e) { throw new ClassAlreadyExistsException(e.getExistingClass()); } return addAnnotations(newType); } /** * Add any class-level annotations required for a newly generated class. * * @param _class * the newly generated class * @return */ private JDefinedClass addAnnotations(JDefinedClass _class) { _class.annotate(JsonSerialize.class).param("include", JsonSerialize.Inclusion.NON_NULL); return _class; } 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, 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; } private void addSerializable(JDefinedClass jclass) { jclass._implements(Serializable.class); } private void addGeneratedAnnotation(JDefinedClass jclass) { JAnnotationUse generated = jclass.annotate(Generated.class); generated.param("value", SchemaMapper.class.getPackage().getName()); } private void addToString(JDefinedClass jclass) { JMethod toString = jclass.method(JMod.PUBLIC, String.class, "toString"); JBlock body = toString.body(); JInvocation reflectionToString = jclass.owner().ref(ToStringBuilder.class).staticInvoke("reflectionToString"); reflectionToString.arg(JExpr._this()); body._return(reflectionToString); toString.annotate(Override.class); } private void addHashCode(JDefinedClass jclass) { JMethod hashCode = jclass.method(JMod.PUBLIC, int.class, "hashCode"); JBlock body = hashCode.body(); JInvocation reflectionHashCode = jclass.owner().ref(HashCodeBuilder.class).staticInvoke("reflectionHashCode"); reflectionHashCode.arg(JExpr._this()); body._return(reflectionHashCode); hashCode.annotate(Override.class); } private void addEquals(JDefinedClass jclass) { JMethod equals = jclass.method(JMod.PUBLIC, boolean.class, "equals"); JVar otherObject = equals.param(Object.class, "other"); JBlock body = equals.body(); JInvocation reflectionEquals = jclass.owner().ref(EqualsBuilder.class).staticInvoke("reflectionEquals"); reflectionEquals.arg(JExpr._this()); reflectionEquals.arg(otherObject); body._return(reflectionEquals); equals.annotate(Override.class); } private String getClassName(String nodeName) { return capitalize(nodeName).replaceAll(ILLEGAL_CHARACTER_REGEX, "_"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy