// Copyright 2013 Michel Kraemer // // 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 $pkg; import java.util.Arrays; import java.util.Map; <% if (!noJsonObject) { %> import java.util.Collection; import de.undercouch.citeproc.helper.json.JsonBuilder; import de.undercouch.citeproc.helper.json.JsonObject; <% } %> <% for (i in additionalImports) { %> import ${i}; <% } %> /** * $description * @author Michel Kraemer */ public class $name <% if (!noJsonObject) { %>implements JsonObject<% } %> { <% for (p in requiredProps) { %>private final ${p.type} ${p.normalizedName}; <% } %> <% for (p in props) { %>private final ${p.type} ${p.normalizedName}; <% } %> public $name(<% if (requiredProps.size > 1) { for (p in requiredProps[0..-2]) { %>${p.type} ${p.normalizedName},<% } } %><% if (!requiredProps.empty) { %> ${toEllipse.call(requiredProps[-1].type)} ${requiredProps[-1].normalizedName} <% } %>) { <% for (p in requiredProps) { %>this.${p.normalizedName} = ${p.normalizedName}; <% } %> <% for (p in props) { %>this.${p.normalizedName} = <% if (p.defval) { %>${p.defval}<% } else { %>null<% } %>; <% } %> } <% if (!props.empty) { %> public $name(<% for (p in requiredProps) { %>${p.type} ${p.normalizedName},<% } %> ${props.collect({ p -> p.type + ' ' + p.normalizedName }).join(',')}) { <% for (p in requiredProps) { %>this.${p.normalizedName} = ${p.normalizedName}; <% } %> <% for (p in props) { %>this.${p.normalizedName} = ${p.normalizedName}; <% } %> } <% } %> <% for (p in requiredProps) { %>/** * @return the <% if (shortname) { %>${shortname}'s <% } %>${p.name} */ public ${p.type} ${toGetter.call(p.normalizedName)}() { return ${p.normalizedName}; } <% } %> <% for (p in props) { %>/** * @return the <% if (shortname) { %>${shortname}'s <% } %>${p.name} */ public ${p.type} ${toGetter.call(p.normalizedName)}() { return ${p.normalizedName}; } <% } %> <% if (!noJsonObject) { %> @Override public Object toJson(JsonBuilder builder) { <% for (p in requiredProps) { %>builder.add("${p.name}", ${p.normalizedName});<% } %> <% for (p in props) { %>if (${p.normalizedName} != null) { builder.add("${p.name}", ${p.normalizedName}); } <% } %> return builder.build(); } /** * Converts a JSON object to a $name object. <% if (!requiredProps.empty) { %>The JSON object must at least contain the following required properties: ${requiredProps.collect({ p -> '<code>' + p.name + '</code>' }).join(',')}<% } %> * @param obj the JSON object to convert * @return the converted $name object */ @SuppressWarnings("unchecked") public static $name fromJson(Map<String, Object> obj) { <% for (p in requiredProps) { %>${p.type} ${p.normalizedName};<% } %> <% def castTemplate = { type, v -> def castBefore if (type.equals('String')) { castBefore = '' } else if (type.equals('int') || type.equals('Integer')) { castBefore = 'toInt(' } else if (type.equals('boolean') || type.equals('Boolean')) { castBefore = 'toBool(' } else { castBefore = '(' + type + ')' } def castAfter if (type.equals('String')) { castAfter = '.toString()' } else if (type.equals('int') || type.equals('Integer') || type.equals('boolean') || type.equals('Boolean')) { castAfter = ')' } else { castAfter = '' } return castBefore + v + castAfter } def fromJsonTemplate = { type, v -> return "${type}.fromJson((Map<String, Object>)$v)" } def constructArrayTemplate = { p -> def r = '' r += """\ if (v instanceof Map) { v = ((Map<?, ?>)v).values(); } else if (!(v instanceof Collection)) { throw new IllegalArgumentException("`${p.name}' must be an array"); } Collection<?> cv = (Collection<?>)v; ${p.normalizedName} = """ if (p.arrayArrayType) { r += "new ${p.typeNoArrayNoArray}[cv.size()][];" } else { r += "new ${p.typeNoArray}[cv.size()];" } r += """\ int i = 0; for (Object vo : cv) {""" if (p.arrayArrayType) { r += """\ if (vo instanceof Map) { vo = ((Map<?, ?>)vo).values(); } else if (!(vo instanceof Collection)) { throw new IllegalArgumentException("`${p.name}' must be an array of arrays"); } Collection<?> icv = (Collection<?>)vo; ${p.normalizedName}[i] = new ${p.typeNoArrayNoArray}[icv.size()]; int j = 0; for (Object ivo : icv) {""" if (p.cslType) { r += "${p.normalizedName}[i][j] = " + fromJsonTemplate(p.typeNoArrayNoArray, "ivo") + ";" } else { r += "${p.normalizedName}[i][j] = " + castTemplate(p.typeNoArrayNoArray, "ivo") + ";" } r += "++j;" r += "}" } else { if (p.cslType) { r += """\ if (!(vo instanceof Map)) { throw new IllegalArgumentException("`${p.name}' must be an array of objects"); } ${p.normalizedName}[i] = """ + fromJsonTemplate(p.typeNoArray, "vo") + ";" } else { r += "${p.normalizedName}[i] = " + castTemplate(p.typeNoArray, "vo") + ";" } } r += "++i;" r += "}" return r } def propertyTemplate = { p, v -> def r = '' if (!p.required) { r += "${p.type} ${p.normalizedName};" } if (p.enumType) { r += "${p.normalizedName} = ${p.type}.fromString(${v}.toString());" } else if (p.cslType) { if (p.arrayType) { r += constructArrayTemplate(p) } else { r += "if (!($v instanceof Map)) {" r += "\tthrow new IllegalArgumentException(\"`${p.name}' must be an object\");" r += '}' r += "${p.normalizedName} = " + fromJsonTemplate(p.type, v) + ';' } } else { if (p.arrayType) { r += constructArrayTemplate(p) } else { r += "${p.normalizedName} = " + castTemplate(p.type, v) + ';' } } if (!p.required) { r += "builder.${p.normalizedName}(${p.normalizedName});" } return r } %> <% for (p in requiredProps) { %>{ Object v = obj.get("${p.name}"); if (v == null) { throw new IllegalArgumentException("Missing property `${p.name}'"); } <% out << propertyTemplate(p, 'v') %> }<% } %> ${name}Builder builder = new ${name}Builder(${requiredProps.collect({ p -> p.normalizedName }).join(',')}); <% for (p in props) { %>{ Object v = obj.get("${p.name}"); if (<% if (p.enumType) { %>!isFalsy(v)<% } else { %>v != null<% } %>) { <% out << propertyTemplate(p, 'v') %> }<% if (p.defval) { %> else { builder.${p.normalizedName}(${p.defval}); } <% } %> }<% } %> ${additionalFromJsonCode.join('\n')} return builder.build(); } private static boolean isFalsy(Object o) { if (o == null) { return true; } if (Boolean.FALSE.equals(o)) { return true; } if ("".equals(o)) { return true; } if (Integer.valueOf(0).equals(o)) { return true; } if (Long.valueOf(0L).equals(o)) { return true; } if (o instanceof Float && (Float.valueOf(0f).equals(o) || ((Float)o).isNaN())) { return true; } if (o instanceof Double && (Double.valueOf(0d).equals(o) || ((Double)o).isNaN())) { return true; } if (Byte.valueOf((byte)0).equals(o)) { return true; } if (Short.valueOf((short)0).equals(o)) { return true; } return false; } private static int toInt(Object o) { if (o instanceof CharSequence) { return Integer.parseInt(o.toString()); } return ((Number)o).intValue(); } private static boolean toBool(Object o) { if (o instanceof String) { return Boolean.parseBoolean((String)o); } else if (o instanceof Number) { return ((Number)o).intValue() != 0; } return (Boolean)o; } <% } %> ${additionalMethods.join('\n')} @Override public int hashCode() { int result = 1; <% for (p in props) { %>result = 31 * result + <% if (p.arrayArrayType) { %>Arrays.deepHashCode(${p.normalizedName});<% } else if (p.arrayType) { %>Arrays.hashCode(${p.normalizedName});<% } else { %>((${p.normalizedName} == null) ? 0 : ${p.normalizedName}.hashCode());<% } %> <% } %> return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof $name)) return false; $name other = ($name) obj; <% for (p in props) { %> <% if (p.arrayArrayType) { %> if (!Arrays.deepEquals(${p.normalizedName}, other.${p.normalizedName})) return false; <% } else if (p.arrayType) { %> if (!Arrays.equals(${p.normalizedName}, other.${p.normalizedName})) return false; <% } else { %> if (${p.normalizedName} == null) { if (other.${p.normalizedName} != null) return false; } else if (!${p.normalizedName}.equals(other.${p.normalizedName})) return false; <% } %> <% } %> return true; } }