/*
* Copyright 2011 JBoss, by Red Hat, Inc
*
* 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.jboss.errai.marshalling.rebind.api.impl.defaultjava;
import static org.jboss.errai.codegen.meta.MetaClassFactory.parameterizedAs;
import static org.jboss.errai.codegen.meta.MetaClassFactory.typeParametersOf;
import static org.jboss.errai.codegen.util.Stmt.loadVariable;
import java.util.ArrayList;
import java.util.List;
import org.jboss.errai.codegen.Cast;
import org.jboss.errai.codegen.InnerClass;
import org.jboss.errai.codegen.Parameter;
import org.jboss.errai.codegen.Statement;
import org.jboss.errai.codegen.TernaryStatement;
import org.jboss.errai.codegen.builder.BlockBuilder;
import org.jboss.errai.codegen.builder.ClassDefinitionStaticOption;
import org.jboss.errai.codegen.builder.ClassStructureBuilder;
import org.jboss.errai.codegen.builder.ContextualStatementBuilder;
import org.jboss.errai.codegen.builder.ElseBlockBuilder;
import org.jboss.errai.codegen.builder.impl.ClassBuilder;
import org.jboss.errai.codegen.meta.MetaClass;
import org.jboss.errai.codegen.meta.MetaClassFactory;
import org.jboss.errai.codegen.meta.MetaClassMember;
import org.jboss.errai.codegen.meta.MetaConstructor;
import org.jboss.errai.codegen.meta.MetaField;
import org.jboss.errai.codegen.meta.MetaMethod;
import org.jboss.errai.codegen.meta.impl.build.BuildMetaClass;
import org.jboss.errai.codegen.util.Bool;
import org.jboss.errai.codegen.util.GenUtil;
import org.jboss.errai.codegen.util.If;
import org.jboss.errai.codegen.util.Implementations;
import org.jboss.errai.codegen.util.PrivateAccessUtil;
import org.jboss.errai.codegen.util.Refs;
import org.jboss.errai.codegen.util.Stmt;
import org.jboss.errai.common.client.protocols.SerializationParts;
import org.jboss.errai.marshalling.client.api.GeneratedMarshaller;
import org.jboss.errai.marshalling.client.api.MarshallingSession;
import org.jboss.errai.marshalling.client.api.exceptions.InvalidMappingException;
import org.jboss.errai.marshalling.client.api.exceptions.MarshallingException;
import org.jboss.errai.marshalling.client.api.exceptions.NoAvailableMarshallerException;
import org.jboss.errai.marshalling.client.api.json.EJObject;
import org.jboss.errai.marshalling.client.api.json.EJValue;
import org.jboss.errai.marshalling.client.marshallers.ObjectMarshaller;
import org.jboss.errai.marshalling.rebind.MarshallerGeneratorFactory;
import org.jboss.errai.marshalling.rebind.api.GeneratorMappingContext;
import org.jboss.errai.marshalling.rebind.api.MappingStrategy;
import org.jboss.errai.marshalling.rebind.api.ObjectMapper;
import org.jboss.errai.marshalling.rebind.api.model.ConstructorMapping;
import org.jboss.errai.marshalling.rebind.api.model.FactoryMapping;
import org.jboss.errai.marshalling.rebind.api.model.InstantiationMapping;
import org.jboss.errai.marshalling.rebind.api.model.Mapping;
import org.jboss.errai.marshalling.rebind.api.model.MappingDefinition;
import org.jboss.errai.marshalling.rebind.api.model.MemberMapping;
import org.jboss.errai.marshalling.rebind.util.MarshallingGenUtil;
/**
* The Errai default Java-to-JSON-to-Java marshaling strategy.
*
* @author Mike Brock <cbrock@redhat.com>
* @author Christian Sadilek <csadilek@redhat.com>
* @author Jonathan Fuerth <jfuerth@redhat.com>
*/
public class DefaultJavaMappingStrategy implements MappingStrategy {
private final GeneratorMappingContext context;
private final MetaClass toMap;
private final boolean gwtTarget;
public DefaultJavaMappingStrategy(final boolean gwtTarget,
final GeneratorMappingContext context,
final MetaClass toMap) {
this.gwtTarget = gwtTarget;
this.context = context;
this.toMap = toMap;
}
@Override
public ObjectMapper getMapper() {
return generateJavaBeanMapper();
}
private ObjectMapper generateJavaBeanMapper() {
final MappingDefinition mappingDefinition = context.getDefinitionsFactory().getDefinition(toMap);
if (mappingDefinition == null) {
throw new InvalidMappingException("no definition for: " + toMap.getFullyQualifiedName());
}
if ((toMap.isAbstract() || toMap.isInterface()) && !toMap.isEnum()) {
throw new RuntimeException("cannot map an abstract class or interface: " + toMap.getFullyQualifiedName());
}
return new ObjectMapper() {
@Override
public ClassStructureBuilder<?> getMarshaller(String marshallerClassName) {
ClassDefinitionStaticOption<?> staticOption = ClassBuilder.define(marshallerClassName).publicScope();
ClassStructureBuilder<?> classStructureBuilder = null;
BlockBuilder<?> initMethod = null;
if (!gwtTarget)
classStructureBuilder = staticOption.staticClass().implementsInterface(
parameterizedAs(GeneratedMarshaller.class, typeParametersOf(toMap))).body();
else {
classStructureBuilder = staticOption.implementsInterface(
parameterizedAs(GeneratedMarshaller.class, typeParametersOf(toMap))).body();
}
initMethod = classStructureBuilder.privateMethod(void.class, "lazyInit");
final MetaClass arrayType = toMap.asArrayOf(1);
classStructureBuilder.privateField("EMPTY_ARRAY", arrayType).initializesWith(Stmt.newArray(toMap, 0)).finish();
classStructureBuilder.publicMethod(arrayType, "getEmptyArray")
.append(Stmt.loadClassMember("EMPTY_ARRAY").returnValue())
.finish();
/**
*
* DEMARSHALL METHOD
*
*/
final BlockBuilder<?> builder =
classStructureBuilder.publicMethod(toMap, "demarshall",
Parameter.of(EJValue.class, "a0"), Parameter.of(MarshallingSession.class, "a1"));
builder.append(Stmt.loadVariable("this").invoke("lazyInit"));
builder.append(Stmt.declareVariable(EJObject.class).named("obj")
.initializeWith(loadVariable("a0").invoke("isObject")));
if (toMap.isEnum()) {
builder.append(Stmt.declareVariable(toMap).named("entity")
.initializeWith(demarshallEnum(loadVariable("obj"), loadVariable("a0"), toMap)));
}
else {
builder.append(If.cond(Bool.isNull(Refs.get("obj"))).append(Stmt.load(null).returnValue()).finish());
builder.append(Stmt.declareVariable(String.class).named("objId")
.initializeWith(loadVariable("obj")
.invoke("get", SerializationParts.OBJECT_ID)
.invoke("isString").invoke("stringValue")));
builder.append(
Stmt.if_(Bool.expr(loadVariable("a1").invoke("hasObject", loadVariable("objId"))))
.append(loadVariable("a1")
.invoke("getObject", toMap, loadVariable("objId")).returnValue()).finish());
final InstantiationMapping instantiationMapping = mappingDefinition.getInstantiationMapping();
/**
* Figure out how to construct this object.
*/
final Mapping[] cMappings = instantiationMapping.getMappings();
if (cMappings.length > 0) {
// use constructor mapping.
final List<String> memberKeys = new ArrayList<String>();
for (MemberMapping memberMapping : mappingDefinition.getMemberMappings()) {
memberKeys.add(memberMapping.getKey());
}
final Statement[] constructorParameters = new Statement[cMappings.length];
for (final Mapping mapping : instantiationMapping.getMappingsInKeyOrder(memberKeys)) {
int parmIndex = instantiationMapping.getIndex(mapping.getKey());
final MetaClass type = mapping.getType().asBoxed();
BlockBuilder<?> lazyInitMethod = (needsLazyInit(type)) ? initMethod : null;
if (type.isArray()) {
MetaClass toMap = type;
while (toMap.isArray()) {
toMap = toMap.getComponentType();
}
if (context.canMarshal(toMap.getFullyQualifiedName())) {
if (gwtTarget) {
BuildMetaClass arrayMarshaller = MarshallerGeneratorFactory.createArrayMarshallerClass(type);
if (!containsInnerClass(classStructureBuilder, arrayMarshaller)) {
classStructureBuilder.declaresInnerClass(new InnerClass(arrayMarshaller));
}
Statement deferred = context.getArrayMarshallerCallback().deferred(type, arrayMarshaller);
MarshallingGenUtil.ensureMarshallerFieldCreated(classStructureBuilder, toMap, type, lazyInitMethod,
deferred);
constructorParameters[parmIndex] =
Stmt.loadVariable(MarshallingGenUtil.getVarName(type)).invoke("demarshall",
extractJSONObjectProperty(mapping.getKey(), EJObject.class), Stmt.loadVariable("a1"));
}
else {
MarshallingGenUtil.ensureMarshallerFieldCreated(classStructureBuilder, toMap, type, lazyInitMethod);
constructorParameters[parmIndex] = context.getArrayMarshallerCallback()
.demarshall(type, extractJSONObjectProperty(mapping.getKey(), EJObject.class));
}
}
else {
throw new MarshallingException("Encountered non-marshallable type " + toMap +
" while building a marshaller for " + mappingDefinition.getMappingClass());
}
}
else {
MarshallingGenUtil.ensureMarshallerFieldCreated(classStructureBuilder, toMap, type, lazyInitMethod);
if (context.canMarshal(type.getFullyQualifiedName())) {
Statement s = maybeAddAssumedTypes(builder,
"c" + parmIndex,
mapping, fieldDemarshall(mapping, EJObject.class));
constructorParameters[parmIndex] = s;
}
else {
throw new MarshallingException("Encountered non-marshallable type " + type +
" while building a marshaller for " + mappingDefinition.getMappingClass());
}
}
}
if (instantiationMapping instanceof ConstructorMapping) {
final ConstructorMapping mapping = (ConstructorMapping) instantiationMapping;
final MetaConstructor constructor = mapping.getMember();
if (constructor.isPublic()) {
builder
.append(Stmt.declareVariable(toMap).named("entity")
.initializeWith(
Stmt.newObject(toMap, (Object[]) constructorParameters)));
}
else {
PrivateAccessUtil.addPrivateAccessStubs(gwtTarget ? "jsni" : "reflection", classStructureBuilder,
constructor);
builder.append(Stmt.declareVariable(toMap).named("entity")
.initializeWith(
Stmt.invokeStatic(
classStructureBuilder.getClassDefinition(),
PrivateAccessUtil.getPrivateMethodName(constructor),
(Object[]) constructorParameters)));
}
}
else if (instantiationMapping instanceof FactoryMapping) {
builder.append(Stmt.declareVariable(toMap).named("entity")
.initializeWith(
Stmt.invokeStatic(toMap, ((FactoryMapping) instantiationMapping).getMember().getName(),
(Object[]) constructorParameters)));
}
}
else {
// use default constructor
builder._(
Stmt.declareVariable(toMap).named("entity").initializeWith(
Stmt.nestedCall(Stmt.newObject(toMap))));
}
builder._(loadVariable("a1").invoke("recordObject",
loadVariable("objId"), loadVariable("entity")));
}
/**
*
* FIELD BINDINGS
*
*/
for (final MemberMapping memberMapping : mappingDefinition.getMemberMappings()) {
if (!memberMapping.canWrite())
continue;
if (memberMapping.getTargetType().isConcrete() && !context.isRendered(memberMapping.getTargetType())) {
context.getMarshallerGeneratorFactory().addMarshaller(memberMapping.getTargetType());
}
final Statement bindingStatement;
final Statement val;
context.getMarshallerGeneratorFactory().addOrMarkMarshallerUnlazy(
memberMapping.getType().getOuterComponentType());
BlockBuilder<?> lazyInitMethod = (needsLazyInit(memberMapping.getType())) ? initMethod : null;
if (memberMapping.getType().isArray()) {
if (gwtTarget) {
BuildMetaClass arrayMarshaller =
MarshallerGeneratorFactory.createArrayMarshallerClass(memberMapping.getType().asBoxed());
if (!containsInnerClass(classStructureBuilder, arrayMarshaller)) {
classStructureBuilder.declaresInnerClass(new InnerClass(arrayMarshaller));
}
Statement deferred =
context.getArrayMarshallerCallback().deferred(memberMapping.getType().asBoxed(), arrayMarshaller);
MarshallingGenUtil.ensureMarshallerFieldCreated(classStructureBuilder, toMap, memberMapping.getType()
.asBoxed(), lazyInitMethod, deferred);
}
else {
MarshallingGenUtil.ensureMarshallerFieldCreated(classStructureBuilder, toMap, memberMapping.getType()
.asBoxed(), lazyInitMethod);
}
val =
context.getArrayMarshallerCallback()
.demarshall(memberMapping.getType(),
extractJSONObjectProperty(memberMapping.getKey(), EJObject.class));
}
else {
MarshallingGenUtil.ensureMarshallerFieldCreated(classStructureBuilder, toMap, memberMapping.getType()
.asBoxed(), lazyInitMethod);
val = fieldDemarshall(memberMapping, MetaClassFactory.get(EJObject.class));
}
if (memberMapping.getBindingMember() instanceof MetaField) {
final MetaField field = (MetaField) memberMapping.getBindingMember();
// handle long case -- GWT does not support long in JSNI
if (field.isPublic()) {
builder.append(loadVariable("entity").loadField(field.getName()).assignValue(val));
continue;
}
else {
final MetaMethod setterMeth = GenUtil.findCaseInsensitiveMatch(null,
field.getDeclaringClass(), "set" + field.getName(),
field.getType());
if (setterMeth != null && !setterMeth.isPrivate()) {
// Bind via setter
bindingStatement =
loadVariable("entity").invoke(setterMeth, Cast.to(memberMapping.getTargetType(), val));
}
else if (field.getType().getCanonicalName().equals("long")) {
throw new RuntimeException("cannot support private field marshalling of long type" +
" (not supported by JSNI) for field: "
+ field.getDeclaringClass().getFullyQualifiedName() + "#" + field.getName());
}
else {
if (!context.isExposed(field, classStructureBuilder.getClassDefinition().getName())) {
PrivateAccessUtil.addPrivateAccessStubs(gwtTarget ? "jsni" : "reflection", classStructureBuilder,
field);
context.markExposed(field, classStructureBuilder.getClassDefinition().getName());
}
// Bind via JSNI
bindingStatement = Stmt.invokeStatic(classStructureBuilder.getClassDefinition(),
PrivateAccessUtil.getPrivateFieldInjectorName(field),
loadVariable("entity"), val);
}
}
}
else if (memberMapping.getBindingMember() instanceof MetaMethod) {
bindingStatement = loadVariable("entity").invoke(((MetaMethod) memberMapping.getBindingMember()),
Cast.to(memberMapping.getTargetType(), val));
}
else {
throw new RuntimeException("unknown member mapping type: " + memberMapping.getType());
}
final BlockBuilder<ElseBlockBuilder> ifBlockBuilder = Stmt.if_(Bool.and(
Bool.expr(loadVariable("obj").invoke("containsKey", memberMapping.getKey())),
Bool.notExpr(loadVariable("obj").invoke("get", memberMapping.getKey()).invoke("isNull"))));
maybeAddAssumedTypes(ifBlockBuilder, null, memberMapping, bindingStatement);
builder.append(ifBlockBuilder.finish());
}
builder.append(loadVariable("entity").returnValue());
builder.finish();
/**
*
* MARSHAL METHOD
*
*/
final BlockBuilder<?> marshallMethodBlock = classStructureBuilder.publicMethod(String.class, "marshall",
Parameter.of(toMap, "a0"), Parameter.of(MarshallingSession.class, "a1"));
marshallMethodBlock.append(Stmt.loadVariable("this").invoke("lazyInit"));
marshallToJSON(marshallMethodBlock, toMap, mappingDefinition, classStructureBuilder, initMethod);
marshallMethodBlock.finish();
if (initMethod != null) {
initMethod.finish();
}
return classStructureBuilder;
}
};
}
public Statement maybeAddAssumedTypes(BlockBuilder<?> blockBuilder, String varName, Mapping mapping,
Statement statement) {
final MetaClass elementType = MarshallingGenUtil.getConcreteCollectionElementType(mapping.getType());
final MetaClass mapKeyType = MarshallingGenUtil.getConcreteMapKeyType(mapping.getType());
final MetaClass mapValueType = MarshallingGenUtil.getConcreteMapValueType(mapping.getType());
boolean assumedMapTypesSet = false;
if (elementType != null) {
blockBuilder.append(Stmt.loadVariable("a1").invoke("setAssumedElementType", elementType.getFullyQualifiedName()));
}
else if (mapKeyType != null && mapValueType != null) {
blockBuilder.append(Stmt.loadVariable("a1").invoke("setAssumedMapKeyType", mapKeyType.getFullyQualifiedName()));
blockBuilder.append(Stmt.loadVariable("a1")
.invoke("setAssumedMapValueType", mapValueType.getFullyQualifiedName()));
assumedMapTypesSet = true;
}
if (varName != null) {
blockBuilder.append(Stmt.declareFinalVariable(varName, mapping.getTargetType(), statement));
}
else {
blockBuilder.append(statement);
}
if (assumedMapTypesSet) {
blockBuilder.append(Stmt.loadVariable("a1").invoke("resetAssumedTypes"));
}
return (varName != null) ? Stmt.loadVariable(varName) : statement;
}
public Statement fieldDemarshall(final Mapping mapping, final Class<?> fromType) {
return fieldDemarshall(mapping, MetaClassFactory.get(fromType));
}
public Statement fieldDemarshall(final Mapping mapping, final MetaClass fromType) {
final Statement statement =
unwrapJSON(extractJSONObjectProperty(mapping.getKey(), fromType), mapping.getType(), mapping.getTargetType());
return Cast.to(mapping.getTargetType(), statement);
}
public Statement extractJSONObjectProperty(final String fieldName, final Class fromType) {
return extractJSONObjectProperty(fieldName, MetaClassFactory.get(fromType));
}
public Statement extractJSONObjectProperty(final String fieldName, final MetaClass fromType) {
if (fromType.getFullyQualifiedName().equals(EJObject.class.getName())) {
return loadVariable("obj").invoke("get", fieldName);
}
else {
return Stmt.nestedCall(Cast.to(fromType, loadVariable("a0"))).invoke("get", fieldName);
}
}
private int calcBufferSize(final List<MappingDefinition> stack,
final MappingDefinition definition) {
int bufSize = 128;
if (!stack.contains(definition)) {
stack.add(definition);
for (final MemberMapping mapping : definition.getMemberMappings()) {
MappingDefinition def = context.getDefinitionsFactory().getDefinition(mapping.getType());
if (def == null) {
if (mapping.getType().isArray()) {
def = context.getDefinitionsFactory().getDefinition(mapping.getType().getOuterComponentType().asBoxed());
// def could still be null in the case where the array component type is abstract or an
// interface
if (def != null) {
bufSize += (calcBufferSize(stack, def)) * 4;
}
}
continue;
}
bufSize += calcBufferSize(stack, def);
}
}
return bufSize;
}
public void marshallToJSON(final BlockBuilder<?> builder,
final MetaClass toType,
final MappingDefinition definition,
final ClassStructureBuilder classStructureBuilder,
final BlockBuilder<?> initMethod) {
if (!context.canMarshal(toType.getFullyQualifiedName())) {
throw new NoAvailableMarshallerException(toType.getName());
}
builder.append(
If.isNull(loadVariable("a0"))
.append(Stmt.load("null").returnValue()).finish()
);
final int bufSize = calcBufferSize(new ArrayList<MappingDefinition>(), definition);
if (toMap.isEnum()) {
builder.append(
Stmt.declareFinalVariable(
"json",
StringBuilder.class,
Stmt.newObject(StringBuilder.class)
)
);
final ContextualStatementBuilder csb = Stmt.loadVariable("json");
marshallEnum(csb, Stmt.loadVariable("a0"), toMap);
builder.append(csb.invoke("toString").returnValue());
return;
}
builder.append(Stmt.declareFinalVariable("ref", boolean.class,
Stmt.loadVariable("a1").invoke("hasObject", Refs.get("a0"))));
builder.append(
Stmt.declareFinalVariable(
"json",
StringBuilder.class,
Stmt.newObject(StringBuilder.class,
"{" + keyValue(SerializationParts.ENCODED_TYPE, string(toType.getFullyQualifiedName())) + ",\"" +
SerializationParts.OBJECT_ID + "\"")
)
);
builder.append(Stmt.loadVariable("json")
.invoke("append", ":\"")
.invoke("append", loadVariable("a1").invoke("getObject", Stmt.loadVariable("a0")))
.invoke("append", "\"")
);
builder.append(
If.cond(loadVariable("ref"))
.append(Stmt.loadVariable("json").invoke("append", "}").invoke("toString").returnValue())
.finish());
boolean hasEncoded = false;
ContextualStatementBuilder appendChain = null;
int i = 0;
for (final MemberMapping mapping : definition.getMemberMappings()) {
if (!mapping.canRead()) {
continue;
}
BlockBuilder<?> lazyInitMethod = (needsLazyInit(mapping.getType())) ? initMethod : null;
MarshallingGenUtil.ensureMarshallerFieldCreated(classStructureBuilder, toMap, mapping.getType()
.asBoxed(), lazyInitMethod);
if (!hasEncoded) {
appendChain = Stmt.loadVariable("json").invoke("append", ",");
hasEncoded = true;
}
else if (i > 0) {
appendChain.invoke("append", ",");
}
final MetaClass targetType = GenUtil.getPrimitiveWrapper(mapping.getType());
final MetaClass compType =
targetType.isArray() ? targetType.getOuterComponentType().asBoxed() : targetType.asBoxed();
if (!(compType.isAbstract() || compType.isInterface() || compType.isEnum())
&& !context.canMarshal(compType.getFullyQualifiedName())) {
throw new NoAvailableMarshallerException(compType.getFullyQualifiedName());
}
Statement valueStatement = valueAccessorFor(mapping.getReadingMember(), classStructureBuilder);
if (targetType.isArray()) {
valueStatement = context.getArrayMarshallerCallback().marshal(targetType, valueStatement);
}
appendChain.invoke("append", "\"" + mapping.getKey() + "\":");
if (targetType.isEnum()) {
marshallEnum(appendChain, valueStatement, targetType);
}
else {
appendChain.invoke("append",
loadVariable(MarshallingGenUtil.getVarName(targetType))
.invoke("marshall", valueStatement, loadVariable("a1")));
}
i++;
}
if (i == 0) {
if (appendChain == null) {
appendChain = Stmt.loadVariable("json");
}
appendChain.invoke("append", ",\"" + SerializationParts.INSTANTIATE_ONLY + "\":true");
}
builder.append(appendChain.invoke("append", "}").invoke("toString").returnValue());
}
private static String keyValue(final String key, final String value) {
return "\"" + key + "\":" + value + "";
}
private static String string(final String value) {
return "\"" + value + "\"";
}
public Statement valueAccessorFor(final MetaClassMember member, ClassStructureBuilder<?> classStructureBuilder) {
if (member instanceof MetaField) {
final MetaField field = (MetaField) member;
if (!field.isPublic()) {
final MetaMethod getterMethod = GenUtil.findCaseInsensitiveMatch(field.getType(),
field.getDeclaringClass(), "get" + field.getName());
if (getterMethod != null) {
return loadVariable("a0").invoke(getterMethod);
}
else {
if (!context.isExposed(field, classStructureBuilder.getClassDefinition().getName())) {
PrivateAccessUtil.addPrivateAccessStubs(gwtTarget ? "jsni" : "reflection", classStructureBuilder, field);
context.markExposed(field, classStructureBuilder.getClassDefinition().getName());
}
return Stmt.invokeStatic(classStructureBuilder.getClassDefinition(), PrivateAccessUtil
.getPrivateFieldInjectorName(field),
loadVariable("a0"));
}
}
else {
return loadVariable("a0").loadField(field.getName());
}
}
else {
final MetaMethod method = (MetaMethod) member;
if (!method.isPublic()) {
if (!context.isExposed(method, classStructureBuilder.getClassDefinition().getName())) {
PrivateAccessUtil.addPrivateAccessStubs(gwtTarget ? "jsni" : "reflection", classStructureBuilder, method);
context.markExposed(method, classStructureBuilder.getClassDefinition().getName());
}
return Stmt.invokeStatic(classStructureBuilder.getClassDefinition(),
PrivateAccessUtil.getPrivateMethodName(method), loadVariable("a0"));
}
else {
return loadVariable("a0").invoke(method);
}
}
}
public Statement demarshallEnum(final Statement objStatement,
final Statement valStatement,
final MetaClass toType) {
final Statement trueStatement = Stmt.invokeStatic(Enum.class, "valueOf", toType,
Stmt.nestedCall(objStatement)
.invoke("get", SerializationParts.ENUM_STRING_VALUE).invoke("isString").invoke("stringValue"));
final Statement falseStatement =
(valStatement != null) ?
new TernaryStatement(Bool.isNotNull(Stmt.nestedCall(valStatement).invoke("isString")),
Stmt.invokeStatic(Enum.class, "valueOf", toType,
Stmt.nestedCall(valStatement).invoke("isString").invoke("stringValue")),
Stmt.load(null))
: Stmt.load(null);
return new TernaryStatement(Bool.isNotNull(objStatement), trueStatement, falseStatement);
}
public void marshallEnum(final ContextualStatementBuilder bb,
final Statement valueStatement,
final MetaClass toType) {
final Implementations.StringBuilderBuilder internalSBB = Implementations.newStringBuilder()
.append("{\"" + SerializationParts.ENCODED_TYPE
+ "\":\"" + toType.getFullyQualifiedName() + "\",\"" + SerializationParts.ENUM_STRING_VALUE + "\":\"")
.append(Stmt.nestedCall(valueStatement).invoke("name")).append("\"}");
final TernaryStatement ternaryStatement = new TernaryStatement(
Bool.isNotNull(valueStatement), internalSBB, Stmt.load("null"));
bb.invoke("append", ternaryStatement);
}
public Statement unwrapJSON(final Statement valueStatement, final MetaClass toType, final MetaClass targetType) {
if (toType.isEnum()) {
return demarshallEnum(Stmt.nestedCall(valueStatement).invoke("isObject"), valueStatement, toType);
}
else {
final String varName = MarshallingGenUtil.getVarName(toType);
if (toType.equals(MetaClassFactory.get(Object.class))) {
return Stmt.castTo(ObjectMarshaller.class, Stmt.loadVariable(varName))
.invoke("demarshall", targetType.asClass(), valueStatement, loadVariable("a1"));
}
return Stmt.loadVariable(varName)
.invoke("demarshall", valueStatement, loadVariable("a1"));
}
}
private boolean needsLazyInit(MetaClass type) {
MetaClass compType = type.getOuterComponentType().getErased();
return (!compType.asUnboxed().isPrimitive() && !compType.equals(MetaClassFactory.get(String.class)) && !context
.getDefinitionsFactory().hasBuiltInDefinition(compType));
}
private boolean containsInnerClass(ClassStructureBuilder<?> classStructureBuilder, BuildMetaClass inner) {
MetaClass[] innerClasses = classStructureBuilder.getClassDefinition().getDeclaredClasses();
for (MetaClass innerClass : innerClasses) {
if(innerClass.getFullyQualifiedName().equals(inner.getFullyQualifiedName())) {
return true;
}
}
return false;
}
}