Package com.skaringa.javaxml.serializers

Source Code of com.skaringa.javaxml.serializers.SerializerRegistry

package com.skaringa.javaxml.serializers;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Hashtable;
import java.util.Map;

import org.xml.sax.Attributes;

import com.skaringa.javaxml.DeserializerException;

/**
* Registry that holds the serializers.
* It is implemented using the singleton pattern.
*/
public final class SerializerRegistry {

  private static SerializerRegistry _theRegistry;
  private Map _serializers = new Hashtable();
  private Map _deserializers = new Hashtable();

  static {
    _theRegistry = new SerializerRegistry();
  }

  /**
   * Get the one instance of the SerializerRegistry.
   * @return The SerializerRegistry.
   */
  public static SerializerRegistry getInstance() {
    return _theRegistry;
  }

  /**
   * Construct a SerializerRegistry.
   * Bootstrap all known serializers.
   */
  private SerializerRegistry() {
    // primitive types
    bootstrapPrimitiveTypes();

    // wrappers
    bootstrapWrappers();

    // string and date
    bootstrapStringAndDate();

    // Set types
    bootstrapSets();

    // collection types
    bootstrapCollections();

    // map types
    bootstrapMaps();

    // java.math
    addSerializer(
      BigDecimal.class.getName(),
      new PrimitiveTypeSerializer("xsd:decimal", BigDecimal.class));
    addSerializer(
      BigInteger.class.getName(),
      new PrimitiveTypeSerializer("xsd:integer", BigInteger.class));

    // java.util.Locale
    addSerializer(
      java.util.Locale.class.getName(),
      new LocaleSerializer(java.util.Locale.class.getName()));

    bootstrapOtherTypes();
  }

  /**
   * These are types that Skaringa will not use during
   * serialization (for the most part they're specialized
   * versions and Skaringa will use the more general versions).
   * however, we might see them during deserialization so we
   * hook them into the deserializer.
   */
  private void bootstrapOtherTypes() {
    _deserializers.put(
      "xsd:nonPositiveInteger",
      new PrimitiveTypeSerializer("xsd:nonPositiveInteger", Integer.class));
    _deserializers.put(
      "xsd:nonNegativeInteger",
      new PrimitiveTypeSerializer("xsd:nonNegativeInteger", Integer.class));
    _deserializers.put(
      "xsd:positiveInteger",
      new PrimitiveTypeSerializer("xsd:positiveInteger", Integer.class));
    _deserializers.put(
      "xsd:negativeInteger",
      new PrimitiveTypeSerializer("xsd:negativeInteger", Integer.class));
    _deserializers.put(
      "xsd:unsignedLong",
      new PrimitiveTypeSerializer("xsd:unsignedLong", Long.class));
    _deserializers.put(
      "xsd:unsignedInt",
      new PrimitiveTypeSerializer("xsd:unsignedInt", Integer.class));
    _deserializers.put(
      "xsd:unsignedShort",
      new PrimitiveTypeSerializer("xsd:unsignedShort", Short.class));
    _deserializers.put(
      "xsd:unsignedByte",
      new PrimitiveTypeSerializer("xsd:unsignedByte", Byte.class));
    _deserializers.put("xsd:date", new DateSerializer("xsd:date"));
  }

  /**
   * Map and subtypes.
   *
   */
  private void bootstrapMaps() {
    addSerializer(
      java.util.Map.class.getName(),
      new MapSerializer(java.util.Map.class.getName()));
    addSerializer(
      java.util.SortedMap.class.getName(),
      new MapSerializer(java.util.SortedMap.class.getName()));
    addSerializer(
      java.util.AbstractMap.class.getName(),
      new MapSerializer(java.util.AbstractMap.class.getName()));
    addSerializer(
      java.util.HashMap.class.getName(),
      new MapSerializer(java.util.HashMap.class.getName()));
    addSerializer(
      java.util.Hashtable.class.getName(),
      new MapSerializer(java.util.Hashtable.class.getName()));
    addSerializer(
      java.util.WeakHashMap.class.getName(),
      new MapSerializer(java.util.WeakHashMap.class.getName()));
    addSerializer(
      java.util.TreeMap.class.getName(),
      new MapSerializer(java.util.TreeMap.class.getName()));
    addSerializer(
      java.util.Properties.class.getName(),
      new MapSerializer(java.util.Properties.class.getName()));

    // map entry
    addSerializer(
      java.util.Map.Entry.class.getName(),
      new MapEntrySerializer());
  }

  /**
   * Collection and subtypes without Sets.
   *
   */
  private void bootstrapCollections() {
    addSerializer(
      java.util.Collection.class.getName(),
      new CollectionSerializer(java.util.Collection.class.getName()));
    addSerializer(
      java.util.List.class.getName(),
      new CollectionSerializer(java.util.List.class.getName()));
    addSerializer(
      java.util.AbstractCollection.class.getName(),
      new CollectionSerializer(java.util.AbstractCollection.class.getName()));
    addSerializer(
      java.util.AbstractList.class.getName(),
      new CollectionSerializer(java.util.AbstractList.class.getName()));
    addSerializer(
      java.util.AbstractSequentialList.class.getName(),
      new CollectionSerializer(
        java.util.AbstractSequentialList.class.getName()));
    addSerializer(
      java.util.ArrayList.class.getName(),
      new CollectionSerializer(java.util.ArrayList.class.getName()));
    addSerializer(
      java.util.LinkedList.class.getName(),
      new CollectionSerializer(java.util.LinkedList.class.getName()));
    addSerializer(
      java.util.Stack.class.getName(),
      new CollectionSerializer(java.util.Stack.class.getName()));
    addSerializer(
      java.util.Vector.class.getName(),
      new CollectionSerializer(java.util.Vector.class.getName()));
  }

  /**
   * Set and subtypes.
   *
   */
  private void bootstrapSets() {
    addSerializer(
      java.util.Set.class.getName(),
      new SetSerializer(java.util.Set.class.getName()));
    addSerializer(
      java.util.SortedSet.class.getName(),
      new SetSerializer(java.util.SortedSet.class.getName()));
    addSerializer(
      java.util.AbstractSet.class.getName(),
      new SetSerializer(java.util.AbstractSet.class.getName()));
    addSerializer(
      java.util.BitSet.class.getName(),
      new SetSerializer(java.util.BitSet.class.getName()));
    addSerializer(
      java.util.HashSet.class.getName(),
      new SetSerializer(java.util.HashSet.class.getName()));
    addSerializer(
      java.util.TreeSet.class.getName(),
      new SetSerializer(java.util.TreeSet.class.getName()));
  }

  /**
   * String and Date
   *
   */
  private void bootstrapStringAndDate() {
    addSerializer(
      String.class.getName(),
      new PrimitiveTypeSerializer("xsd:string", String.class));
    addSerializer(java.util.Date.class.getName(), new DateSerializer());
  }

  /**
   * Wrappers around primitive types.
   *
   */
  private void bootstrapWrappers() {
    addSerializer(
      Integer.class.getName(),
      new PrimitiveTypeSerializer("xsd:int", Integer.class));
    addSerializer(
      Long.class.getName(),
      new PrimitiveTypeSerializer("xsd:long", Long.class));
    addSerializer(
      Short.class.getName(),
      new PrimitiveTypeSerializer("xsd:short", Short.class));
    addSerializer(
      Byte.class.getName(),
      new PrimitiveTypeSerializer("xsd:byte", Byte.class));
    addSerializer(
      Float.class.getName(),
      new PrimitiveTypeSerializer("xsd:float", Float.class));
    addSerializer(
      Double.class.getName(),
      new PrimitiveTypeSerializer("xsd:double", Double.class));
    addSerializer(
      Character.class.getName(),
      new PrimitiveTypeSerializer("char", Character.class));
    addSerializer(
      Boolean.class.getName(),
      new PrimitiveTypeSerializer("xsd:boolean", Boolean.class));
  }

  /**
   * Primitive types.
   *
   */
  private void bootstrapPrimitiveTypes() {
    addSerializer(
      int.class.getName(),
      new PrimitiveTypeSerializer("xsd:int", Integer.class));
    addSerializer(
      long.class.getName(),
      new PrimitiveTypeSerializer("xsd:long", Long.class));
    addSerializer(
      short.class.getName(),
      new PrimitiveTypeSerializer("xsd:short", Short.class));
    addSerializer(
      byte.class.getName(),
      new PrimitiveTypeSerializer("xsd:byte", Byte.class));
    addSerializer(
      float.class.getName(),
      new PrimitiveTypeSerializer("xsd:float", Float.class));
    addSerializer(
      double.class.getName(),
      new PrimitiveTypeSerializer("xsd:double", Double.class));
    addSerializer(
      char.class.getName(),
      new PrimitiveTypeSerializer("char", Character.class));
    addSerializer(
      boolean.class.getName(),
      new PrimitiveTypeSerializer("xsd:boolean", Boolean.class));
  }

  /**
   * Add a serializer to the registry.
   * @param className The name of the class which should be handled by the
   * serializer.
   * @param ser The serializer.
   */
  public void addSerializer(String className, ComponentSerializer ser) {
    _serializers.put(className, ser);
    _deserializers.put(ser.getXMLTypeName(), ser);
  }

  /**
   * Get a serializer for a type.
   * @param type The type.
   * @return The serializer.
   */
  public ComponentSerializer getSerializer(Class type) {

    String typeStr = type.getName();

    ComponentSerializer ser = (ComponentSerializer) _serializers.get(typeStr);
    if (ser == null) {
      // no serializer found

      // check for array
      if (type.isArray()) {
        ser = new ArraySerializer(type);
        addSerializer(typeStr, ser);
      }
      else {
        ser = getAndRegisterType(type, typeStr);
      }
    }

    return ser;
  }

  /**
   * Get and register serializers for types unknown by this registry.
   * @param type The type of the object to (de)serialize.
   * @param typeStr The XML type string to register the type with.
   * @return The serializer.
   */
  private ComponentSerializer getAndRegisterType(Class type, String typeStr) {
    ComponentSerializer ser;
    // check for subtypes of map, collection, and set
    if (java.util.Map.class.isAssignableFrom(type)) {
      ser = new MapSerializer(typeStr);
      addSerializer(typeStr, ser);
    }
    else if (java.util.Set.class.isAssignableFrom(type)) {
      ser = new SetSerializer(typeStr);
      addSerializer(typeStr, ser);
    }
    else if (java.util.Collection.class.isAssignableFrom(type)) {
      ser = new CollectionSerializer(typeStr);
      addSerializer(typeStr, ser);
    }
    else {
      // use and register new object serializer
      ser = new ObjectSerializer(typeStr);
      addSerializer(typeStr, ser);
    }
    return ser;
  }

  /**
   * Get a deserializer for an xml element.
   * This is done by evaluating the xsi:type attribute.
   * @param elementName The name of the element.
   * @param attrs The attributes of the element.
   * @param classLoader The class loader used to load new classes.
   * @return The deserializer.
   * @throws DeserializerException If the deserializer can't be found.
   */
  public ComponentSerializer getDeserializer(
    String elementName,
    Attributes attrs,
    ClassLoader classLoader)
    throws DeserializerException {

    String xmlType = attrs.getValue("xsi:type");
    if (xmlType == null) {
      throw new DeserializerException(
        "Element " + elementName + " missing xsi:type attribute");
    }

    ComponentSerializer ser = (ComponentSerializer) _deserializers.get(xmlType);
    if (ser == null) {
      // handle arrays
      if (xmlType.startsWith(ArraySerializer.TYPENAME_PREFIX)) {
        ser = new ArraySerializer(xmlType);
        addSerializer(xmlType, ser);
      }
      else {
        // no serializer found - use and register new serializer
        try {
          Class c =
            Class.forName(
              ObjectSerializer.fixJavaTypeNameForInnerClass(xmlType),
              true,
              classLoader);
          ser = getAndRegisterType(c, xmlType);
        }
        catch (ClassNotFoundException e) {
          throw new DeserializerException(
            "class not found: "
              + ObjectSerializer.fixJavaTypeNameForInnerClass(xmlType));
        }
      }
    }

    return ser;
  }

  /**
   * Try to find a deserializer if no xsi:type attribute is available.
   * This is done by examining the class definition of the parent.
   * @param parent The parent object.
   * @param elementName The name of the element.
   * @return The deserializer.
   * @throws DeserializerException If the deserializer can't be found.
   */
  public ComponentSerializer findDeserializer(
    Object parent,
    String elementName)
    throws DeserializerException {

    Class c = null;
    if (parent != null) {
      // parent available
      if (parent instanceof ArrayHelper) {
        // parent is array
        c = ((ArrayHelper) parent).getComponentType();
      }
      else if (elementName != null){
        // look if the parent has a field with name "elementName"
        c = ObjectSerializer.getFieldType(parent, elementName);
      }
    }
    if (c == null && elementName != null) {
      // possibly a root element - then its name should be the classname
      try {
        c =
          Class.forName(
            ObjectSerializer.fixJavaTypeNameForInnerClass(elementName));
      }
      catch (ClassNotFoundException ex) {
        // c remains null
      }
    }

    if (c == null) {
      throw new DeserializerException(
        "can't determine java type for element: " + elementName);
    }

    return getSerializer(c);
    // we must call getSerializer() here instead of getDeserializer(),
    // because we have the JAVA type and not the XML type string!
  }

  /**
   * Guess the deserializer for a number.
   *
   * @param s
   *          The number as String.
   * @return The deserializer.
   * @throws DeserializerException
   *           If the argument is not a number.
   */
  public ComponentSerializer guessDeserializerForNumber(String s)
      throws DeserializerException {
    try {
      Integer.parseInt(s);
      return getSerializer(Integer.class);
    } catch (NumberFormatException e) {
    }
    try {
      Long.parseLong(s);
      return getSerializer(Long.class);
    } catch (NumberFormatException e) {
    }
    try {
      Double.parseDouble(s);
      return getSerializer(Double.class);
    } catch (NumberFormatException e) {
    }
    try {
      new BigInteger(s);
      return getSerializer(BigInteger.class);
    } catch (NumberFormatException e) {
    }
    try {
      new BigDecimal(s);
      return getSerializer(BigDecimal.class);
    } catch (NumberFormatException e) {
    }
    throw new DeserializerException("Not a number: " + s);
  }

}
TOP

Related Classes of com.skaringa.javaxml.serializers.SerializerRegistry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.