com.googlecode.jsonschema2pojo.rules.AdditionalPropertiesRule.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.jsonschema2pojo.rules.AdditionalPropertiesRule.java

Source

/**
 * Copyright  2010-2013 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 java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.databind.JsonNode;
import com.googlecode.jsonschema2pojo.Schema;
import com.sun.codemodel.JClass;
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.JType;
import com.sun.codemodel.JVar;

/**
 * Applies the "additionalProperties" JSON schema rule.
 * 
 * @see <a
 *      href="http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.6">http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.6</a>
 */
public class AdditionalPropertiesRule implements Rule<JDefinedClass, JDefinedClass> {

    private final RuleFactory ruleFactory;

    protected AdditionalPropertiesRule(RuleFactory ruleFactory) {
        this.ruleFactory = ruleFactory;
    }

    /**
     * Applies this schema rule to take the required code generation steps.
     * <p>
     * If additionalProperties is specified and set to the boolean value
     * <code>false</code>, this rule does not make any change to the generated
     * Java type (the type does not allow additional properties).
     * <p>
     * If the additionalProperties node is <code>null</code> (not specified in
     * the schema) or empty, then a new bean property named
     * "additionalProperties", of type {@link Map}{@literal <String,Object>} is
     * added to the generated type (with appropriate accessors). The accessors
     * are annotated to allow unrecognised (additional) properties found in JSON
     * data to be marshalled/unmarshalled from/to this map.
     * <p>
     * If the additionalProperties node is present and specifies a schema, then
     * an "additionalProperties" map is added to the generated type. This time
     * the map values will be restricted and must be instances of a newly
     * generated Java type that will be created based on the
     * additionalProperties schema provided. If the schema does not specify the
     * javaType property, the name of the newly generated type will be derived
     * from the nodeName and the suffix 'Property'.
     * 
     * @param nodeName
     *            the name of the schema node for which the additionalProperties
     *            node applies
     * @param node
     *            the additionalProperties node itself, found in the schema (may
     *            be null if not specified in the schema)
     * @param jclass
     *            the Java type that is being generated to represent this schema
     * @return the given Java type jclass
     */
    @Override
    public JDefinedClass apply(String nodeName, JsonNode node, JDefinedClass jclass, Schema schema) {

        if (node != null && node.isBoolean() && node.asBoolean() == false) {
            // no additional properties allowed
            return jclass;
        }

        JType propertyType;
        if (node != null && node.size() != 0) {
            propertyType = ruleFactory.getSchemaRule().apply(nodeName + "Property", node, jclass, schema);
        } else {
            propertyType = jclass.owner().ref(Object.class);
        }

        JFieldVar field = addAdditionalPropertiesField(jclass, propertyType);

        addGetter(jclass, field);

        addSetter(jclass, propertyType, field);

        return jclass;
    }

    private JFieldVar addAdditionalPropertiesField(JDefinedClass jclass, JType propertyType) {
        JClass propertiesMapType = jclass.owner().ref(Map.class);
        propertiesMapType = propertiesMapType.narrow(jclass.owner().ref(String.class), propertyType.boxify());

        JClass propertiesMapImplType = jclass.owner().ref(HashMap.class);
        propertiesMapImplType = propertiesMapImplType.narrow(jclass.owner().ref(String.class),
                propertyType.boxify());

        JFieldVar field = jclass.field(JMod.PRIVATE, propertiesMapType, "additionalProperties");
        field.init(JExpr._new(propertiesMapImplType));

        return field;
    }

    private void addSetter(JDefinedClass jclass, JType propertyType, JFieldVar field) {
        JMethod setter = jclass.method(JMod.PUBLIC, void.class, "setAdditionalProperties");

        ruleFactory.getAnnotator().anySetter(setter);

        JVar nameParam = setter.param(String.class, "name");
        JVar valueParam = setter.param(propertyType, "value");

        JInvocation mapInvocation = setter.body().invoke(JExpr._this().ref(field), "put");
        mapInvocation.arg(nameParam);
        mapInvocation.arg(valueParam);
    }

    private JMethod addGetter(JDefinedClass jclass, JFieldVar field) {
        JMethod getter = jclass.method(JMod.PUBLIC, field.type(), "getAdditionalProperties");

        ruleFactory.getAnnotator().anyGetter(getter);

        getter.body()._return(JExpr._this().ref(field));
        return getter;
    }

}