| /* |
| * 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; |
| |
| import java.lang.reflect.Field; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Properties; |
| |
| import org.apache.geode.cache.Cache; |
| import org.apache.geode.cache.Declarable; |
| import org.apache.geode.cache.RegionService; |
| import org.apache.geode.pdx.internal.AutoSerializableManager; |
| |
| /** |
| * This class uses Java reflection in conjunction with {@link org.apache.geode.pdx.PdxSerializer |
| * PdxSerialzer} to perform automatic serialization of domain objects. The implication is that the |
| * domain classes do not need to implement the <code>PdxSerializable</code> interface. |
| * <p> |
| * This implementation will serialize all relevant fields |
| * <p> |
| * For example: |
| * |
| * <pre> |
| * Cache c = new CacheFactory().set("cache-xml-file", cacheXmlFileName) |
| * .setPdxSerializer(new ReflectionBasedAutoSerializer("com.foo.DomainObject")).create(); |
| * </pre> |
| * <p> |
| * In this example <code>DomainObject</code> would not need to implement |
| * <code>PdxSerializable</code> to be serialized. |
| * <p> |
| * The equivalent <code>cache.xml</code> entries might be as follows: |
| * |
| * <pre> |
| * <pdx> |
| * <pdx-serializer> |
| * <class-name> |
| * org.apache.geode.pdx.ReflectionBasedAutoSerializer |
| * </class-name> |
| * <parameter name="classes"> |
| * <string> com.company.domain.DomainObject </string> |
| * </parameter> |
| * </pdx-serializer> |
| * </pdx> |
| * </pre> |
| * |
| * See {@link ReflectionBasedAutoSerializer#reconfigure(String...) reconfigure} for additional |
| * details on the format of the parameter string. |
| * |
| * @since GemFire 6.6 |
| */ |
| public class ReflectionBasedAutoSerializer implements PdxSerializer, Declarable { |
| |
| private final AutoSerializableManager manager; |
| |
| /** |
| * Default constructor primarily used during declarative configuration via the cache.xml file. |
| * Instances created with this constructor will not match any classes so use |
| * {@link #ReflectionBasedAutoSerializer(String...)} instead. |
| */ |
| public ReflectionBasedAutoSerializer() { |
| this(new String[0]); |
| } |
| |
| /** |
| * Constructor which takes a list of class name patterns which are to be auto-serialized. |
| * Portability of serialization will not be checked. |
| * <p> |
| * Each string in the list represents a definition in the following form: |
| * |
| * <pre> |
| * <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern> |
| * </pre> |
| * |
| * The hash (#) characters are separators and are not part of the parameter name. An example would |
| * be: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.*#exclude=creationDate |
| * </pre> |
| * |
| * This would select all classes with a class name beginning with |
| * <code>com.company.DomainObject</code> and would select as PDX identity fields any fields |
| * beginning with <code>id</code> and would not serialize the field called |
| * <code>creationDate</code>. |
| * <p> |
| * There is no association between the the <i>identity</i> and <i>exclude</i> options, so the |
| * above example could also be expressed as: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.* |
| * com.company.DomainObject.*#exclude=creationDate |
| * </pre> |
| * |
| * Note that <u>all</u> defined patterns are used when determining whether a field should be |
| * considered as an identity field or should be excluded. Thus the order of the patterns is not |
| * relevant. |
| * |
| * @param classes the patterns which are matched against domain class names to determine whether |
| * they should be serialized |
| * @deprecated as of 6.6.2 use ReflectionBasedAutoSerializer(String...) instead. |
| */ |
| public ReflectionBasedAutoSerializer(List<String> classes) { |
| this(listToArray(classes)); |
| } |
| |
| private static String[] listToArray(List<String> l) { |
| if (l == null) { |
| l = Collections.emptyList(); |
| } |
| return l.toArray(new String[0]); |
| } |
| |
| /** |
| * Constructor which takes a list of class name patterns which are to be auto-serialized. |
| * Portability of serialization will not be checked. |
| * <p> |
| * Each string in the list represents a definition in the following form: |
| * |
| * <pre> |
| * <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern> |
| * </pre> |
| * |
| * The hash (#) characters are separators and are not part of the parameter name. An example would |
| * be: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.*#exclude=creationDate |
| * </pre> |
| * |
| * This would select all classes with a class name beginning with |
| * <code>com.company.DomainObject</code> and would select as PDX identity fields any fields |
| * beginning with <code>id</code> and would not serialize the field called |
| * <code>creationDate</code>. |
| * <p> |
| * There is no association between the the <i>identity</i> and <i>exclude</i> options, so the |
| * above example could also be expressed as: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.* |
| * com.company.DomainObject.*#exclude=creationDate |
| * </pre> |
| * |
| * Note that <u>all</u> defined patterns are used when determining whether a field should be |
| * considered as an identity field or should be excluded. Thus the order of the patterns is not |
| * relevant. |
| * |
| * @param patterns the patterns which are matched against domain class names to determine whether |
| * they should be serialized |
| * @since GemFire 6.6.2 |
| */ |
| public ReflectionBasedAutoSerializer(String... patterns) { |
| this(false, patterns); |
| } |
| |
| /** |
| * Constructor which takes a list of class name patterns which are to be auto-serialized. |
| * <p> |
| * Each string in the list represents a definition in the following form: |
| * |
| * <pre> |
| * <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern> |
| * </pre> |
| * |
| * The hash (#) characters are separators and are not part of the parameter name. An example would |
| * be: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.*#exclude=creationDate |
| * </pre> |
| * |
| * This would select all classes with a class name beginning with |
| * <code>com.company.DomainObject</code> and would select as PDX identity fields any fields |
| * beginning with <code>id</code> and would not serialize the field called |
| * <code>creationDate</code>. |
| * <p> |
| * There is no association between the the <i>identity</i> and <i>exclude</i> options, so the |
| * above example could also be expressed as: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.* |
| * com.company.DomainObject.*#exclude=creationDate |
| * </pre> |
| * |
| * Note that <u>all</u> defined patterns are used when determining whether a field should be |
| * considered as an identity field or should be excluded. Thus the order of the patterns is not |
| * relevant. |
| * |
| * @param checkPortability if <code>true</code> then an serialization done by this serializer will |
| * throw an exception if the object it not portable to non-java languages. |
| * @param patterns the patterns which are matched against domain class names to determine whether |
| * they should be serialized |
| * @since GemFire 6.6.2 |
| */ |
| public ReflectionBasedAutoSerializer(boolean checkPortability, String... patterns) { |
| // We allow this class to escape its constructor so that our delegate can |
| // call back to us when needed. Callbacks will not happen until this instance |
| // is fully constructed and registered with the Cache. |
| this.manager = AutoSerializableManager.create(this, checkPortability, patterns); |
| } |
| |
| /** |
| * Method to configure classes to consider for serialization, to set any identity fields and to |
| * define any fields to exclude from serialization. |
| * <p> |
| * Each string in the list represents a definition in the following form: |
| * |
| * <pre> |
| * <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern> |
| * </pre> |
| * |
| * The hash (#) characters are separators and are not part of the parameter name. An example would |
| * be: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.*#exclude=creationDate |
| * </pre> |
| * |
| * This would select all classes with a class name beginning with |
| * <code>com.company.DomainObject</code> and would select as PDX identity fields any fields |
| * beginning with <code>id</code> and would not serialize the field called |
| * <code>creationDate</code>. |
| * <p> |
| * There is no association between the the <i>identity</i> and <i>exclude</i> options, so the |
| * above example could also be expressed as: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.* |
| * com.company.DomainObject.*#exclude=creationDate |
| * </pre> |
| * |
| * Note that <u>all</u> defined patterns are used when determining whether a field should be |
| * considered as an identity field or should be excluded. Thus the order of the patterns is not |
| * relevant. |
| * |
| * @param patterns the list of definitions to apply |
| * @deprecated as of 6.6.2 use {@link #reconfigure(String...)} instead. |
| */ |
| public void setSerializableClasses(List<String> patterns) { |
| reconfigure(listToArray(patterns)); |
| } |
| |
| /** |
| * Method to reconfigure this serializer. Any previous configuration is cleared. The serializer |
| * will not check for portable serialization. |
| * <p> |
| * Each string in the list represents a definition in the following form: |
| * |
| * <pre> |
| * <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern> |
| * </pre> |
| * |
| * The hash (#) characters are separators and are not part of the parameter name. An example would |
| * be: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.*#exclude=creationDate |
| * </pre> |
| * |
| * This would select all classes with a class name beginning with |
| * <code>com.company.DomainObject</code> and would select as PDX identity fields any fields |
| * beginning with <code>id</code> and would not serialize the field called |
| * <code>creationDate</code>. |
| * <p> |
| * There is no association between the the <i>identity</i> and <i>exclude</i> options, so the |
| * above example could also be expressed as: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.* |
| * com.company.DomainObject.*#exclude=creationDate |
| * </pre> |
| * |
| * Note that <u>all</u> defined patterns are used when determining whether a field should be |
| * considered as an identity field or should be excluded. Thus the order of the patterns is not |
| * relevant. |
| * |
| * @param patterns the definitions to apply |
| * @since GemFire 6.6.2 |
| */ |
| public void reconfigure(String... patterns) { |
| reconfigure(false, patterns); |
| } |
| |
| /** |
| * Method to reconfigure this serializer. Any previous configuration is cleared. |
| * <p> |
| * Each string in the list represents a definition in the following form: |
| * |
| * <pre> |
| * <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern> |
| * </pre> |
| * |
| * The hash (#) characters are separators and are not part of the parameter name. An example would |
| * be: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.*#exclude=creationDate |
| * </pre> |
| * |
| * This would select all classes with a class name beginning with |
| * <code>com.company.DomainObject</code> and would select as PDX identity fields any fields |
| * beginning with <code>id</code> and would not serialize the field called |
| * <code>creationDate</code>. |
| * <p> |
| * There is no association between the the <i>identity</i> and <i>exclude</i> options, so the |
| * above example could also be expressed as: |
| * |
| * <pre> |
| * com.company.DomainObject.*#identity=id.* |
| * com.company.DomainObject.*#exclude=creationDate |
| * </pre> |
| * |
| * Note that <u>all</u> defined patterns are used when determining whether a field should be |
| * considered as an identity field or should be excluded. Thus the order of the patterns is not |
| * relevant. |
| * |
| * @param patterns the definitions to apply |
| * @param checkPortability if <code>true</code> then an serialization done by this serializer will |
| * throw an exception if the object it not portable to non-java languages. |
| * @since GemFire 6.6.2 |
| */ |
| public void reconfigure(boolean checkPortability, String... patterns) { |
| this.manager.reconfigure(checkPortability, patterns); |
| } |
| |
| /** |
| * Method implemented from <code>PdxSerializer</code> which performs object serialization. |
| * |
| * @param obj the object to serialize |
| * @param writer the <code>PdxWriter</code> to use when serializing this object |
| * @return <code>true</code> if the object was serialized, <code>false</code> otherwise |
| */ |
| @Override |
| public boolean toData(Object obj, PdxWriter writer) { |
| return manager.writeData(writer, obj); |
| } |
| |
| /** |
| * Method implemented from <code>PdxSerializer</code> which performs object de-serialization. |
| * |
| * @param clazz the class of the object to re-create |
| * @param reader the <code>PdxReader</code> to use when creating this object |
| * @return the deserialized object if this serializer handles the given class, null otherwise. |
| */ |
| @Override |
| public Object fromData(Class<?> clazz, PdxReader reader) { |
| return manager.readData(reader, clazz); |
| } |
| |
| /** |
| * Used for declarative class initialization from cache.xml. The following property may be |
| * specified: |
| * <ul> |
| * <li><b>classes</b> - a comma-delimited list of strings which represent the patterns used to |
| * select classes for serialization, patterns to select identity fields and patterns to exclude |
| * fields. See {@link ReflectionBasedAutoSerializer#reconfigure(String...) reconfigure} for |
| * specifics.</li> |
| * <li><b>check-portability</b> - if true then an exception will be thrown if an attempt to |
| * serialize data that is not portable to .NET is made. |
| * |
| * @param props properties used to configure the auto serializer |
| * @deprecated as of Geode 1.5 use initialize instead |
| */ |
| @Override |
| public void init(Properties props) { |
| this.manager.init(props); |
| } |
| |
| /** |
| * Used for declarative class initialization from cache.xml. The following property may be |
| * specified: |
| * <ul> |
| * <li><b>classes</b> - a comma-delimited list of strings which represent the patterns used to |
| * select classes for serialization, patterns to select identity fields and patterns to exclude |
| * fields. See {@link ReflectionBasedAutoSerializer#reconfigure(String...) reconfigure} for |
| * specifics.</li> |
| * <li><b>check-portability</b> - if true then an exception will be thrown if an attempt to |
| * serialize data that is not portable to .NET is made. |
| * |
| * @param cache the cache that owns this serializer |
| * @param props properties used to configure the auto serializer |
| * @since Geode 1.5 |
| */ |
| @Override |
| public void initialize(Cache cache, Properties props) { |
| this.manager.setRegionService(cache); |
| this.manager.init(props); |
| } |
| |
| /** |
| * Return a <code>Properties</code> object with a representation of the current config. Depending |
| * on how this <code>ReflectionBasedAutoSerializer</code> was configured, the returned property |
| * value will have the correct semantics but may differ from the the original configuration |
| * string. |
| * |
| * @return a <code>Properties</code> object |
| */ |
| public Properties getConfig() { |
| return this.manager.getConfig(); |
| } |
| |
| /** |
| * Controls what classes will be auto serialized by this serializer. Override this method to |
| * customize what classes will be auto serialized. |
| * <p> |
| * The default implementation: |
| * <ul> |
| * <li>only serializes classes whose name matches one of the patterns |
| * <li>excludes classes whose package begins with "org.apache.", "java.", or "javax." unless the |
| * system property "gemfire.auto.serialization.no.hardcoded.excludes" is set to "true". |
| * <li>excludes classes that do not have a public no-arg constructor |
| * <li>excludes enum classes |
| * <li>excludes classes that require standard java serialization. A class requires standard java |
| * serialization if it extends Externalizable or if it extends Serializable and has either a |
| * private writeObject method or a writeReplace method as defined by the java serialization |
| * specification. |
| * </ul> |
| * <p> |
| * This method is only called the first time it sees a new class. The result will be remembered |
| * and used the next time the same class is seen. |
| * |
| * @param clazz the class that is being considered for auto serialization. |
| * @return true if instances of the class should be auto serialized; false if not. |
| * @since GemFire 6.6.2 |
| */ |
| public boolean isClassAutoSerialized(Class<?> clazz) { |
| return this.manager.defaultIsClassAutoSerialized(clazz); |
| } |
| |
| /** |
| * Controls what fields of a class will be auto serialized by this serializer. Override this |
| * method to customize what fields of a class will be auto serialized. |
| * <p> |
| * The default implementation: |
| * <ul> |
| * <li>excludes transient fields |
| * <li>excludes static fields |
| * <li>excludes any fields that match an "#exclude=" pattern. |
| * </ul> |
| * All other fields are included. |
| * <p> |
| * This method is only called the first time it sees a new class. The result will be remembered |
| * and used the next time the same class is seen. |
| * |
| * @param f the field being considered for serialization |
| * @param clazz the original class being serialized that owns this field. Note that this field may |
| * have been inherited from a super class by this class. If you want to find the class that |
| * declared this field use {@link Field#getDeclaringClass()}. |
| * @return true if the field should be serialized as a pdx field; false if it should be ignored. |
| * @since GemFire 6.6.2 |
| */ |
| public boolean isFieldIncluded(Field f, Class<?> clazz) { |
| return this.manager.defaultIsFieldIncluded(f, clazz); |
| } |
| |
| /** |
| * Controls the field name that will be used in pdx for a field being auto serialized. Override |
| * this method to customize the field names that will be generated by auto serialization. It |
| * allows you to convert a local, language dependent name, to a more portable name. The returned |
| * name is the one that will show up in a {@link PdxInstance} and that one that will need to be |
| * used to access the field when doing a query. |
| * <p> |
| * The default implementation returns the name obtained from <code>f</code>. |
| * <p> |
| * This method is only called the first time it sees a new class. The result will be remembered |
| * and used the next time the same class is seen. |
| * |
| * @param f the field whose name is returned. |
| * @param clazz the original class being serialized that owns this field. Note that this field may |
| * have been inherited from a super class by this class. If you want to find the class that |
| * declared this field use {@link Field#getDeclaringClass()}. |
| * @return the name of the field |
| * @since GemFire 6.6.2 |
| */ |
| public String getFieldName(Field f, Class<?> clazz) { |
| return f.getName(); |
| } |
| |
| /** |
| * Controls what fields of a class that is auto serialized will be marked as pdx identity fields. |
| * Override this method to customize what fields of an auto serialized class will be identity |
| * fields. Identity fields are used when a {@link PdxInstance} computes its hash code and checks |
| * to see if it is equal to another object. |
| * <p> |
| * The default implementation only marks fields that match an "#identity=" pattern as identity |
| * fields. |
| * <p> |
| * This method is only called the first time it sees a new class. The result will be remembered |
| * and used the next time the same class is seen. |
| * |
| * @param f the field to test to see if it is an identity field. |
| * @param clazz the original class being serialized that owns this field. Note that this field may |
| * have been inherited from a super class by this class. If you want to find the class that |
| * declared this field use {@link Field#getDeclaringClass()}. |
| * @return true if the field should be marked as an identity field; false if not. |
| * @since GemFire 6.6.2 |
| */ |
| public boolean isIdentityField(Field f, Class<?> clazz) { |
| return this.manager.defaultIsIdentityField(f, clazz); |
| } |
| |
| /** |
| * Controls what pdx field type will be used when auto serializing. Override this method to |
| * customize what pdx field type will be used for a given domain class field. |
| * <p> |
| * The default implementation uses {@link FieldType#get(Class)} by passing it |
| * {@link Field#getType()}. |
| * <p> |
| * This method is only called the first time it sees a new class. The result will be remembered |
| * and used the next time the same class is seen. |
| * |
| * @param f the field whose pdx field type needs to be determined |
| * @param clazz the original class being serialized that owns this field. Note that this field may |
| * have been inherited from a super class by this class. If you want to find the class that |
| * declared this field use {@link Field#getDeclaringClass()}. |
| * @return the pdx field type of the given domain class field. |
| * @since GemFire 6.6.2 |
| */ |
| public FieldType getFieldType(Field f, Class<?> clazz) { |
| return this.manager.defaultGetFieldType(f, clazz); |
| } |
| |
| /** |
| * Controls if a pdx field's value can be transformed during serialization. Override this method |
| * to customize what fields can have their values transformed. If you return true then you need to |
| * also override {@link #writeTransform} and {@link #readTransform}. |
| * <p> |
| * The default implementation returns false. |
| * <p> |
| * This method is only called the first time it sees a new class. The result will be remembered |
| * and used the next time the same class is seen. |
| * |
| * @param f the field in question |
| * @param clazz the original class being serialized that owns this field. Note that this field may |
| * have been inherited from a super class by this class. If you want to find the class that |
| * declared this field use {@link Field#getDeclaringClass()}. |
| * @return true if the {@link #writeTransform} and {@link #readTransform} need to be called when |
| * serializing and deserializing this field's value. |
| * @since GemFire 6.6.2 |
| */ |
| public boolean transformFieldValue(Field f, Class<?> clazz) { |
| return false; |
| } |
| |
| /** |
| * Controls what field value is written during auto serialization. Override this method to |
| * customize the data that will be written during auto serialization. This method will only be |
| * called if {@link #transformFieldValue} returned true. |
| * |
| * @param f the field in question |
| * @param clazz the original class being serialized that owns this field. Note that this field may |
| * have been inherited from a super class by this class. If you want to find the class that |
| * declared this field use {@link Field#getDeclaringClass()}. |
| * @param originalValue the value of the field that was read from the domain object. |
| * @return the actual value to write for this field. Return <code>originalValue</code> if you |
| * decide not to transform the value. |
| * @since GemFire 6.6.2 |
| */ |
| public Object writeTransform(Field f, Class<?> clazz, Object originalValue) { |
| return originalValue; |
| } |
| |
| /** |
| * Controls what field value is read during auto deserialization. Override this method to |
| * customize the data that will be read during auto deserialization. This method will only be |
| * called if {@link #transformFieldValue} returned true. |
| * |
| * @param f the field in question |
| * @param clazz the original class being serialized that owns this field. Note that this field may |
| * have been inherited from a super class by this class. If you want to find the class that |
| * declared this field use {@link Field#getDeclaringClass()}. |
| * @param serializedValue the value of the field that was serialized for this field. |
| * @return the actual value to write for this field. Return <code>serializedValue</code> if you |
| * decide not to transform the value. |
| * @since GemFire 6.6.2 |
| */ |
| public Object readTransform(Field f, Class<?> clazz, Object serializedValue) { |
| return serializedValue; |
| } |
| |
| /** |
| * Returns the cache that this serializer is installed on. Returns null if it is not installed. |
| * |
| * @since GemFire 6.6.2 |
| */ |
| public RegionService getRegionService() { |
| return this.manager.getRegionService(); |
| } |
| |
| /** |
| * For internal use only. |
| * |
| * @since GemFire 8.2 |
| */ |
| public Object getManager() { |
| // The result is not AutoSerializableManager because |
| // that class is not part of our public APIs. |
| return this.manager; |
| } |
| } |