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

com.gemstone.gemfire.pdx.ReflectionBasedAutoSerializer 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;

import com.gemstone.gemfire.cache.Declarable;
import com.gemstone.gemfire.cache.RegionService;
import com.gemstone.gemfire.pdx.internal.AutoSerializableManager;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

/**
 * This class uses Java reflection in conjunction with
 * {@link com.gemstone.gemfire.pdx.PdxSerializer PdxSerialzer} to perform
 * automatic serialization of domain objects. The implication is that the domain
 * classes do not need to implement the PdxSerializable interface.
 * 

* This implementation will serialize all relevant fields *

* For example: * *

 * Cache c = new CacheFactory().set("cache-xml-file", cacheXmlFileName)
 *     .setPdxSerializer(new ReflectionBasedAutoSerializer("com.foo.DomainObject"))
 *     .create();
 * 
*

* In this example DomainObject would not need to implement * PdxSerializable to be serialized. *

* The equivalent cache.xml entries might be as follows: * *

 * <pdx>
 *   <pdx-serializer>
 *     <class-name>
 *       com.gemstone.gemfire.pdx.ReflectionBasedAutoSerializer
 *     </class-name>
 *     <parameter name="classes">
 *       <string> com.company.domain.DomainObject </string>
 *     </parameter>
 *   </pdx-serializer>
 * </pdx>
 * 
* See {@link ReflectionBasedAutoSerializer#reconfigure(String...) reconfigure} * for additional details on the format of the parameter string. * * @since 6.6 * @author jens * @author darrel */ 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. *

* Each string in the list represents a definition in the following form: *

   *   <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern>
   * 
* The hash (#) characters are separators and are not part of the parameter * name. An example would be: *
   *   com.company.DomainObject.*#identity=id.*#exclude=creationDate
   * 
* This would select all classes with a class name beginning with com.company.DomainObject * and would select as PDX identity fields any fields beginning with id * and would not serialize the field called creationDate. *

* There is no association between the the identity and exclude * options, so the above example could also be expressed as: *

   *   com.company.DomainObject.*#identity=id.*
   *   com.company.DomainObject.*#exclude=creationDate
   * 
* * Note that all 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 classes) { this(listToArray(classes)); } private static String[] listToArray(List l) { if (l == null) { l = Collections.emptyList(); } return l.toArray(new String[l.size()]); } /** * Constructor which takes a list of class name patterns which are to be * auto-serialized. Portability of serialization will not be checked. *

* Each string in the list represents a definition in the following form: *

   *   <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern>
   * 
* The hash (#) characters are separators and are not part of the parameter * name. An example would be: *
   *   com.company.DomainObject.*#identity=id.*#exclude=creationDate
   * 
* This would select all classes with a class name beginning with com.company.DomainObject * and would select as PDX identity fields any fields beginning with id * and would not serialize the field called creationDate. *

* There is no association between the the identity and exclude * options, so the above example could also be expressed as: *

   *   com.company.DomainObject.*#identity=id.*
   *   com.company.DomainObject.*#exclude=creationDate
   * 
* * Note that all 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 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. *

* Each string in the list represents a definition in the following form: *

   *   <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern>
   * 
* The hash (#) characters are separators and are not part of the parameter * name. An example would be: *
   *   com.company.DomainObject.*#identity=id.*#exclude=creationDate
   * 
* This would select all classes with a class name beginning with com.company.DomainObject * and would select as PDX identity fields any fields beginning with id * and would not serialize the field called creationDate. *

* There is no association between the the identity and exclude * options, so the above example could also be expressed as: *

   *   com.company.DomainObject.*#identity=id.*
   *   com.company.DomainObject.*#exclude=creationDate
   * 
* * Note that all 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 true 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 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. *

* Each string in the list represents a definition in the following form: *

   *   <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern>
   * 
* The hash (#) characters are separators and are not part of the parameter * name. An example would be: *
   *   com.company.DomainObject.*#identity=id.*#exclude=creationDate
   * 
* This would select all classes with a class name beginning with com.company.DomainObject * and would select as PDX identity fields any fields beginning with id * and would not serialize the field called creationDate. *

* There is no association between the the identity and exclude * options, so the above example could also be expressed as: *

   *   com.company.DomainObject.*#identity=id.*
   *   com.company.DomainObject.*#exclude=creationDate
   * 
* * Note that all 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 final void setSerializableClasses(List patterns) { reconfigure(listToArray(patterns)); } /** * Method to reconfigure this serializer. Any previous configuration is cleared. * The serializer will not check for portable serialization. *

* Each string in the list represents a definition in the following form: *

   *   <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern>
   * 
* The hash (#) characters are separators and are not part of the parameter * name. An example would be: *
   *   com.company.DomainObject.*#identity=id.*#exclude=creationDate
   * 
* This would select all classes with a class name beginning with com.company.DomainObject * and would select as PDX identity fields any fields beginning with id * and would not serialize the field called creationDate. *

* There is no association between the the identity and exclude * options, so the above example could also be expressed as: *

   *   com.company.DomainObject.*#identity=id.*
   *   com.company.DomainObject.*#exclude=creationDate
   * 
* * Note that all 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 6.6.2 */ public final void reconfigure(String... patterns) { reconfigure(false, patterns); } /** * Method to reconfigure this serializer. Any previous configuration is cleared. *

* Each string in the list represents a definition in the following form: *

   *   <class pattern>#identity=<identity field pattern>#exclude=<exclude field pattern>
   * 
* The hash (#) characters are separators and are not part of the parameter * name. An example would be: *
   *   com.company.DomainObject.*#identity=id.*#exclude=creationDate
   * 
* This would select all classes with a class name beginning with com.company.DomainObject * and would select as PDX identity fields any fields beginning with id * and would not serialize the field called creationDate. *

* There is no association between the the identity and exclude * options, so the above example could also be expressed as: *

   *   com.company.DomainObject.*#identity=id.*
   *   com.company.DomainObject.*#exclude=creationDate
   * 
* * Note that all 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 true then an serialization done by * this serializer will throw an exception if the object it not portable to * non-java languages. * @since 6.6.2 */ public final void reconfigure(boolean checkPortability, String... patterns) { this.manager.reconfigure(checkPortability, patterns); } /** * Method implemented from PdxSerializer which performs object * serialization. * * @param obj * the object to serialize * @param writer * the PdxWriter to use when serializing this object * @return true if the object was serialized, false * otherwise */ public boolean toData(Object obj, PdxWriter writer) { return manager.writeData(writer, obj); } /** * Method implemented from PdxSerializer which performs object * de-serialization. * * @param clazz * the class of the object to re-create * @param reader * the PdxReader to use when creating this object * @return the deserialized object if this serializer handles the given class, * null otherwise. */ 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: *
    *
  • classes - 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. *
  • *
  • check-portability - 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 */ public void init(Properties props) { this.manager.init(props); } /** * Return a Properties object with a representation of the * current config. Depending on how this ReflectionBasedAutoSerializer * was configured, the returned property value will have the correct semantics * but may differ from the the original configuration string. * * @return a Properties 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. *

    * The default implementation: *

      *
    • only serializes classes whose name matches one of the patterns *
    • excludes classes whose package begins with "com.gemstone.", "java.", or "javax." * unless the system property "gemfire.auto.serialization.no.hardcoded.excludes" * is set to "true". *
    • excludes classes that do not have a public no-arg constructor *
    • excludes enum classes *
    • 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. *
    *

    * 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 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. *

    * The default implementation: *

      *
    • excludes transient fields *
    • excludes static fields *
    • excludes any fields that match an "#exclude=" pattern. *
    * All other fields are included. *

    * 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 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. *

    * The default implementation returns the name obtained from f. *

    * 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 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. *

    * The default implementation only marks fields that match an "#identity=" pattern * as identity fields. *

    * 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 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. *

    * The default implementation uses {@link FieldType#get(Class)} * by passing it {@link Field#getType()}. *

    * 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 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}. *

    * The default implementation returns false. *

    * 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 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 originalValue * if you decide not to transform the value. * @since 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 serializedValue * if you decide not to transform the value. * @since 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 6.6.2 */ public final RegionService getRegionService() { return this.manager.getRegionService(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy