/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You 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.apache.geode.pdx.internal; import org.apache.geode.CancelException; import org.apache.geode.cache.RegionService; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.CopyOnWriteHashSet; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.util.concurrent.CopyOnWriteWeakHashMap; import org.apache.geode.pdx.*; import org.apache.geode.pdx.internal.unsafe.UnsafeWrapper; import org.apache.logging.log4j.Logger; 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.*; 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. * * @since GemFire 6.6 */ public class AutoSerializableManager { private static final Logger logger = LogService.getLogger(); 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<Class<?>, AutoClassInfo> classMap = new CopyOnWriteWeakHashMap<Class<?>, AutoClassInfo>(); /* * Mapping between class patterns and identity field patterns. */ private final List<String[]> identityPatterns = new CopyOnWriteArrayList<String[]>(); /* * Mapping between class patterns and patterns of fields to exclude */ private final List<String[]> excludePatterns = new CopyOnWriteArrayList<String[]>(); /* * 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 = DistributionConfig.GEMFIRE_PREFIX + "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<Pattern> classPatterns = new LinkedHashSet<Pattern>(); /* * Hardcoded set of patterns which we always exclude. */ private Set<Pattern> hardcodedExclusions = new HashSet<Pattern>() { { 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<String> cachedExcludedClasses = new CopyOnWriteHashSet<String>(); /* * Cache of class names which have been determined to be included for serialization. Built up * within isRelevant(). */ private final Set<String> cachedIncludedClasses = new CopyOnWriteHashSet<String>(); /* * 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<String> loggedNoAutoSerializeMsg = new CopyOnWriteHashSet<String>(); 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); return result; } private AutoSerializableManager(ReflectionBasedAutoSerializer owner) { this.owner = owner; } public Map<Class<?>, AutoClassInfo> getClassMap() { return classMap; } private boolean checkPortability; public void setCheckPortability(boolean b) { this.checkPortability = b; } public boolean getCheckPortability() { return this.checkPortability; } public void resetCachedTypes() { classMap.clear(); } public void resetCaches() { identityPatterns.clear(); excludePatterns.clear(); resetCachedTypes(); } 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); logger.warn( "Class {} matched with '{}' cannot be auto-serialized due to missing public no-arg constructor. Will attempt using Java serialization.", className, matchedPattern.pattern()); } 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); logger.warn( "Class {} matched with '{}' cannot be auto-serialized because it is Externalizable. Java serialization will be used instead of auto-serialization.", className, matchedPattern.pattern()); } return true; } else { if (getPrivateMethod(clazz, "writeObject", new Class[] {ObjectOutputStream.class}, Void.TYPE)) { String className = clazz.getName(); if (!loggedNoAutoSerializeMsg.contains(className)) { loggedNoAutoSerializeMsg.add(className); logger.warn( "Class {} matched with '{}' cannot be auto-serialized because it has a writeObject(ObjectOutputStream) method. Java serialization will be used instead of auto-serialization.", className, matchedPattern.pattern()); } return true; } else if (getInheritableMethod(clazz, "writeReplace", null, Object.class)) { String className = clazz.getName(); if (!loggedNoAutoSerializeMsg.contains(className)) { loggedNoAutoSerializeMsg.add(className); logger.warn( "Class {} matched with '{}' cannot be auto-serialized because it has a writeReplace() method. Java serialization will be used instead of auto-serialization.", className, matchedPattern.pattern()); } 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 <code>Class</code> we're interested in * @return a list of fields to be used when this class is (de)serialized */ public List<PdxFieldWrapper> 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<PdxFieldWrapper> fieldList = new ArrayList<PdxFieldWrapper>(); List<PdxFieldWrapper> variableLenFields = new ArrayList<PdxFieldWrapper>(); 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); logger.info("Auto serializer generating type for {} for fields: {}", clazz, 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(DistributionConfig.GEMFIRE_PREFIX + "AutoSerializer.SAFE")) { try { tmp = new UnsafeWrapper(); // only throw an exception if UNSAFE was explicitly requested } catch (RuntimeException ex) { if (Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "AutoSerializer.UNSAFE")) { throw ex; } } catch (Error ex) { if (Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "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<PdxFieldWrapper> 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 <code>PdxWriter</code> to use when writing the object * @param obj the object to serialize * @return <code>true</code> if the object was serialized, <code>false</code> 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 <code>PdxWriter</code> to use when writing the object * @param obj the object to serialize * @param autoClassInfo a <code>List</code> of <code>Field</code>s 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(DistributionConfig.GEMFIRE_PREFIX + "autopdx.ignoreConstructor"); /** * Using the given PdxReader, recreate the given object. * * @param reader the <code>PdxReader</code> 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 <code>List</code> of * <code>String</code> arrays of size 2 - essentially a tuple of the form * * <pre> * (classPattern, identityPattern) * </pre> * * @return the identity patterns */ public List<String[]> 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 <code>List</code> of * <code>String</code> arrays of size 2 - essentially a tuple of the form * * <pre> * (classPattern, excludePattern) * </pre> * * @return the exclude patterns */ public List<String[]> getExcludePatterns() { return excludePatterns; } /* * Helper method which determines whether a given field matches a set of class/field patterns. * * @param field the <code>Field</code> 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<String[]> 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. * */ public static class AutoClassInfo { private final WeakReference<Class<?>> clazzRef; /** * The fields that describe the class */ private final List<PdxFieldWrapper> fields; /** * The pdxType ids that we are known to exactly match. */ private final Set<Integer> matchingPdxIds = new CopyOnWriteArraySet<Integer>(); /** * 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<Integer> mismatchingPdxIds = new CopyOnWriteArraySet<Integer>(); /** * The PdxType created by the first serialization by the auto serializer. */ private PdxType serializedType = null; public AutoClassInfo(Class<?> clazz, List<PdxFieldWrapper> fields) { this.clazzRef = new WeakReference<Class<?>>(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<PdxFieldWrapper> 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.getUndeletedFieldCount()) { return false; } Iterator<PdxField> pdxIt = t.getFields().iterator(); for (PdxFieldWrapper f : this.fields) { PdxField pdxF = pdxIt.next(); if (pdxF.isDeleted()) { return false; // If the type has a deleted field then we can't do ordered deserialization // because we need to skip over the deleted field's bytes. } 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 duplicates // LinkedHashSet is used to preserve the order of classPatterns. See bug 52286. Set<String> tmp = new LinkedHashSet<String>(); for (Pattern p : classPatterns) { tmp.add(p.pattern()); } for (Iterator<String> 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<String[]> 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<String[]> 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; } }