All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.pdx.internal.AutoSerializableManager Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * 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. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire.pdx.internal;

import com.gemstone.gemfire.CancelException;
import com.gemstone.gemfire.cache.RegionService;
import com.gemstone.gemfire.internal.CopyOnWriteHashSet;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.util.concurrent.CopyOnWriteWeakHashMap;
import com.gemstone.gemfire.pdx.FieldType;
import com.gemstone.gemfire.pdx.NonPortableClassException;
import com.gemstone.gemfire.pdx.PdxReader;
import com.gemstone.gemfire.pdx.PdxSerializationException;
import com.gemstone.gemfire.pdx.PdxWriter;
import com.gemstone.gemfire.pdx.ReflectionBasedAutoSerializer;
import com.gemstone.gemfire.pdx.internal.unsafe.UnsafeWrapper;

import java.io.Externalizable;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.regex.Pattern;

/**
 * The core of auto serialization which is used in both aspect and
 * reflection-based auto-serialization. This simple manager class is a singleton
 * which tracks the relevant fields for each class which is to be
 * auto-serialized.
 * This class used to be a singleton. But now every instance of ReflectionBasedAutoSerializer
 * will have its own instance of this class. We allow instances of this class to be found
 * so that tests can access internal apis that are not exposed on the public ReflectionBasedAutoSerializer.
 * 
 * @author jens
 * @author darrel
 * @since 6.6
 */

public class AutoSerializableManager {
  private static final String INIT_CLASSES_PARAM = "classes";
  private static final String INIT_CHECK_PORTABILITY_PARAM = "check-portability";
  private static final String OPT_IDENTITY = "identity";
  private static final String OPT_EXCLUDE = "exclude";

  /*
   * Map of class and list of fields, we're interested in, for that class.
   */
  private final Map, AutoClassInfo> classMap =
      new CopyOnWriteWeakHashMap, AutoClassInfo>();

  /*
   * Mapping between class patterns and identity field patterns.
   */
  private final List identityPatterns = new CopyOnWriteArrayList();

  /*
   * Mapping between class patterns and patterns of fields to exclude
   */
  private final List excludePatterns = new CopyOnWriteArrayList();

  /*
   * This is an internal parameter which, when set either as a system property
   * or via cache.xml will not evaluate any hardcoded excludes. This helps with
   * testing as well as possibly debugging future customer issues.
   */
  private static final String NO_HARDCODED_EXCLUDES_PARAM =
      "gemfire.auto.serialization.no.hardcoded.excludes";

  private boolean noHardcodedExcludes =
      Boolean.getBoolean(NO_HARDCODED_EXCLUDES_PARAM);


  /*
   * Holds a set of regex patterns which match the list of classes we're
   * interested in.
   */
  private final Set classPatterns = new LinkedHashSet();

  /*
   * Hardcoded set of patterns which we always exclude.
   */
  private Set hardcodedExclusions = new HashSet() {{
    add(Pattern.compile("com\\.gemstone\\..*"));
    add(Pattern.compile("java\\..*"));
    add(Pattern.compile("javax\\..*"));
  }};

  /*
   * Cache of class names which have been determined to be excluded from
   * serialization. Built up within isRelevant().
   */
  private final Set cachedExcludedClasses =
    new CopyOnWriteHashSet();

  /*
   * Cache of class names which have been determined to be included for
   * serialization. Built up within isRelevant().
   */
  private final Set cachedIncludedClasses =
      new CopyOnWriteHashSet();

  /*
   * Used to hold the class names which have triggered a warning because
   * they have been determined that they should be auto serialized 
   * based on a pattern much but were not because that either do not
   * have a public no-arg constructor or have explicit java serialization code.
   */
  private final Set loggedNoAutoSerializeMsg =
      new CopyOnWriteHashSet();


  private static final Map instances = new CopyOnWriteWeakHashMap();

  private final ReflectionBasedAutoSerializer owner;
  
  public ReflectionBasedAutoSerializer getOwner() {
    return this.owner;
  }

  public static AutoSerializableManager create(ReflectionBasedAutoSerializer owner, boolean checkPortability, String... patterns) {
    AutoSerializableManager result = new AutoSerializableManager(owner);
    result.reconfigure(checkPortability, patterns);
    instances.put(owner, result);
    return result;
  }
  private AutoSerializableManager(ReflectionBasedAutoSerializer owner) {
    this.owner = owner;
  }

  public static AutoSerializableManager getInstance(ReflectionBasedAutoSerializer owner) {
    return instances.get(owner);
  }


  public Map, AutoClassInfo> getClassMap() {
    return classMap;
  }

  private boolean checkPortability;
  public void setCheckPortability(boolean b) {
    this.checkPortability = b;
  }

  public boolean getCheckPortability() {
    return this.checkPortability;
  }
  
  public void resetCaches() {
    identityPatterns.clear();
    excludePatterns.clear();
    classMap.clear();
  }

  public void resetAll() {
    resetCaches();
    this.checkPortability = false;
    classPatterns.clear();
    cachedIncludedClasses.clear();
    cachedExcludedClasses.clear();
    loggedNoAutoSerializeMsg.clear();
    this.noHardcodedExcludes = Boolean.getBoolean(NO_HARDCODED_EXCLUDES_PARAM);
  }

  /*
   * Helper method to determine whether the class of a given object is a class
   * which we are interested in (de)serializing.
   * 
   * @param obj
   * 
   * @return true if the object should be considered for serialization or false
   * otherwise
   */
  private boolean isRelevant(Class clazz) {
    String className = clazz.getName();

    // Do some short-circuiting if possible
    if (cachedIncludedClasses.contains(className)) {
      return true;
    } else if (cachedExcludedClasses.contains(className)) {
      return false;
    }

    boolean result = getOwner().isClassAutoSerialized(clazz);
    if (result) {
      cachedIncludedClasses.add(className);
    } else {
      cachedExcludedClasses.add(className);
    }
    return result;
  }

  public boolean defaultIsClassAutoSerialized(Class  clazz) {
    if (clazz.isEnum()) {
      return false;
    }
    String className = clazz.getName();
    if (! noHardcodedExcludes) {
      for (Pattern p : hardcodedExclusions) {
        if (p.matcher(className).matches()) {
          return false;
        }
      }
    }

    for (Pattern p : classPatterns) {
      if (p.matcher(className).matches()) {
        if (hasValidConstructor(clazz, p)
            && !needsStandardSerialization(clazz, p)) {
          return true;
        } else {
          return false;
        }
      }
    }
    return false;
  }
  
  /*
   * Helper method to determine whether a class has a default constructor.
   * That's needed so that it can be re-instantiated by PDX on de-serialization.
   * 
   */
  private boolean hasValidConstructor(Class clazz, Pattern matchedPattern) {
    if (unsafe != null && !USE_CONSTRUCTOR) {
      // unsafe allows us to create instances without a constructor
      return true;
    }
    try {
      clazz.getConstructor();
      return true;
    } catch (NoSuchMethodException nex) {
      String className = clazz.getName();
      if (! loggedNoAutoSerializeMsg.contains(className)) {
        loggedNoAutoSerializeMsg.add(className);
        GemFireCacheImpl.getInstance().getLogger().warning("Class "
            + className + " matched with '" + matchedPattern.pattern()
            + "' cannot be auto-serialized due to missing public no-arg"
            + " constructor. Will attempt using Java serialization.");
      }
      return false;
    }
  }
  private boolean needsStandardSerialization(Class clazz, Pattern matchedPattern) {
    if (Serializable.class.isAssignableFrom(clazz)) {
      if (Externalizable.class.isAssignableFrom(clazz)) {
        String className = clazz.getName();
        if (! loggedNoAutoSerializeMsg.contains(className)) {
          loggedNoAutoSerializeMsg.add(className);
          GemFireCacheImpl.getInstance().getLogger().warning("Class "
              + className + " matched with '" + matchedPattern.pattern()
              + "' cannot be auto-serialized because it is Externalizable."
              + " Java serialization will be used instead of auto serialization.");
        }
        return true;
      } else {
        if (getPrivateMethod(clazz, "writeObject", 
            new Class[] { ObjectOutputStream.class }, Void.TYPE)) {
          String className = clazz.getName();
          if (! loggedNoAutoSerializeMsg.contains(className)) {
            loggedNoAutoSerializeMsg.add(className);
            GemFireCacheImpl.getInstance().getLogger().warning("Class "
                + className + " matched with '" + matchedPattern.pattern()
                + "' cannot be auto-serialized because it has a writeObject(ObjectOutputStream) method."
                + " Java serialization will be used instead of auto serialization.");
          }
          return true;
        } else if (getInheritableMethod(clazz, "writeReplace", null, Object.class)) {
          String className = clazz.getName();
          if (! loggedNoAutoSerializeMsg.contains(className)) {
            loggedNoAutoSerializeMsg.add(className);
            GemFireCacheImpl.getInstance().getLogger().warning("Class "
                + className + " matched with '" + matchedPattern.pattern()
                + "' cannot be auto-serialized because it has a writeReplace() method."
                + " Java serialization will be used instead of auto serialization.");
          }
          return true;
        }
      }
    }
    return false;
  }
  /**
   * Returns true if a non-static private method with given signature defined by given
   * class, or false if none found.
   */
  private static boolean getPrivateMethod(Class cl, String name, 
                                         Class[] argTypes,
                                         Class returnType)
  {
      try {
          Method meth = cl.getDeclaredMethod(name, argTypes);
          int mods = meth.getModifiers();
          return ((meth.getReturnType() == returnType) &&
                  ((mods & Modifier.STATIC) == 0) &&
                  ((mods & Modifier.PRIVATE) != 0));
      } catch (NoSuchMethodException ex) {
          return false;
      }
  }
  /**
   * Returns true if a non-static, non-abstract method with given signature provided it
   * is defined by or accessible (via inheritance) by the given class, or
   * false if no match found.
   */
  private static boolean getInheritableMethod(Class cl, String name,
                                             Class[] argTypes,
                                             Class returnType)
  {
      Method meth = null;
      Class defCl = cl;
      while (defCl != null) {
          try {
              meth = defCl.getDeclaredMethod(name, argTypes);
              break;
          } catch (NoSuchMethodException ex) {
              defCl = defCl.getSuperclass();
          }
      }

      if ((meth == null) || (meth.getReturnType() != returnType)) {
          return false;
      }
      int mods = meth.getModifiers();
      if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
          return false;
      } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
          return true;
      } else if ((mods & Modifier.PRIVATE) != 0) {
          return (cl == defCl);
      } else {
          return packageEquals(cl, defCl);
      }
  }
  /**
   * Returns true if classes are defined in the same runtime package, false
   * otherwise.
   */
  private static boolean packageEquals(Class cl1, Class cl2) {
      return (cl1.getClassLoader() == cl2.getClassLoader() &&
              getPackageName(cl1).equals(getPackageName(cl2)));
  }
  /**
   * Returns package name of given class.
   */
  private static String getPackageName(Class cl) {
      String s = cl.getName();
      int i = s.lastIndexOf('[');
      if (i >= 0) {
          s = s.substring(i + 2);
      }
      i = s.lastIndexOf('.');
      return (i >= 0) ? s.substring(0, i) : "";
  }
  /**
   * Given a class, figure out which fields we're interested in serializing. The
   * class' entire hierarchy will be traversed and used. Transients and statics
   * will be ignored.
   * 
   * @param clazz
   *          the Class we're interested in
   * @return a list of fields to be used when this class is (de)serialized
   */
  public List getFields(Class clazz) {
    return getClassInfo(clazz).getFields();
    
  }
  public AutoClassInfo getExistingClassInfo(Class clazz) {
    return classMap.get(clazz);
  }
  public AutoClassInfo getClassInfo(Class clazz) {
    Class tmpClass = clazz;
    AutoClassInfo classInfo = getExistingClassInfo(tmpClass);
    if (classInfo == null) {
      synchronized (classMap) {
        classInfo = classMap.get(tmpClass);
        if (classInfo != null) return classInfo;
        
        List fieldList = new ArrayList();
        List variableLenFields = new ArrayList();

        while (tmpClass != Object.class) {
          Field[] fields = tmpClass.getDeclaredFields();
          for (Field f : fields) {
            if (getOwner().isFieldIncluded(f, clazz)) {
              // Should this be reset at some point?
              f.setAccessible(true);
              FieldType ft = getOwner().getFieldType(f, clazz);
              PdxFieldWrapper fw = PdxFieldWrapper.create(this, f, ft,
                  getOwner().getFieldName(f, clazz),
                  getOwner().transformFieldValue(f, clazz),
                  getOwner().isIdentityField(f, clazz));
              if (ft.isFixedWidth()) {
                fieldList.add(fw);
              } else {
                variableLenFields.add(fw);
              }
            }
          }
          tmpClass = tmpClass.getSuperclass();
        }

        fieldList.addAll(variableLenFields);
        classInfo = new AutoClassInfo(clazz, fieldList);
        GemFireCacheImpl.getInstance().getLogger().info("Auto serializer generating type for " + clazz + " for fields: " + classInfo.toFormattedString());
        classMap.put(clazz, classInfo);
      } // end sync
    }
    return classInfo;
  }
  
  public boolean defaultIsIdentityField(Field f, Class clazz) {
    return fieldMatches(f, clazz.getName(), identityPatterns);
  }
  
  public boolean defaultIsFieldIncluded(Field f, Class clazz) {
    return !Modifier.isTransient(f.getModifiers())
        && !Modifier.isStatic(f.getModifiers())
        && !fieldMatches(f, clazz.getName(), excludePatterns);
  }
  public FieldType defaultGetFieldType(Field f, Class  clazz) {
    return FieldType.get(f.getType());
  }

  private static class FieldWrapper {
    private final Field field;
    public FieldWrapper(Field f) {
      this.field = f;
    }
    public Field getField() {
      return this.field;
    }
    public int getInt(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getInt(o);
    }
    public void setInt(Object o, int v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setInt(o, v);
    }
    public boolean getBoolean(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getBoolean(o);
    }
    public void setBoolean(Object o, boolean v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setBoolean(o, v);
    }
    public byte getByte(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getByte(o);
    }
    public void setByte(Object o, byte v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setByte(o, v);
    }
    public short getShort(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getShort(o);
    }
    public void setShort(Object o, short v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setShort(o, v);
    }
    public char getChar(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getChar(o);
    }
    public void setChar(Object o, char v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setChar(o, v);
    }
    public long getLong(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getLong(o);
    }
    public void setLong(Object o, long v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setLong(o, v);
    }
    public float getFloat(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getFloat(o);
    }
    public void setFloat(Object o, float v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setFloat(o, v);
    }
    public double getDouble(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getDouble(o);
    }
    public void setDouble(Object o, double v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setDouble(o, v);
    }
    public Object getObject(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.get(o);
    }
    public void setObject(Object o, Object v) throws IllegalArgumentException, IllegalAccessException {
      this.field.set(o, v);
    }
    @Override
    public String toString() {
      return field.toString();
    }
  }
  
  private static class UnsafeFieldWrapper extends FieldWrapper {
    private final long offset;
    public UnsafeFieldWrapper(Field f) {
      super(f);
      this.offset = unsafe.objectFieldOffset(f);
    }

    @Override
    public int getInt(Object o) throws IllegalArgumentException, IllegalAccessException {
      return unsafe.getInt(o, this.offset);
    }
    @Override
    public void setInt(Object o, int v) throws IllegalArgumentException, IllegalAccessException {
      unsafe.putInt(o, this.offset, v);
    }
    @Override
    public boolean getBoolean(Object o) throws IllegalArgumentException, IllegalAccessException {
      return unsafe.getBoolean(o, this.offset);
    }
    @Override
    public void setBoolean(Object o, boolean v) throws IllegalArgumentException, IllegalAccessException {
      unsafe.putBoolean(o, this.offset, v);
    }
    @Override
    public byte getByte(Object o) throws IllegalArgumentException, IllegalAccessException {
      return unsafe.getByte(o, this.offset);
    }
    @Override
    public void setByte(Object o, byte v) throws IllegalArgumentException, IllegalAccessException {
      unsafe.putByte(o, this.offset, v);
    }
    @Override
    public short getShort(Object o) throws IllegalArgumentException, IllegalAccessException {
      return unsafe.getShort(o, this.offset);
    }
    @Override
    public void setShort(Object o, short v) throws IllegalArgumentException, IllegalAccessException {
      unsafe.putShort(o, this.offset, v);
    }
    @Override
    public char getChar(Object o) throws IllegalArgumentException, IllegalAccessException {
      return unsafe.getChar(o, this.offset);
    }
    @Override
    public void setChar(Object o, char v) throws IllegalArgumentException, IllegalAccessException {
      unsafe.putChar(o, this.offset, v);
    }
    @Override
    public long getLong(Object o) throws IllegalArgumentException, IllegalAccessException {
      return unsafe.getLong(o, this.offset);
    }
    @Override
    public void setLong(Object o, long v) throws IllegalArgumentException, IllegalAccessException {
      unsafe.putLong(o, this.offset, v);
    }
    @Override
    public float getFloat(Object o) throws IllegalArgumentException, IllegalAccessException {
      return unsafe.getFloat(o, this.offset);
    }
    @Override
    public void setFloat(Object o, float v) throws IllegalArgumentException, IllegalAccessException {
      unsafe.putFloat(o, this.offset, v);
    }
    @Override
    public double getDouble(Object o) throws IllegalArgumentException, IllegalAccessException {
      return unsafe.getDouble(o, this.offset);
    }
    @Override
    public void setDouble(Object o, double v) throws IllegalArgumentException, IllegalAccessException {
      unsafe.putDouble(o, this.offset, v);
    }
    @Override
    public Object getObject(Object o) throws IllegalArgumentException, IllegalAccessException {
      return unsafe.getObject(o, this.offset);
    }
    @Override
    public void setObject(Object o, Object v) throws IllegalArgumentException, IllegalAccessException {
      unsafe.putObject(o, this.offset, v);
    }
  }

  // unsafe will be null if the Unsafe class is not available or SAFE was requested.
  // We attempt to use Unsafe by default for best performance.
  private static final UnsafeWrapper unsafe;
  static {
    UnsafeWrapper tmp = null;
    // only use Unsafe if SAFE was not explicitly requested
    if (!Boolean.getBoolean("gemfire.AutoSerializer.SAFE")) {
      try {
        tmp = new UnsafeWrapper();
        // only throw an exception if UNSAFE was explicitly requested
      } catch (RuntimeException ex) {
        if (Boolean.getBoolean("gemfire.AutoSerializer.UNSAFE")) {
          throw ex;
        }
      } catch (Error ex) {
        if (Boolean.getBoolean("gemfire.AutoSerializer.UNSAFE")) {
          throw ex;
        }
      }
    }
    unsafe = tmp;
  }

  public static abstract class PdxFieldWrapper {
    private final FieldWrapper field;
    private final String fieldName;
    private final boolean transformValue;
    private final AutoSerializableManager owner;
    private final boolean isIdentityField;
    
    protected PdxFieldWrapper(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      FieldWrapper tmp;
      if (unsafe != null) {
        tmp = new UnsafeFieldWrapper(f);
      } else {
        tmp = new FieldWrapper(f);
      }
      this.field = tmp;
      this.fieldName = name;
      this.transformValue = transformValue;
      this.owner = owner;
      this.isIdentityField = isIdentityField;
    }
    public static PdxFieldWrapper create(AutoSerializableManager owner, Field f, FieldType ft, String name, boolean transformValue, boolean isIdentityField) {
      switch (ft) {
      case INT:
        return new IntField(owner, f, name, transformValue, isIdentityField);
      case BYTE:
        return new ByteField(owner, f, name, transformValue, isIdentityField);
      case LONG:
        return new LongField(owner, f, name, transformValue, isIdentityField);
      case BOOLEAN:
        return new BooleanField(owner, f, name, transformValue, isIdentityField);
      case CHAR:
        return new CharField(owner, f, name, transformValue, isIdentityField);
      case SHORT:
        return new ShortField(owner, f, name, transformValue, isIdentityField);
      case DOUBLE:
        return new DoubleField(owner, f, name, transformValue, isIdentityField);
      case FLOAT:
        return new FloatField(owner, f, name, transformValue, isIdentityField);
      case STRING:
        return new StringField(owner, f, name, transformValue, isIdentityField);
      case DATE:
        return new DateField(owner, f, name, transformValue, isIdentityField);
      case BYTE_ARRAY:
        return new ByteArrayField(owner, f, name, transformValue, isIdentityField);
      case STRING_ARRAY:
        return new StringArrayField(owner, f, name, transformValue, isIdentityField);
      case ARRAY_OF_BYTE_ARRAYS:
        return new ByteArrayArrayField(owner, f, name, transformValue, isIdentityField);
      case BOOLEAN_ARRAY:
        return new BooleanArrayField(owner, f, name, transformValue, isIdentityField);
      case CHAR_ARRAY:
        return new CharArrayField(owner, f, name, transformValue, isIdentityField);
      case SHORT_ARRAY:
        return new ShortArrayField(owner, f, name, transformValue, isIdentityField);
      case INT_ARRAY:
        return new IntArrayField(owner, f, name, transformValue, isIdentityField);
      case LONG_ARRAY:
        return new LongArrayField(owner, f, name, transformValue, isIdentityField);
      case FLOAT_ARRAY:
        return new FloatArrayField(owner, f, name, transformValue, isIdentityField);
      case DOUBLE_ARRAY:
        return new DoubleArrayField(owner, f, name, transformValue, isIdentityField);
      case OBJECT_ARRAY:
        return new ObjectArrayField(owner, f, name, transformValue, isIdentityField);
      case OBJECT:
        return new ObjectField(owner, f, name, transformValue, isIdentityField);
      default:
        throw new IllegalStateException("unhandled field type " + ft);
      }
    }
    public boolean getCheckPortability() {
      return this.owner.getCheckPortability();
    }
    public Field getField() {
      return this.field.getField();
    }
    public String getName() {
      return this.fieldName;
    }
    public boolean transform() {
      return this.transformValue;
    }
    public abstract void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite);
    public abstract void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite);
    public abstract void deserialize(InternalPdxReader reader, Object obj);
    public abstract void orderedDeserialize(InternalPdxReader reader, Object obj);
    
    protected final Object readTransformIf(Object o, Object serializedValue) throws IllegalArgumentException, IllegalAccessException {
      if (!transform()) return serializedValue;
      return readTransform(o, serializedValue);
    }
    protected final Object readTransform(Object o, Object serializedValue) throws IllegalArgumentException, IllegalAccessException {
      return this.owner.getOwner().readTransform(getField(), o.getClass(), serializedValue);
    }
    protected void handleException(boolean serialization, Object obj, Exception ex) {
      AutoSerializableManager.handleException(ex, serialization, getName(), obj);
    }
    protected int getInt(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getInt(o);
    }
    protected void setInt(Object o, int v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setInt(o, v);
    }
    protected boolean getBoolean(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getBoolean(o);
    }
    protected void setBoolean(Object o, boolean v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setBoolean(o, v);
    }
    protected byte getByte(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getByte(o);
    }
    protected void setByte(Object o, byte v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setByte(o, v);
    }
    protected short getShort(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getShort(o);
    }
    protected void setShort(Object o, short v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setShort(o, v);
    }
    protected char getChar(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getChar(o);
    }
    protected void setChar(Object o, char v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setChar(o, v);
    }
    protected long getLong(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getLong(o);
    }
    protected void setLong(Object o, long v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setLong(o, v);
    }
    protected float getFloat(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getFloat(o);
    }
    protected void setFloat(Object o, float v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setFloat(o, v);
    }
    protected double getDouble(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getDouble(o);
    }
    protected void setDouble(Object o, double v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setDouble(o, v);
    }
    protected Object getObject(Object o) throws IllegalArgumentException, IllegalAccessException {
      return this.field.getObject(o);
    }
    protected void setObject(Object o, Object v) throws IllegalArgumentException, IllegalAccessException {
      this.field.setObject(o, v);
    }
    public boolean isIdentityField() {
      return this.isIdentityField;
    }
    @Override
    public String toString() {
      return this.fieldName + ": " + field.toString();
    }
  }
  
  public static final class IntField extends PdxFieldWrapper {
    public IntField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        if (optimizeWrite) {
          writer.writeInt(getInt(obj));
        } else {
          writer.writeInt(getName(), getInt(obj));
        }
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeInt((Integer)newValue);
      } else {
        writer.writeInt(getName(), (Integer)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          if (transform()) {
            setObject(obj, readTransform(obj, reader.readInt(pf)));
          } else {
            setInt(obj, reader.readInt(pf));
          }
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        if (transform()) {
          setObject(obj, readTransform(obj, reader.readInt()));
        } else {
          setInt(obj, reader.readInt());
        }
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class ByteField extends PdxFieldWrapper {
    public ByteField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        if (optimizeWrite) {
          writer.writeByte(getByte(obj));
        } else {
          writer.writeByte(getName(), getByte(obj));
        }
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeByte((Byte)newValue);
      } else {
        writer.writeByte(getName(), (Byte)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          if (transform()) {
            setObject(obj, readTransform(obj, reader.readByte(pf)));
          } else {
            setByte(obj, reader.readByte(pf));
          }
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        if (transform()) {
          setObject(obj, readTransform(obj, reader.readByte()));
        } else {
          setByte(obj, reader.readByte());
        }
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class LongField extends PdxFieldWrapper {
    public LongField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        if (optimizeWrite) {
          writer.writeLong(getLong(obj));
        } else {
          writer.writeLong(getName(), getLong(obj));
        }
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeLong((Long)newValue);
      } else {
        writer.writeLong(getName(), (Long)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          if (transform()) {
            setObject(obj, readTransform(obj, reader.readLong(pf)));
          } else {
            setLong(obj, reader.readLong(pf));
          }
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        if (transform()) {
          setObject(obj, readTransform(obj, reader.readLong()));
        } else {
          setLong(obj, reader.readLong());
        }
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class BooleanField extends PdxFieldWrapper {
    public BooleanField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        if (optimizeWrite) {
          writer.writeBoolean(getBoolean(obj));
        } else {
          writer.writeBoolean(getName(), getBoolean(obj));
        }
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeBoolean((Boolean)newValue);
      } else {
        writer.writeBoolean(getName(), (Boolean)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          if (transform()) {
            setObject(obj, readTransform(obj, reader.readBoolean(pf)));
          } else {
            setBoolean(obj, reader.readBoolean(pf));
          }
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        if (transform()) {
          setObject(obj, readTransform(obj, reader.readBoolean()));
        } else {
          setBoolean(obj, reader.readBoolean());
        }
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class CharField extends PdxFieldWrapper {
    public CharField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        if (optimizeWrite) {
          writer.writeChar(getChar(obj));
        } else {
          writer.writeChar(getName(), getChar(obj));
        }
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeChar((Character)newValue);
      } else {
        writer.writeChar(getName(), (Character)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          if (transform()) {
            setObject(obj, readTransform(obj, reader.readChar(pf)));
          } else {
            setChar(obj, reader.readChar(pf));
          }
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        if (transform()) {
          setObject(obj, readTransform(obj, reader.readChar()));
        } else {
          setChar(obj, reader.readChar());
        }
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class ShortField extends PdxFieldWrapper {
    public ShortField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        if (optimizeWrite) {
          writer.writeShort(getShort(obj));
        } else {
          writer.writeShort(getName(), getShort(obj));
        }
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeShort((Short)newValue);
      } else {
        writer.writeShort(getName(), (Short)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          if (transform()) {
            setObject(obj, readTransform(obj, reader.readShort(pf)));
          } else {
            setShort(obj, reader.readShort(pf));
          }
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        if (transform()) {
          setObject(obj, readTransform(obj, reader.readShort()));
        } else {
          setShort(obj, reader.readShort());
        }
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class FloatField extends PdxFieldWrapper {
    public FloatField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        if (optimizeWrite) {
          writer.writeFloat(getFloat(obj));
        } else {
          writer.writeFloat(getName(), getFloat(obj));
        }
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeFloat((Float)newValue);
      } else {
        writer.writeFloat(getName(), (Float)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          if (transform()) {
            setObject(obj, readTransform(obj, reader.readFloat(pf)));
          } else {
            setFloat(obj, reader.readFloat(pf));
          }
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        if (transform()) {
          setObject(obj, readTransform(obj, reader.readFloat()));
        } else {
          setFloat(obj, reader.readFloat());
        }
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class DoubleField extends PdxFieldWrapper {
    public DoubleField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        if (optimizeWrite) {
          writer.writeDouble(getDouble(obj));
        } else {
          writer.writeDouble(getName(), getDouble(obj));
        }
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeDouble((Double)newValue);
      } else {
        writer.writeDouble(getName(), (Double)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          if (transform()) {
            setObject(obj, readTransform(obj, reader.readDouble(pf)));
          } else {
            setDouble(obj, reader.readDouble(pf));
          }
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        if (transform()) {
          setObject(obj, readTransform(obj, reader.readDouble()));
        } else {
          setDouble(obj, reader.readDouble());
        }
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class ObjectField extends PdxFieldWrapper {
    public ObjectField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeObject(newValue, getCheckPortability());
      } else {
        writer.writeObject(getName(), newValue, getCheckPortability());
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readObject(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readObject()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class StringField extends PdxFieldWrapper {
    public StringField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeString((String)newValue);
      } else {
        writer.writeString(getName(), (String)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readString(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readString()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class DateField extends PdxFieldWrapper {
    public DateField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeDate((Date)newValue);
      } else {
        writer.writeDate(getName(), (Date)newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readDate(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readDate()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class ByteArrayField extends PdxFieldWrapper {
    public ByteArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeByteArray((byte[])newValue);
      } else {
        writer.writeByteArray(getName(), (byte[])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readByteArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readByteArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class BooleanArrayField extends PdxFieldWrapper {
    public BooleanArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeBooleanArray((boolean[])newValue);
      } else {
        writer.writeBooleanArray(getName(), (boolean[])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readBooleanArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readBooleanArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class ShortArrayField extends PdxFieldWrapper {
    public ShortArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeShortArray((short[])newValue);
      } else {
        writer.writeShortArray(getName(), (short[])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readShortArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readShortArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class CharArrayField extends PdxFieldWrapper {
    public CharArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeCharArray((char[])newValue);
      } else {
        writer.writeCharArray(getName(), (char[])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readCharArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readCharArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class IntArrayField extends PdxFieldWrapper {
    public IntArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeIntArray((int[])newValue);
      } else {
        writer.writeIntArray(getName(), (int[])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readIntArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readIntArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class LongArrayField extends PdxFieldWrapper {
    public LongArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeLongArray((long[])newValue);
      } else {
        writer.writeLongArray(getName(), (long[])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readLongArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readLongArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class FloatArrayField extends PdxFieldWrapper {
    public FloatArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeFloatArray((float[])newValue);
      } else {
        writer.writeFloatArray(getName(), (float[])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readFloatArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readFloatArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class DoubleArrayField extends PdxFieldWrapper {
    public DoubleArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeDoubleArray((double[])newValue);
      } else {
        writer.writeDoubleArray(getName(), (double[])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readDoubleArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readDoubleArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class StringArrayField extends PdxFieldWrapper {
    public StringArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeStringArray((String[])newValue);
      } else {
        writer.writeStringArray(getName(), (String[])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readStringArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readStringArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class ByteArrayArrayField extends PdxFieldWrapper {
    public ByteArrayArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeArrayOfByteArrays((byte[][])newValue);
      } else {
        writer.writeArrayOfByteArrays(getName(), (byte[][])newValue);
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readArrayOfByteArrays(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readArrayOfByteArrays()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  public static final class ObjectArrayField extends PdxFieldWrapper {
    public ObjectArrayField(AutoSerializableManager owner, Field f, String name, boolean transformValue, boolean isIdentityField) {
      super(owner, f, name, transformValue, isIdentityField);
    }

    @Override
    public void serialize(PdxWriterImpl writer, Object obj, boolean optimizeWrite) {
      try {
        serializeValue(writer, getObject(obj), optimizeWrite);
      } catch (Exception ex) {
        handleException(true, obj, ex);
      }
    }
    @Override
    public void serializeValue(PdxWriterImpl writer, Object newValue, boolean optimizeWrite) {
      if (optimizeWrite) {
        writer.writeObjectArray((Object[])newValue, getCheckPortability());
      } else {
        writer.writeObjectArray(getName(), (Object[])newValue, getCheckPortability());
      }
    }

    @Override
    public void deserialize(InternalPdxReader reader, Object obj) {
      PdxField pf = reader.getPdxField(getName());
      if (pf != null) {
        try {
          setObject(obj, readTransformIf(obj, reader.readObjectArray(pf)));
        } catch (Exception ex) {
          handleException(false, obj, ex);
        }
      }
    }

    @Override
    public void orderedDeserialize(InternalPdxReader reader, Object obj) {
      try {
        setObject(obj, readTransformIf(obj, reader.readObjectArray()));
      } catch (Exception ex) {
        handleException(false, obj, ex);
      }
    }
  }
  /**
   * Given an object, use its class to determine which fields are to be used
   * when (de)serializing.
   * 
   * @param obj
   *          the object whose class we're interested in
   * @return a list of fields to be used when this object's class is
   *         (de)serialized
   */
  public List getFields(Object obj) {
    return getFields(obj.getClass());
  }

  /**
   * Using the given PdxWriter, write out the relevant fields for the object
   * instance passed in.
   * 
   * @param writer
   *          the PdxWriter to use when writing the object
   * @param obj
   *          the object to serialize
   * @return true if the object was serialized, false
   *         otherwise
   */
  public boolean writeData(PdxWriter writer, Object obj) {
    if (isRelevant(obj.getClass())) {
      writeData(writer, obj, getClassInfo(obj.getClass()));
      return true;
    }
    return false;
  }

  private static void handleException(Exception ex, boolean serialization, String fieldName, Object obj) {
    if (ex instanceof CancelException) {
      // fix for bug 43936
      throw (CancelException)ex;
    } else if (ex instanceof NonPortableClassException) {
      throw (NonPortableClassException)ex;
    } else {
      throw new PdxSerializationException((serialization ? "Serialization" : "Deserialization") 
          + " error on field "
          + fieldName + " for class " + obj.getClass().getName(), ex);
    }
  }

  /**
   * Using the given PdxWriter, write out the fields which have been passed in.
   * 
   * @param writer
   *          the PdxWriter to use when writing the object
   * @param obj
   *          the object to serialize
   * @param autoClassInfo
   *          a List of Fields which are to be written
   *          out
   */
  public void writeData(PdxWriter writer, Object obj, AutoClassInfo autoClassInfo) {
    PdxWriterImpl w = (PdxWriterImpl)writer;
    boolean optimizeFieldWrites = false;
    if (autoClassInfo.getSerializedType() != null) {
      // check to see if we have unread data for this instance
      if (w.initUnreadData() == null) {
        // we don't so we can optimize the field writes since
        // we will write them in the correct order
        optimizeFieldWrites = true;
      }
    }
    for (PdxFieldWrapper f : autoClassInfo.getFields()) {
      //System.out.println("DEBUG writing field=" + f.getField().getName() + " offset=" + ((PdxWriterImpl)writer).position());
      if (f.transform()) {
        try {
          Object newValue = getOwner().writeTransform(f.getField(), obj.getClass(), f.getObject(obj));
          f.serializeValue(w, newValue, optimizeFieldWrites);
        } catch (Exception ex) {
          f.handleException(true, obj, ex);
        }
      } else {
        f.serialize(w, obj, optimizeFieldWrites);
      }
      if (f.isIdentityField() && w.definingNewPdxType()) {
        try {
          w.markIdentityField(f.getName());
        } catch (Exception ex) {
          handleException(ex, true, f.getName(), obj);
        }
      }
    }
    if (autoClassInfo.getSerializedType() == null) {
      autoClassInfo.setSerializedType(w.getAutoPdxType());
    }
  }
  
  private static final boolean USE_CONSTRUCTOR = !Boolean.getBoolean("gemfire.autopdx.ignoreConstructor");
  
  /**
   * Using the given PdxReader, recreate the given object.
   * 
   * @param reader
   *          the PdxReader to use when reading the object
   * @param clazz
   *          the class of the object to re-create
   */
  public Object readData(PdxReader reader, Class clazz) {
    Object result = null;
    if (isRelevant(clazz)) {
      AutoClassInfo ci = getClassInfo(clazz);
      result = ci.newInstance(clazz);
      InternalPdxReader ri = (InternalPdxReader)reader;
      PdxType pt = ri.getPdxType();
      if (ci.matchesPdxType(pt)) {
        pt.setAutoInfo(ci);
        ri.orderedDeserialize(result, ci);
      } else {
        for (PdxFieldWrapper f : ci.getFields()) {
          f.deserialize(ri, result);
        }
      }
    }
    return result;
  }

  /**
   * Add a new class pattern / identity-field pattern tuple
   * @param classPattern the class pattern
   * @param fieldPattern the pattern to identify a field as an identity field
   *  within the given class pattern
   */
  public void addIdentityPattern(String classPattern, String fieldPattern) {
    identityPatterns.add(new String[] {classPattern, fieldPattern});
  }

  /**
   * Return the identity patterns. The patterns are returned as a List
   * of String arrays of size 2 - essentially a tuple of the form
   * 
   *   (classPattern, identityPattern)
   * 
* * @return the identity patterns */ public List getIdentityPatterns() { return identityPatterns; } /** * Add a new class pattern / exclude-field pattern tuple * @param classPattern the class pattern * @param fieldPattern the pattern to exclude a field from serialization * within the given class pattern */ public void addExcludePattern(String classPattern, String fieldPattern) { excludePatterns.add(new String[] {classPattern, fieldPattern}); } /** * Return the exclude patterns. The patterns are returned as a List * of String arrays of size 2 - essentially a tuple of the form *
   *   (classPattern, excludePattern)
   * 
* * @return the exclude patterns */ public List getExcludePatterns() { return excludePatterns; } /* * Helper method which determines whether a given field matches a set of * class/field patterns. * * @param field the Field to consider * @param field the className which references this field * @param matches a map containing the * @param */ private boolean fieldMatches(Field field, String className, List matches) { String fieldName = field.getName(); for (String[] e : matches) { if (className.matches(e[0]) && fieldName.matches(e[1])) { return true; } } return false; } /** * Holds meta information about a class that we have auto serialized. * @author darrel * */ public static class AutoClassInfo { private final WeakReference> clazzRef; /** * The fields that describe the class */ private final List fields; /** * The pdxType ids that we are known to exactly match. */ private final Set matchingPdxIds = new CopyOnWriteArraySet(); /** * The pdxType ids that do not exactly match our class. * Either their field order differs it they have extra or missing fields. */ private final Set mismatchingPdxIds = new CopyOnWriteArraySet(); /** * The PdxType created by the first serialization by the auto serializer. */ private PdxType serializedType = null; public AutoClassInfo(Class clazz, List fields) { this.clazzRef = new WeakReference>(clazz); this.fields = fields; } public String toFormattedString() { StringBuffer sb = new StringBuffer(); boolean first = true; for (Object o: this.fields) { if (first) { first = false; sb.append('\n'); } sb.append(" ").append(o).append('\n'); } return sb.toString(); } public Object newInstance(Class clazz) { Object result; try { if (unsafe != null && !USE_CONSTRUCTOR) { result = unsafe.allocateInstance(clazz); } else { result = clazz.newInstance(); } } catch (Exception ex) { throw new PdxSerializationException( LocalizedStrings.DataSerializer_COULD_NOT_CREATE_AN_INSTANCE_OF_A_CLASS_0 .toLocalizedString(clazz.getName()), ex); } return result; } public void setSerializedType(PdxType v) { this.serializedType = v; } public PdxType getSerializedType() { return this.serializedType; } public Class getInfoClass() { return this.clazzRef.get(); } public List getFields() { return this.fields; } public boolean matchesPdxType(PdxType t) { Integer pdxTypeId = Integer.valueOf(t.getTypeId()); if (this.matchingPdxIds.contains(pdxTypeId)) { return true; } else if (this.mismatchingPdxIds.contains(pdxTypeId)) { return false; } else if (checkForMatch(t)) { this.matchingPdxIds.add(pdxTypeId); return true; } else { this.mismatchingPdxIds.add(pdxTypeId); return false; } } private boolean checkForMatch(PdxType t) { if (this.fields.size() != t.getFieldCount()) { return false; } Iterator pdxIt = t.getFields().iterator(); for (PdxFieldWrapper f: this.fields) { PdxField pdxF = pdxIt.next(); if (!f.getName().equals(pdxF.getFieldName())) { return false; } if (!FieldType.get(f.getField().getType()).equals(pdxF.getFieldType())) { return false; } } return true; } @Override public String toString() { return "AutoClassInfo [fields=" + fields + "]"; } } public void init(Properties props) { resetAll(); if (props != null) { Enumeration it = props.propertyNames(); while (it.hasMoreElements()) { Object o = it.nextElement(); if (o instanceof String) { String key = (String)o; if (INIT_CLASSES_PARAM.equals(key)) { String propValue = props.getProperty(INIT_CLASSES_PARAM); if (propValue != null) { processInitParams(propValue); } } else if (INIT_CHECK_PORTABILITY_PARAM.equals(key)) { String propValue = props.getProperty(INIT_CHECK_PORTABILITY_PARAM); if (propValue != null) { setCheckPortability(Boolean.parseBoolean(propValue)); } } else if (NO_HARDCODED_EXCLUDES_PARAM.equals(key)) { if (props.getProperty(NO_HARDCODED_EXCLUDES_PARAM) != null) { noHardcodedExcludes = true; } } else { throw new IllegalArgumentException("ReflectionBasedAutoSerializer: unknown init property \"" + key + "\""); } } else { throw new IllegalArgumentException("ReflectionBasedAutoSerializer: unknown non-String init property \"" + o + "\""); } } } } public Properties getConfig() { Properties props = new Properties(); if (classPatterns.isEmpty()) { return props; } StringBuilder sb = new StringBuilder(); // This is so that we can exclude duplicate Set tmp = new HashSet(); for (Pattern p : classPatterns) { tmp.add(p.pattern()); } for (Iterator i = tmp.iterator(); i.hasNext(); ) { String s = i.next(); sb.append(s); if (i.hasNext()) { sb.append(", "); } } if (getIdentityPatterns().size() > 0) { sb.append(", "); for (Iterator i = getIdentityPatterns().iterator(); i.hasNext(); ) { String[] s = i.next(); sb.append(s[0]).append("#" + OPT_IDENTITY + "=").append(s[1]); if (i.hasNext()) { sb.append(", "); } } } if (getExcludePatterns().size() > 0) { sb.append(", "); for (Iterator i = getExcludePatterns().iterator(); i.hasNext(); ) { String[] s = i.next(); sb.append(s[0]).append("#" + OPT_EXCLUDE + "=").append(s[1]); if (i.hasNext()) { sb.append(", "); } } } props.put(INIT_CLASSES_PARAM, sb.toString()); if (getCheckPortability()) { props.put(INIT_CHECK_PORTABILITY_PARAM, "true"); } return props; } public void reconfigure(boolean b, String... patterns) { resetAll(); setCheckPortability(b); for (String c : patterns) { processInitParams(c); } } private void processInitParams(String value) { String identityPattern; String excludePattern; for (String s : value.split("[, ]+")) { if (s.length() > 0) { // Let's check for any additional embedded params... String[] split = s.split("#"); for (int i = 1; i < split.length; i++) { identityPattern = null; excludePattern = null; String[] paramVals = split[i].split("="); if (paramVals.length != 2) { throw new IllegalArgumentException("Unable to correctly process auto serialization init value: " + value); } if (OPT_IDENTITY.equalsIgnoreCase(paramVals[0])) { identityPattern = paramVals[1]; } else if (OPT_EXCLUDE.equalsIgnoreCase(paramVals[0])) { excludePattern = paramVals[1]; } else { throw new IllegalArgumentException("Unable to correctly process auto serialization init value: " + value); } if (identityPattern != null) { addIdentityPattern(split[0], identityPattern); } if (excludePattern != null) { addExcludePattern(split[0], excludePattern); } } classPatterns.add(Pattern.compile(split[0])); } } } private RegionService cache; public RegionService getRegionService() { return this.cache; } public void setRegionService(RegionService rs) { this.cache = rs; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (checkPortability ? 1231 : 1237); result = prime * result + ((classPatterns == null) ? 0 : classPatterns.hashCode()); result = prime * result + ((excludePatterns == null) ? 0 : excludePatterns.hashCode()); result = prime * result + ((identityPatterns == null) ? 0 : identityPatterns.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; AutoSerializableManager other = (AutoSerializableManager) obj; if (checkPortability != other.checkPortability) return false; if (classPatterns == null) { if (other.classPatterns != null) return false; } else if (!classPatterns.equals(other.classPatterns)) return false; if (excludePatterns == null) { if (other.excludePatterns != null) return false; } else if (!excludePatterns.equals(other.excludePatterns)) return false; if (identityPatterns == null) { if (other.identityPatterns != null) return false; } else if (!identityPatterns.equals(other.identityPatterns)) return false; return true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy