}
return new ObjectMapper() {
@Override
public Statement getMarshaller() {
final AnonymousClassStructureBuilder classStructureBuilder = Stmt.create(context.getCodegenContext())
.newObject(parameterizedAs(Marshaller.class, typeParametersOf(toMap))).extend();
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();
classStructureBuilder.publicOverridesMethod("getTypeHandled")
.append(Stmt.load(toMap).returnValue())
.finish();
/**
*
* DEMARSHALL METHOD
*
*/
final BlockBuilder<?> builder =
classStructureBuilder.publicOverridesMethod("demarshall",
Parameter.of(EJValue.class, "a0"), Parameter.of(MarshallingSession.class, "a1"));
final BlockBuilder<CatchBlockBuilder> tryBuilder = Stmt.try_();
tryBuilder.append(Stmt.if_(Bool.expr(Stmt.loadVariable("a0").invoke("isNull")))
.append(Stmt.load(null).returnValue()).finish());
tryBuilder.append(Stmt.declareVariable(EJObject.class).named("obj")
.initializeWith(loadVariable("a0").invoke("isObject")));
if (toMap.isEnum()) {
tryBuilder.append(Stmt.declareVariable(toMap).named("entity")
.initializeWith(demarshallEnum(loadVariable("obj"), loadVariable("a0"), toMap)));
}
else {
tryBuilder.append(Stmt.declareVariable(String.class).named("objId")
.initializeWith(loadVariable("obj")
.invoke("get", SerializationParts.OBJECT_ID)
.invoke("isString").invoke("stringValue")));
tryBuilder.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<Statement> constructorParameters = new ArrayList<Statement>();
for (final Mapping mapping : mappingDefinition.getInstantiationMapping().getMappings()) {
final MetaClass type = mapping.getType().asBoxed();
if (type.isArray()) {
MetaClass toMap = type;
while (toMap.isArray()) {
toMap = toMap.getComponentType();
}
if (context.canMarshal(toMap.getFullyQualifiedName())) {
constructorParameters.add(context.getArrayMarshallerCallback()
.demarshall(type, extractJSONObjectProperty(mapping.getKey(), EJObject.class)));
}
else {
throw new MarshallingException("no marshaller for type: " + toMap);
}
}
else {
if (context.canMarshal(type.getFullyQualifiedName())) {
Statement s = maybeAddAssumedTypes(tryBuilder, "c" + constructorParameters.size(),
mapping, fieldDemarshall(mapping, EJObject.class));
constructorParameters.add(s);
}
else {
throw new MarshallingException("no marshaller for type: " + type);
}
}
}
if (instantiationMapping instanceof ConstructorMapping) {
final ConstructorMapping mapping = (ConstructorMapping) instantiationMapping;
final MetaConstructor constructor = mapping.getMember();
if (constructor.isPublic()) {
tryBuilder.append(Stmt.declareVariable(toMap).named("entity")
.initializeWith(Stmt.newObject(toMap, constructorParameters.toArray(new Object[constructorParameters.size()]))));
}
else {
PrivateAccessUtil.addPrivateAccessStubs(gwtTarget ? "jsni" : "reflection", context.getClassStructureBuilder(), constructor);
tryBuilder.append(Stmt.declareVariable(toMap).named("entity")
.initializeWith(
Stmt.invokeStatic(
context.getClassStructureBuilder().getClassDefinition(),
PrivateAccessUtil.getPrivateMethodName(constructor),
constructorParameters.toArray(new Object[constructorParameters.size()]))));
}
}
else if (instantiationMapping instanceof FactoryMapping) {
tryBuilder.append(Stmt.declareVariable(toMap).named("entity")
.initializeWith(
Stmt.invokeStatic(toMap, ((FactoryMapping) instantiationMapping).getMember().getName(),
constructorParameters.toArray(new Object[constructorParameters.size()]))));
}
}
else {
// use default constructor
tryBuilder._(
Stmt.declareVariable(toMap).named("entity").initializeWith(
Stmt.nestedCall(Stmt.newObject(toMap))));
}
tryBuilder._(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;
if (memberMapping.getType().isArray()) {
val =
context.getArrayMarshallerCallback()
.demarshall(memberMapping.getType(),
extractJSONObjectProperty(memberMapping.getKey(), EJObject.class));
}
else {
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()) {
tryBuilder.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)) {
PrivateAccessUtil.addPrivateAccessStubs(gwtTarget ? "jsni" : "reflection", context.getClassStructureBuilder(), field);
context.markExposed(field);
}
// Bind via JSNI
bindingStatement = Stmt.invokeStatic(context.getGeneratedBootstrapClass(),
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);
tryBuilder.append(ifBlockBuilder.finish());
}
tryBuilder.append(loadVariable("entity").returnValue());
tryBuilder.finish()
.catch_(Throwable.class, "t")
.append(loadVariable("t").invoke("printStackTrace"))
.append(Stmt.throw_(RuntimeException.class,
"error demarshalling entity: " + toMap.getFullyQualifiedName(), loadVariable("t")))
.finish();
builder.append(tryBuilder.finish()).finish();
/**
*
* MARSHAL METHOD
*
*/
final BlockBuilder<?> marshallMethodBlock = classStructureBuilder.publicOverridesMethod("marshall",
Parameter.of(toMap, "a0"), Parameter.of(MarshallingSession.class, "a1"));
marshallToJSON(marshallMethodBlock, toMap, mappingDefinition);
marshallMethodBlock.finish();
return classStructureBuilder.finish();
}
};
}