/*
* Copyright 2013 cruxframework.org.
*
* 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 org.cruxframework.crux.core.rebind.rest;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.cruxframework.crux.core.client.bean.JsonEncoder;
import org.cruxframework.crux.core.client.collection.FastList;
import org.cruxframework.crux.core.client.collection.FastMap;
import org.cruxframework.crux.core.client.utils.EscapeUtils;
import org.cruxframework.crux.core.client.utils.JsUtils;
import org.cruxframework.crux.core.client.utils.StringUtils;
import org.cruxframework.crux.core.rebind.AbstractProxyCreator;
import org.cruxframework.crux.core.rebind.CruxGeneratorException;
import org.cruxframework.crux.core.rebind.context.RebindContext;
import org.cruxframework.crux.core.shared.json.annotations.JsonIgnore;
import org.cruxframework.crux.core.shared.json.annotations.JsonProperty;
import org.cruxframework.crux.core.shared.json.annotations.JsonSubTypes;
import org.cruxframework.crux.core.shared.json.annotations.JsonSubTypes.Type;
import org.cruxframework.crux.core.utils.JClassUtils;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.dev.generator.NameFactory;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNull;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
/**
* @author Thiago da Rosa de Bustamante
*
*/
public class JSonSerializerProxyCreator extends AbstractProxyCreator
{
private final JType targetObjectType;
private JClassType jsonEncoderType;
private JClassType listType;
private JClassType setType;
private JClassType mapType;
private JClassType javascriptObjectType;
private JClassType exceptionType;
private JClassType stringType;
private Set<String> referencedTypes = new HashSet<String>();
private static NameFactory nameFactory = new NameFactory();
public JSonSerializerProxyCreator(RebindContext context, JType targetObjectType)
{
this(context, targetObjectType, new HashSet<String>());
}
public JSonSerializerProxyCreator(RebindContext context, JType targetObjectType, Set<String> referencedTypes)
{
super(context, true);
registerReferencedType(targetObjectType, referencedTypes);
jsonEncoderType = context.getGeneratorContext().getTypeOracle().findType(JsonEncoder.class.getCanonicalName());
exceptionType = context.getGeneratorContext().getTypeOracle().findType(Exception.class.getCanonicalName());
listType = context.getGeneratorContext().getTypeOracle().findType(List.class.getCanonicalName());
setType = context.getGeneratorContext().getTypeOracle().findType(Set.class.getCanonicalName());
mapType = context.getGeneratorContext().getTypeOracle().findType(Map.class.getCanonicalName());
javascriptObjectType = context.getGeneratorContext().getTypeOracle().findType(JavaScriptObject.class.getCanonicalName());
stringType = context.getGeneratorContext().getTypeOracle().findType(String.class.getCanonicalName());
this.targetObjectType = targetObjectType;
}
private void registerReferencedType(JType targetObjectType,
Set<String> referencedTypes) {
if(targetObjectType.isClassOrInterface() != null && !JClassUtils.isSimpleType(targetObjectType))
{
referencedTypes.add(targetObjectType.getQualifiedSourceName());
}
this.referencedTypes = referencedTypes;
}
@Override
protected void generateProxyMethods(SourcePrinter srcWriter) throws CruxGeneratorException
{
generateEncodeMethod(srcWriter);
generateDecodeMethod(srcWriter);
}
@Override
public String getProxyQualifiedName()
{
return jsonEncoderType.getPackage().getName()+"."+getProxySimpleName();
}
@Override
public String getProxySimpleName()
{
String typeName = targetObjectType.getParameterizedQualifiedSourceName().replaceAll("\\W", "_");
return typeName+"_JsonEncoder";
}
@Override
protected SourcePrinter getSourcePrinter()
{
String packageName = jsonEncoderType.getPackage().getName();
PrintWriter printWriter = context.getGeneratorContext().tryCreate(context.getLogger(), packageName, getProxySimpleName());
if (printWriter == null)
{
return null;
}
ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, getProxySimpleName());
String[] imports = getImports();
for (String imp : imports)
{
composerFactory.addImport(imp);
}
return new SourceCodePrinter(composerFactory.createSourceWriter(context.getGeneratorContext(), printWriter), context.getLogger());
}
/**
* @return
*/
protected String[] getImports()
{
String[] imports = new String[] {
JSONParser.class.getCanonicalName(),
JSONValue.class.getCanonicalName(),
JSONObject.class.getCanonicalName(),
JSONArray.class.getCanonicalName(),
JSONNull.class.getCanonicalName(),
JSONNumber.class.getCanonicalName(),
JSONBoolean.class.getCanonicalName(),
JSONString.class.getCanonicalName(),
JsUtils.class.getCanonicalName(),
GWT.class.getCanonicalName()
};
return imports;
}
private void generateEncodeMethod(SourcePrinter srcWriter)
{
srcWriter.println("public JSONValue encode(" + targetObjectType.getParameterizedQualifiedSourceName() + " object){");
String encoded = generateEncodeObject(srcWriter, targetObjectType, "object");
srcWriter.println("return "+encoded+";");
srcWriter.println("}");
}
private void generateDecodeMethod(SourcePrinter srcWriter)
{
srcWriter.println("public " + targetObjectType.getParameterizedQualifiedSourceName() + " decode(JSONValue json){");
String decodedString = generateDecodeJsonValue(srcWriter, targetObjectType, "json");
srcWriter.println("return "+decodedString+";");
srcWriter.println("}");
}
private String generateDecodeJsonValue(SourcePrinter srcWriter, JType objectType, String jsonValueVar)
{
String resultObjectVar = nameFactory.createName("o");
String resultSourceName = objectType.getParameterizedQualifiedSourceName();
srcWriter.println(resultSourceName + " "+resultObjectVar + " = " + JClassUtils.getEmptyValueForType(objectType) +";");
srcWriter.println("if ("+jsonValueVar+" != null && "+jsonValueVar+".isNull() == null){");
JArrayType objectArrayType = objectType.isArray();
if (objectArrayType != null)
{
generateDecodeStringForArrayType(srcWriter, objectArrayType, jsonValueVar, resultObjectVar, resultSourceName);
}
else if(objectType.getQualifiedSourceName().equals(Void.class.getCanonicalName()))
{
srcWriter.println("return null;");
}
else if (JClassUtils.isSimpleType(objectType))
{
generateDecodeStringForJsonFriendlyType(srcWriter, objectType, jsonValueVar, resultObjectVar);
}
else
{
JClassType objectClassType = objectType.isClassOrInterface();
if (objectClassType == null)
{
throw new CruxGeneratorException("Type ["+objectType.getParameterizedQualifiedSourceName()+"] can not be deserialized by JsonEncoder. ");
}
if (objectClassType.isAssignableTo(javascriptObjectType))
{
srcWriter.println(resultObjectVar+" = ("+resultSourceName+")JsUtils.fromJSONValue("+jsonValueVar+");");
}
else if (isCollection(objectClassType))
{
generateDecodeStringForCollectionType(srcWriter, objectClassType, jsonValueVar, resultObjectVar, resultSourceName);
}
else
{
generateDecodeStringForCustomType(srcWriter, objectClassType, jsonValueVar, resultObjectVar, resultSourceName);
}
}
srcWriter.println("}");
return resultObjectVar;
}
private void generateDecodeStringForArrayType(SourcePrinter srcWriter, JArrayType objectArrayType, String jsonValueVar,
String resultObjectVar, String resultSourceName)
{
JType targetObjectType = objectArrayType.getComponentType();
String jsonCollectionVar = generateJSONValueCollectionForDecode(srcWriter, jsonValueVar, true);
srcWriter.println(resultObjectVar+" = new "+targetObjectType.getParameterizedQualifiedSourceName()+"["+jsonCollectionVar+".size()];");
String loopIndexVar = nameFactory.createName("i");
String loopJsonVar = nameFactory.createName("loopJsonVar");
srcWriter.println("for (int "+loopIndexVar+"=0; "+loopIndexVar+" < "+jsonCollectionVar+".size(); "+loopIndexVar+"++){");
srcWriter.println("JSONValue "+loopJsonVar+"="+jsonCollectionVar + ".get("+loopIndexVar+");");
String decodedJsonValue = generateDecodeJsonValue(srcWriter, targetObjectType, loopJsonVar);
srcWriter.println(resultObjectVar+"["+loopIndexVar+"] = "+decodedJsonValue+";");
srcWriter.println("}");
}
private String generateEncodeObject(SourcePrinter srcWriter, JType objectType, String objectVar)
{
String resultJSONValueVar = nameFactory.createName("json");
srcWriter.println("JSONValue "+resultJSONValueVar + " = JSONNull.getInstance();");
boolean isPrimitive = objectType.isPrimitive() != null;
if (!isPrimitive)
{
srcWriter.println("if ("+objectVar+" != null){");
}
JArrayType objectArrayType = objectType.isArray();
if (objectArrayType != null)
{
generateEncodeStringForArrayType(srcWriter, objectArrayType, objectVar, resultJSONValueVar);
}
else if (JClassUtils.isSimpleType(objectType))
{
generateEncodeStringForJsonFriendlyType(srcWriter, objectType, objectVar, resultJSONValueVar);
}
else
{
JClassType objectClassType = objectType.isClassOrInterface();
if (objectClassType == null)
{
throw new CruxGeneratorException("Type ["+objectType.getParameterizedQualifiedSourceName()+"] can not be serialized by JsonEncoder. ");
}
if (objectClassType.isAssignableTo(javascriptObjectType))
{
srcWriter.println(resultJSONValueVar+" = JsUtils.toJSONValue("+objectVar+");");
}
else if (isCollection(objectClassType))
{
generateEncodeStringForCollectionType(srcWriter, objectClassType, objectVar, resultJSONValueVar);
}
else
{
generateEncodeStringForCustomType(srcWriter, objectClassType, objectVar, resultJSONValueVar);
}
}
if (!isPrimitive)
{
srcWriter.println("}");
}
return resultJSONValueVar;
}
private void generateEncodeStringForArrayType(SourcePrinter srcWriter, JArrayType objectArrayType, String objectVar, String resultJSONValueVar)
{
JType targetObjectType = objectArrayType.getComponentType();
generateJSONValueCollectionForEncode(srcWriter, resultJSONValueVar, true);
String loopObjVar = nameFactory.createName("loopObjVar");
srcWriter.println("for ("+targetObjectType.getParameterizedQualifiedSourceName()+" "+loopObjVar+": "+objectVar+"){");
String encodedObjectVar = generateEncodeObject(srcWriter, targetObjectType, loopObjVar);
srcWriter.println(resultJSONValueVar+".isArray().set("+resultJSONValueVar+".isArray().size(), "+encodedObjectVar+");");
srcWriter.println("}");
}
private boolean isCollection(JClassType objectType)
{
if ((objectType.isAssignableTo(listType)) || (objectType.isAssignableTo(setType)) || (objectType.isAssignableTo(mapType))
|| (objectType.getQualifiedSourceName().equals(FastMap.class.getCanonicalName()))
|| (objectType.getQualifiedSourceName().equals(FastList.class.getCanonicalName())))
{
return true;
}
return false;
}
private void generateDecodeStringForJsonFriendlyType(SourcePrinter srcWriter, JType objectType, String jsonValueVar, String resultObjectVar)
{
try
{
if (objectType.getQualifiedSourceName().equals("java.lang.String") || objectType.isEnum() != null)
{
srcWriter.println(resultObjectVar + " = " + JClassUtils.getParsingExpressionForSimpleType(jsonValueVar+".isString().stringValue()", objectType) + ";");
} else if (objectType.getQualifiedSourceName().equals("java.sql.Date"))
{
context.getLogger().log(TreeLogger.Type.WARN, "We recommend to avoid type ["+objectType.getParameterizedQualifiedSourceName()+"]: "
+ "there are some known issues with respect to Jackson timezone handling, partly due to design of this class.");
srcWriter.println(resultObjectVar + " = " + JClassUtils.getParsingExpressionForSimpleType(jsonValueVar+".isString().stringValue().replace(\"/\",\"-\")", objectType) + ";");
} else
{
srcWriter.println(resultObjectVar + " = " + JClassUtils.getParsingExpressionForSimpleType(jsonValueVar+".toString()", objectType) + ";");
}
}
catch (NotFoundException e)
{
throw new CruxGeneratorException("Type ["+objectType.getParameterizedQualifiedSourceName()+"] can not be deserialized by JsonEncoder. " +
"Error Interpreting object type.", e);
}
}
private void generateEncodeStringForJsonFriendlyType(SourcePrinter srcWriter, JType objectType, String objectVar, String resultJSONValueVar)
{
if (objectType.getQualifiedSourceName().equals(String.class.getCanonicalName()))
{
srcWriter.println(resultJSONValueVar + " = new JSONString(" + objectVar + ");");
}
else if ((objectType == JPrimitiveType.BYTE) || (objectType.getQualifiedSourceName().equals(Byte.class.getCanonicalName()))
||(objectType == JPrimitiveType.SHORT) || (objectType.getQualifiedSourceName().equals(Short.class.getCanonicalName()))
||(objectType == JPrimitiveType.INT) || (objectType.getQualifiedSourceName().equals(Integer.class.getCanonicalName()))
||(objectType == JPrimitiveType.LONG) || (objectType.getQualifiedSourceName().equals(Long.class.getCanonicalName()))
||(objectType == JPrimitiveType.FLOAT) || (objectType.getQualifiedSourceName().equals(Float.class.getCanonicalName()))
||(objectType == JPrimitiveType.DOUBLE) || (objectType.getQualifiedSourceName().equals(Double.class.getCanonicalName())))
{
srcWriter.println(resultJSONValueVar + " = new JSONNumber(" + objectVar + ");");
}
else if (objectType.getQualifiedSourceName().equals(Date.class.getCanonicalName()))
{
srcWriter.println(resultJSONValueVar + " = new JSONNumber(" + objectVar + ".getTime());");
}
else if (objectType.getQualifiedSourceName().equals(java.sql.Date.class.getCanonicalName()))
{
srcWriter.println(resultJSONValueVar + " = new JSONNumber(" + objectVar + ".getTime());");
}
else if ((objectType == JPrimitiveType.BOOLEAN) || (objectType.getQualifiedSourceName().equals(Boolean.class.getCanonicalName())))
{
srcWriter.println(resultJSONValueVar + " = JSONBoolean.getInstance(" + objectVar + ");");
}
else if ((objectType == JPrimitiveType.CHAR) || (objectType.getQualifiedSourceName().equals(Character.class.getCanonicalName())))
{
srcWriter.println(resultJSONValueVar + " = new JSONString(\"\"+" + objectVar + ");");
}
else if (objectType.isEnum() != null)
{
srcWriter.println(resultJSONValueVar + " = new JSONString(" + objectVar + ".toString());");
}
else if (objectType.getQualifiedSourceName().equals(BigInteger.class.getCanonicalName())
|| objectType.getQualifiedSourceName().equals(BigDecimal.class.getCanonicalName()))
{
srcWriter.println(resultJSONValueVar + " = new JSONString(" + objectVar + ".toString());");
}
else
{
throw new CruxGeneratorException("Type ["+objectType.getParameterizedQualifiedSourceName()+"] can not be serialized by JsonEncoder. " +
"Error Interpreting object type.");
}
}
private void generateDecodeStringForCollectionType(SourcePrinter srcWriter, JClassType objectType, String jsonValueVar, String resultObjectVar, String resultSourceName)
{
boolean isList = (!objectType.isAssignableTo(mapType)) && (!objectType.getQualifiedSourceName().equals(FastMap.class.getCanonicalName()));
String jsonCollectionVar = generateJSONValueCollectionForDecode(srcWriter, jsonValueVar, isList);
JClassType targetObjectType = getCollectionTargetType(objectType);
generateCollectionInstantiation(srcWriter, objectType, resultObjectVar, resultSourceName, targetObjectType);
String serializerName = new JSonSerializerProxyCreator(context, targetObjectType, new HashSet<String>(referencedTypes)).create();
String serializerVar = nameFactory.createName("serializer");
srcWriter.println(serializerName+" "+serializerVar+" = new "+serializerName+"();");
if (isList)
{
srcWriter.println("for (int i=0; i < "+jsonCollectionVar+".size(); i++){");
srcWriter.println(resultObjectVar+".add("+serializerVar+".decode("+jsonCollectionVar + ".get(i)));");
srcWriter.println("}");
}
else
{
srcWriter.println("for (String key : "+jsonCollectionVar+".keySet()){");
srcWriter.println(resultObjectVar+".put(key, "+serializerVar+".decode("+jsonCollectionVar + ".get(key)));");
srcWriter.println("}");
}
}
private void generateCollectionInstantiation(SourcePrinter srcWriter, JClassType objectType,
String resultObjectVar, String resultSourceName,
JClassType targetObjectType)
{
if (objectType.getQualifiedSourceName().equals(FastList.class.getCanonicalName())
|| objectType.getQualifiedSourceName().equals(FastMap.class.getCanonicalName())
|| objectType.isInterface() == null)
{
srcWriter.println(resultObjectVar+" = new "+resultSourceName+"();");
}
else
{
if (objectType.isAssignableTo(listType))
{
srcWriter.println(resultObjectVar+" = new "+ArrayList.class.getCanonicalName()+"<"+targetObjectType.getParameterizedQualifiedSourceName()+">();");
}
else if (objectType.isAssignableTo(setType))
{
srcWriter.println(resultObjectVar+" = new "+HashSet.class.getCanonicalName()+"<"+targetObjectType.getParameterizedQualifiedSourceName()+">();");
}
else if (objectType.isAssignableTo(mapType))
{
JClassType keyObjectType = objectType.isParameterized().getTypeArgs()[0];
if (!keyObjectType.getQualifiedSourceName().equals("java.lang.String"))
{
throw new CruxGeneratorException("Type ["+objectType.getParameterizedQualifiedSourceName()+"] can not be deserialized by JsonEncoder. " +
"Map Key is invalid. Only Strings are accepted.");
}
srcWriter.println(resultObjectVar+" = new "+HashMap.class.getCanonicalName()+"<"+
keyObjectType.getParameterizedQualifiedSourceName()+","+targetObjectType.getParameterizedQualifiedSourceName()+">();");
}
else
{
throw new CruxGeneratorException("Type ["+objectType.getParameterizedQualifiedSourceName()+"] can not be deserialized by JsonEncoder. " +
"Invalid collection type.");
}
}
}
private String generateJSONValueCollectionForDecode(SourcePrinter srcWriter, String jsonValueVar, boolean isList)
{
String jsonCollectionVar;
if (isList)
{
jsonCollectionVar = nameFactory.createName("jsonArray");
srcWriter.println("JSONArray "+jsonCollectionVar+" = "+jsonValueVar+".isArray();");
}
else
{
jsonCollectionVar = nameFactory.createName("jsonMap");
srcWriter.println("JSONObject "+jsonCollectionVar+" = "+jsonValueVar+".isObject();");
}
return jsonCollectionVar;
}
private void generateEncodeStringForCollectionType(SourcePrinter srcWriter, JClassType objectType, String objectVar, String resultJSONValueVar)
{
boolean isList = (!objectType.isAssignableTo(mapType)) && (!objectType.getQualifiedSourceName().equals(FastMap.class.getCanonicalName()));
JClassType targetObjectType = getCollectionTargetType(objectType);
generateJSONValueCollectionForEncode(srcWriter, resultJSONValueVar, isList);
String serializerName = new JSonSerializerProxyCreator(context, targetObjectType, new HashSet<String>(referencedTypes)).create();
String serializerVar = nameFactory.createName("serializer");
srcWriter.println(serializerName+" "+serializerVar+" = new "+serializerName+"();");
if (isList)
{
srcWriter.println("for ("+targetObjectType.getParameterizedQualifiedSourceName()+" obj: "+objectVar+"){");
srcWriter.println(resultJSONValueVar+".isArray().set("+resultJSONValueVar+".isArray().size(), "+serializerVar+".encode(obj));");
srcWriter.println("}");
}
else
{
srcWriter.println("for (String key : "+objectVar+".keySet()){");
srcWriter.println(resultJSONValueVar+".isObject().put(key, "+serializerVar+".encode("+objectVar+".get(key)));");
srcWriter.println("}");
}
}
private void generateJSONValueCollectionForEncode(SourcePrinter srcWriter, String resultJSONValueVar, boolean isList)
{
if (isList)
{
srcWriter.println(resultJSONValueVar+" = new JSONArray();");
}
else
{
srcWriter.println(resultJSONValueVar+" = new JSONObject();");
}
}
private JClassType getCollectionTargetType(JClassType objectType)
{
JClassType targetObjectType;
if (objectType.getQualifiedSourceName().equals(FastList.class.getCanonicalName())
|| objectType.getQualifiedSourceName().equals(FastMap.class.getCanonicalName())
|| (objectType.isAssignableTo(listType))
|| (objectType.isAssignableTo(setType)))
{
targetObjectType = objectType.isParameterized().getTypeArgs()[0];
}
else if (objectType.isAssignableTo(mapType))
{
JClassType keyObjectType = objectType.isParameterized().getTypeArgs()[0];
if (!keyObjectType.getQualifiedSourceName().equals("java.lang.String"))
{
throw new CruxGeneratorException("Type ["+objectType.getParameterizedQualifiedSourceName()+"] can not be serialized by JsonEncoder. " +
"Map Key is invalid. Only Strings are accepted.");
}
targetObjectType = objectType.isParameterized().getTypeArgs()[1];
}
else
{
throw new CruxGeneratorException("Type ["+objectType.getParameterizedQualifiedSourceName()+"] can not be serialized by JsonEncoder. " +
"Invalid collection type.");
}
return targetObjectType;
}
private void generateDecodeStringForCustomType(SourcePrinter srcWriter, JClassType objectType, String jsonValueVar, String resultObjectVar, String resultSourceName)
{
JsonSubTypes jsonSubTypesClass = objectType.getAnnotation(JsonSubTypes.class);
boolean hasJsonSubTypes = jsonSubTypesClass != null && jsonSubTypesClass.value() != null;
if (hasJsonSubTypes)
{
boolean first = true;
for(Type innerObject : jsonSubTypesClass.value())
{
if (!first)
{
srcWriter.println("else ");
}
first = false;
srcWriter.println("if ("+StringUtils.class.getCanonicalName()+".unsafeEquals("+jsonValueVar+".isObject().get("+
EscapeUtils.quote(JsonSubTypes.SUB_TYPE_SELECTOR)+").isString().stringValue(),"+
EscapeUtils.quote(innerObject.value().getName())+")){");
JClassType innerClass = context.getGeneratorContext().getTypeOracle().findType(innerObject.value().getCanonicalName());
String serializerName = getSerializerForType(innerClass);
srcWriter.println(resultObjectVar+" = new "+serializerName+"().decode("+jsonValueVar+");");
srcWriter.println("}");
}
if (!first)
{
srcWriter.println("else ");
}
srcWriter.println("if ("+StringUtils.class.getCanonicalName()+".unsafeEquals("+jsonValueVar+".isObject().get("+
EscapeUtils.quote(JsonSubTypes.SUB_TYPE_SELECTOR)+").isString().stringValue(),"+
EscapeUtils.quote(objectType.getQualifiedSourceName())+")){");
srcWriter.println(resultObjectVar+" = GWT.create("+objectType.getQualifiedSourceName()+".class);");
}
String jsonObjectVar = nameFactory.createName("jsonObject");
srcWriter.println("JSONObject "+jsonObjectVar+" = "+jsonValueVar+".isObject();");
if (objectType.isAssignableTo(exceptionType) && objectType.findConstructor(new JType[]{stringType}) != null)
{
srcWriter.println("if ("+jsonObjectVar+".containsKey(\"message\")){");
srcWriter.println(resultObjectVar+" = new "+resultSourceName+"(("+jsonObjectVar+".get(\"message\") != null && "+jsonObjectVar+".get(\"message\").isString() != null) ? "+jsonObjectVar+".get(\"message\").isString().stringValue() : \"\");");
srcWriter.println("} else {");
srcWriter.println(resultObjectVar+" = GWT.create("+objectType.getQualifiedSourceName()+".class);");
srcWriter.println("}");
}
else
{
if(!hasJsonSubTypes)
{
srcWriter.println(resultObjectVar+" = GWT.create("+objectType.getQualifiedSourceName()+".class);");
}
}
List<JMethod> setterMethods = JClassUtils.getSetterMethods(objectType);
srcWriter.println("if ("+jsonObjectVar+" != null) {");
for (JMethod method : setterMethods)
{
if (method.getAnnotation(JsonIgnore.class) == null)
{
String property = null;
JsonProperty jsonProperty = method.getAnnotation(JsonProperty.class);
if (jsonProperty != null)
{
property = jsonProperty.value();
} else {
property = JClassUtils.getPropertyForGetterOrSetterMethod(method);
}
JType paramType = method.getParameterTypes()[0];
String serializerName = getSerializerForType(paramType);
srcWriter.println(resultObjectVar+"."+method.getName()+"(new "+serializerName+"().decode("+jsonObjectVar+".get("+EscapeUtils.quote(property)+")));");
}
}
if (hasJsonSubTypes)
{
srcWriter.println("}");
}
srcWriter.println("}");
}
private String getSerializerForType(JType paramType) {
HashSet<String> referencedTypesBackup = new HashSet<String>(referencedTypes);
//check cyclic reference and clear user types after the recursive call.
if(referencedTypes.contains(paramType.getQualifiedSourceName()))
{
context.getLogger().log(TreeLogger.Type.WARN, "Recursive reference found: " + referencedTypes.toString() + "-> please check for cyclic references in order to avoid infinite loops.");
}
//run nested evaluation.
String serializerName = new JSonSerializerProxyCreator(context, paramType, referencedTypes).create();
//revert processed list
this.referencedTypes = referencedTypesBackup;
return serializerName;
}
private void generateEncodeStringForCustomType(SourcePrinter srcWriter, JClassType objectType, String objectVar, String resultJSONValueVar)
{
JsonSubTypes jsonSubTypesClass = objectType.getAnnotation(JsonSubTypes.class);
boolean hasJsonSubTypes = jsonSubTypesClass != null && jsonSubTypesClass.value() != null;
if (hasJsonSubTypes)
{
boolean first = true;
for(Type innerObject : jsonSubTypesClass.value())
{
if (!first)
{
srcWriter.print("else ");
}
first = false;
srcWriter.println("if ("+StringUtils.class.getCanonicalName()+".unsafeEquals("+objectVar+".getClass().getName(),"+EscapeUtils.quote(innerObject.value().getName())+")){");
JClassType innerClass = context.getGeneratorContext().getTypeOracle().findType(innerObject.value().getCanonicalName());
String serializerName = getSerializerForType(innerClass);
srcWriter.println(resultJSONValueVar+" = new "+serializerName+"().encode(("+innerClass.getQualifiedSourceName()+")"+objectVar+");");
srcWriter.println("}");
}
if (!first)
{
srcWriter.print("else ");
}
srcWriter.println("if ("+StringUtils.class.getCanonicalName()+".unsafeEquals("+objectVar+".getClass().getName(),"+EscapeUtils.quote(objectType.getQualifiedSourceName())+")){");
srcWriter.println(resultJSONValueVar+" = new JSONObject();");
srcWriter.println("}");
srcWriter.println("if ("+resultJSONValueVar+" != null && !JSONNull.getInstance().equals("+resultJSONValueVar+")){");
srcWriter.println(resultJSONValueVar+".isObject().put("+EscapeUtils.quote(JsonSubTypes.SUB_TYPE_SELECTOR)+", new JSONString("+objectVar+".getClass().getName()));");
srcWriter.println("}");
}
if(!hasJsonSubTypes)
{
srcWriter.println(resultJSONValueVar+" = new JSONObject();");
}
srcWriter.println("if ("+resultJSONValueVar+" != null && !JSONNull.getInstance().equals("+resultJSONValueVar+")){");
generateEncodeStringForCustomTypeInnerProperties(srcWriter, objectType, objectVar, resultJSONValueVar);
srcWriter.println("}");
}
private void generateEncodeStringForCustomTypeInnerProperties(SourcePrinter srcWriter,
JClassType objectType, String objectVar, String resultJSONValueVar)
{
List<JMethod> getterMethods = JClassUtils.getGetterMethods(objectType);
for (JMethod method : getterMethods)
{
if (method.getAnnotation(JsonIgnore.class) == null)
{
String property = null;
JsonProperty jsonProperty = method.getAnnotation(JsonProperty.class);
if (jsonProperty != null)
{
property = jsonProperty.value();
} else {
property = JClassUtils.getPropertyForGetterOrSetterMethod(method);
}
JType returnType = method.getReturnType();
String serializerName = getSerializerForType(returnType);
boolean primitive = returnType.isPrimitive() != null;
if (!primitive)
{
srcWriter.println("if ("+objectVar+"."+method.getName()+"() != null){");
}
srcWriter.println(resultJSONValueVar+".isObject().put("+EscapeUtils.quote(property)+", new "+serializerName+"().encode("+objectVar+"."+method.getName()+"()));");
if (!primitive)
{
srcWriter.println("}");
}
}
}
}
}