com.googlecode.jsonschema2pojo.rules.AdditionalPropertiesRule Maven / Gradle / Ivy
/**
* 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 java.util.HashMap;
import java.util.Map;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.annotate.JsonAnyGetter;
import org.codehaus.jackson.annotate.JsonAnySetter;
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 http://tools.ietf.org/html/draft-zyp-json-schema-02#section-5.5
*/
public class AdditionalPropertiesRule implements SchemaRule {
private final RuleFactory ruleFactory;
protected AdditionalPropertiesRule(RuleFactory ruleFactory) {
this.ruleFactory = ruleFactory;
}
/**
* Applies this schema rule to take the required code generation steps.
*
* If additionalProperties is specified and set to the boolean value
* false
, this rule does not make any change to the generated
* Java type (the type does not allow additional properties).
*
* If the additionalProperties node is null
(not specified in
* the schema) or empty, then a new bean property named
* "additionalProperties", of type {@link Map} is added to
* the generated type (with appropriate accessors). The accessors are
* annotated to allow Jackson to marshal/unmarshal unrecognised (additional)
* properties found in JSON data from/to this map.
*
* 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.getBooleanValue() == 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");
setter.annotate(JsonAnySetter.class);
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");
getter.annotate(JsonAnyGetter.class);
getter.body()._return(JExpr._this().ref(field));
return getter;
}
}