Package org.jboss.errai.marshalling.server.marshallers

Source Code of org.jboss.errai.marshalling.server.marshallers.DefaultDefinitionMarshaller

/*
* 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.server.marshallers;

import org.jboss.errai.codegen.meta.MetaField;
import org.jboss.errai.codegen.meta.MetaMethod;
import org.jboss.errai.common.client.protocols.SerializationParts;
import org.jboss.errai.marshalling.client.api.Marshaller;
import org.jboss.errai.marshalling.client.api.MarshallingSession;
import org.jboss.errai.marshalling.client.api.exceptions.MarshallingException;
import org.jboss.errai.marshalling.client.api.json.EJObject;
import org.jboss.errai.marshalling.client.api.json.EJValue;
import org.jboss.errai.marshalling.client.util.NumbersUtils;
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.server.EncodingSession;
import org.jboss.errai.marshalling.server.MappingContextSingleton;
import org.jboss.errai.marshalling.server.api.ServerMarshaller;
import org.mvel2.DataConversion;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
* @author Mike Brock
*/
public class DefaultDefinitionMarshaller implements ServerMarshaller<Object> {

  private MappingDefinition definition;

  public DefaultDefinitionMarshaller(MappingDefinition definition) {
    this.definition = definition;
  }

  public static void setProperty(Object i, Field f, Object v) {
    try {
      f.setAccessible(true);
      f.set(i, DataConversion.convert(v, f.getType()));
    }
    catch (Exception e) {
      throw new RuntimeException("could not set field (inst=" + i + "; field=" + f + "; val=" + v + ")", e);
    }
  }

  @Override
  public Class<Object> getTypeHandled() {
    return (Class<Object>) definition.getMappingClass().asClass();
  }

  @Override
  public Object demarshall(EJValue o, MarshallingSession ctx) {
    try {
      if (o.isObject() != null) {
        EJObject oMap = o.isObject();

        Object newInstance;
        if (oMap.containsKey(SerializationParts.OBJECT_ID)) {
          if (oMap.containsKey(SerializationParts.NUMERIC_VALUE)) {
            return NumbersUtils.getNumber(oMap.get(SerializationParts.ENCODED_TYPE).isString().stringValue(),
                    oMap.get(SerializationParts.NUMERIC_VALUE));
          }

          if (oMap.containsKey(SerializationParts.OBJECT_ID)) {
            String hash = oMap.get(SerializationParts.OBJECT_ID).isString().stringValue();

            if (ctx.hasObjectHash(hash)) {
              newInstance = ctx.getObject(Object.class, hash);

              /**
               * If this only contains 2 fields, it is only a graph reference.
               */
              if (oMap.size() == 2) {
                return newInstance;
              }
            }
            else {
              if (oMap.containsKey(SerializationParts.INSTANTIATE_ONLY)) {
                newInstance = getTypeHandled().newInstance();
                ctx.recordObjectHash(hash, newInstance);
                return newInstance;
              }

              InstantiationMapping cMapping = definition.getInstantiationMapping();

              Object[] parms = new Object[cMapping.getMappings().length];
              Class[] targetTypes = cMapping.getSignature();

              int i = 0;
              for (Mapping mapping : cMapping.getMappings()) {
                Marshaller<Object> marshaller = ctx.getMarshallerInstance(mapping.getType().getFullyQualifiedName());
                parms[i] = DataConversion.convert(
                        marshaller.demarshall(oMap.get(mapping.getKey()), ctx), targetTypes[i++]);
              }

              if (cMapping instanceof ConstructorMapping) {
                newInstance = ((ConstructorMapping) cMapping).getMember().asConstructor().newInstance(parms);
              }
              else {
                newInstance = ((FactoryMapping) cMapping).getMember().asMethod().invoke(null, parms);
              }

              ctx.recordObjectHash(hash, newInstance);
            }

            for (MemberMapping mapping : definition.getWritableMemberMappings()) {
              Marshaller<Object> marshaller = ctx.getMarshallerInstance(mapping.getType().getFullyQualifiedName());

              if (mapping.getBindingMember() instanceof MetaField) {
                MetaField f = (MetaField) mapping.getBindingMember();

                setProperty(newInstance, f.asField(),
                        marshaller.demarshall(oMap.get(mapping.getKey()), ctx));
              }
              else {
                Method m = ((MetaMethod) mapping.getBindingMember()).asMethod();
                m.invoke(newInstance, DataConversion.convert(
                        marshaller.demarshall(oMap.get(mapping.getKey()), ctx),
                        m.getParameterTypes()[0]));
              }
            }
          }
          else {
            throw new RuntimeException("unknown type to demarshall");
          }

          return newInstance;
        }
        else if (oMap.containsKey(SerializationParts.ENUM_STRING_VALUE)) {
          return Enum.valueOf(getClassReference(oMap), oMap.get(SerializationParts.ENUM_STRING_VALUE).isString().stringValue());
        }
        else {
          throw new RuntimeException("bad payload");
        }
      }

      else {
        return o.getRawValue();
      }
    }
    catch (Exception e) {
      throw new MarshallingException("Failed to demarshall an instance of " + definition.getMappingClass(), e);
    }
  }

  @Override
  public String marshall(Object o, MarshallingSession ctx) {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
    try {
      marshall(byteArrayOutputStream, o, ctx);
      return new String(byteArrayOutputStream.toByteArray());
    }
    catch (Exception e) {
      throw new RuntimeException(e);
    }
  }


  @Override
  public void marshall(final OutputStream outstream, Object o, MarshallingSession mSession) throws IOException {

    if (o == null) {
      outstream.write("null".getBytes());
      return;
    }

    EncodingSession ctx = (EncodingSession) mSession;
    Class cls = o.getClass();

    if (o instanceof Enum) {
      Enum enumer = (Enum) o;

      outstream.write(("{\"" + SerializationParts.ENCODED_TYPE + "\":\""
              + enumer.getDeclaringClass().getName() + "\""
              + ",\"" + SerializationParts.ENUM_STRING_VALUE + "\":\"" + enumer.name() + "\"}")
              .getBytes());

      return;
    }


    boolean enc = ctx.isEncoded(o);
    String hash = ctx.getObjectHash(o);

    if (enc) {
      /**
       * If this object is referencing a duplicate object in the graph, we only provide an ID reference.
       */

      outstream.write(("{\"" + SerializationParts.ENCODED_TYPE + "\":\"" + cls.getName()
              + "\",\"" + SerializationParts.OBJECT_ID + "\":\"" + hash + "\"}").getBytes());

      return;
    }

    int i = 0;
    boolean first = true;

    outstream.write(("{\"" + SerializationParts.ENCODED_TYPE + "\":\"" + cls.getName() + "\",\""
            + SerializationParts.OBJECT_ID + "\":\"" + hash + "\",").getBytes());


    for (MemberMapping mapping : definition.getReadableMemberMappings()) {
      if (!first) {
        outstream.write(',');
      }

      i++;
      Object v;

      if (mapping.getReadingMember() instanceof MetaField) {
        Field field = ((MetaField) mapping.getReadingMember()).asField();

        try {
          v = field.get(o);
        }
        catch (Exception e) {
          throw new RuntimeException("error accessing field: " + field, e);
        }
      }
      else {
        Method method = ((MetaMethod) mapping.getReadingMember()).asMethod();

        try {
          v = method.invoke(o);
        }
        catch (Exception e) {
          throw new RuntimeException("error calling getter: " + method, e);
        }
      }

      outstream.write(("\"" + mapping.getKey() + "\"").getBytes());

      outstream.write(':');
      outstream.write(
              MappingContextSingleton.get().getDefinitionsFactory()
                      .getDefinition(mapping.getType()).getMarshallerInstance().marshall(v, ctx)
                      .getBytes()
      );

      first = false;
    }

    if (i == 0) {
      outstream.write(("\"" + SerializationParts.INSTANTIATE_ONLY + "\":true").getBytes());
    }

    outstream.write('}');
  }

  public static Class getClassReference(EJObject oMap) {
    try {
      return Thread.currentThread().getContextClassLoader().loadClass(oMap.get(SerializationParts.ENCODED_TYPE).isString().stringValue());
    }
    catch (ClassNotFoundException e) {
      throw new RuntimeException("could not instantiate class", e);
    }
  }

}
TOP

Related Classes of org.jboss.errai.marshalling.server.marshallers.DefaultDefinitionMarshaller

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.