Package org.jboss.errai.marshalling.rebind.api.impl.defaultjava

Source Code of org.jboss.errai.marshalling.rebind.api.impl.defaultjava.DefaultJavaMappingStrategy

/*
* 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;
  }
}
TOP

Related Classes of org.jboss.errai.marshalling.rebind.api.impl.defaultjava.DefaultJavaMappingStrategy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.