Package siena.gae

Source Code of siena.gae.GaeNativeSerializer

/**
*
*/
package siena.gae;

import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;

import siena.ClassInfo;
import siena.Json;
import siena.SienaException;
import siena.Util;
import siena.core.DecimalPrecision;
import siena.embed.Embedded;
import siena.embed.JavaSerializer;
import siena.embed.JsonSerializer;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Text;

/**
* @author mandubian <pascal.voitot@mandubian.org>
*
*/
public class GaeNativeSerializer {

  public static void embed(Entity entity, String embeddingColumnName, Object embeddedObj, int level){
    // the level prevents from stackoverflow in case of a circular ref
    if(level > 2) return;
   
    Class<?> clazz = embeddedObj.getClass();
    if(clazz.isArray() || Collection.class.isAssignableFrom(clazz)){
      throw new SienaException("can't serializer Array/Collection in native mode");
    }
   
    for (Field f : ClassInfo.getClassInfo(clazz).allFields) {
      // doesn't try to analyze fields, just try to store it
      Class<?> fieldClass = f.getType();
      String propName = embeddingColumnName + "." + ClassInfo.getSingleColumnName(f);
      Object propValue = Util.readField(embeddedObj, f);     
     
      if (propValue != null) {
        if (fieldClass == Json.class) {
          propValue = propValue.toString();
        } else if (propValue instanceof String) {
          String s = (String) propValue;
          if (s.length() > 500)
            propValue = new Text(s);
        } else if (propValue instanceof byte[]) {
          byte[] arr = (byte[]) propValue;
          // GAE Blob doesn't accept more than 1MB
          if (arr.length < 1000000)
            propValue = new Blob(arr);
          else
            propValue = new Blob(Arrays.copyOf(arr, 1000000));
        }
        else if (ClassInfo.isEmbedded(f)) {
          Embedded embed = f.getAnnotation(Embedded.class);
          switch(embed.mode()){
          case SERIALIZE_JSON:
            propValue = JsonSerializer.serialize(propValue).toString();
            String s = (String) propValue;
            if (s.length() > 500)
              propValue = new Text(s);
            break;
          case SERIALIZE_JAVA:
            // this embedding mode doesn't manage @EmbedIgnores
            try {
              byte[] b = JavaSerializer.serialize(propValue);
              // if length is less than 1Mb, can store in a blob else???
              if(b.length <= 1000000){
                propValue = new Blob(b);
              }else{
                throw new SienaException("object can be java serialized because it's too large >1mb");
              }               
            }
            catch(IOException ex) {
              throw new SienaException(ex);
            }
            break;
          case NATIVE:
            GaeNativeSerializer.embed(entity, embeddingColumnName + "." + ClassInfo.getSingleColumnName(f), propValue, level+1);
            // has set several new properties in entity so go to next field
            continue;
          }
         
        }
        else if (fieldClass == BigDecimal.class){
          DecimalPrecision ann = f.getAnnotation(DecimalPrecision.class);
          if(ann == null) {
            propValue = ((BigDecimal)propValue).toPlainString();
          }else {
            switch(ann.storageType()){
            case DOUBLE:
              propValue = ((BigDecimal)propValue).doubleValue();
              break;
            case STRING:
            case NATIVE:
              propValue = ((BigDecimal)propValue).toPlainString();
              break;
            }
          }
        }
        // enum is after embedded because an enum can be embedded
        // don't know if anyone will use it but it will work :)
        else if (Enum.class.isAssignableFrom(fieldClass)) {
          propValue = propValue.toString();
        }
        else if(ClassInfo.isModel(fieldClass)){
          // if it's a model and as there a no join, we can't fetch everything! So only the key is embedded
          //GaeNativeSerializer.embed(entity, embeddingColumnName + "." + ClassInfo.getSingleColumnName(f), propValue, level + 1);
          propValue = Util.readField(propValue, ClassInfo.getIdField(fieldClass));
        }
      }
     
      Unindexed ui = f.getAnnotation(Unindexed.class);
      if (ui == null) {
        entity.setProperty(propName, propValue);
      } else {
        entity.setUnindexedProperty(propName, propValue);
      }
    }
  }
 
  public static <T> T unembed(Class<T> clazz, String embeddingFieldName, Entity entity, int level){
    // the level prevents from stackoverflow in case of a circular ref
    if(level > 2) return null;
   
    if(clazz.isArray() || Collection.class.isAssignableFrom(clazz)){
      throw new SienaException("can't serializer Array/Collection in native mode");
    }

    T obj = Util.createObjectInstance(clazz);

    try {
      for (Field f : ClassInfo.getClassInfo(clazz).allFields) {
        // doesn't try to analyze fields, just try to store it
        String propName = embeddingFieldName + "." + ClassInfo.getSingleColumnName(f);     
        Object propValue = entity.getProperty(propName);
       
        if(ClassInfo.isEmbedded(f) && f.getAnnotation(Embedded.class).mode() == Embedded.Mode.NATIVE){
          Object value = GaeNativeSerializer.unembed(
              f.getType(), embeddingFieldName + "." + ClassInfo.getSingleColumnName(f), entity, level+1);
          Util.setField(obj, f, value);
        }
        else if(ClassInfo.isModel(f.getType())){
          // here we create a model with only the key as we don't embed anything else because there is no join by default
          Class<?> fieldClass = f.getType();
          Object value = Util.createObjectInstance(fieldClass);
          Util.setField(value, ClassInfo.getIdField(fieldClass), propValue);
         
          Util.setField(obj, f, value);
        }
        else {
          GaeMappingUtils.setFromObject(obj, f, propValue);
        }
      }
     
      return obj;
    }catch(Exception e){
      throw new SienaException(e);
    }
  }
}
TOP

Related Classes of siena.gae.GaeNativeSerializer

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.