Package com.skaringa.javaxml.serializers

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

package com.skaringa.javaxml.serializers;

import java.io.PrintStream;
import java.lang.reflect.Array;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;

import org.xml.sax.Attributes;

import com.skaringa.javaxml.DeserializerException;
import com.skaringa.javaxml.SerializerException;
import com.skaringa.javaxml.handler.DocumentOutputHandlerInterface;

/**
* Implementation of ComponentSerializer for arrays.
*/
public final class ArraySerializer extends AbstractSerializer {

  /**
   * Type code prefix for arrays.
   */
  static final String TYPENAME_PREFIX = "array";

  private String _xmlTypeName;
  private Class _type;
  private Class _componentType;

  /**
   * Construct an array serializer for a given array class.
   * @param type The type of the array.
   */
  ArraySerializer(Class type) {
    _type = type;
    _componentType = type.getComponentType();
    computeXMLTypeName();
  }

  /**
   * Construct an array deserializer for a given XML type.
   * @param xmlTypeName The XML type name of the array.
   * @throws DeserializerException If xmlTypeName is not valid.
   */
  ArraySerializer(String xmlTypeName) throws DeserializerException {
    _xmlTypeName = xmlTypeName;
    // defer the determination of component type to startDeserialize
    // (because of using user class loader).
  }

  /**
   * @see ComponentSerializer#serialize(Object, Class, String, Map, Map, DocumentOutputHandlerInterface)
   */
  public void serialize(
    Object obj,
    Class type,
    String name,
    Map propertyMap,
    Map objectIdMap,
    DocumentOutputHandlerInterface output)
    throws SerializerException {

    startElement(obj, _xmlTypeName, name, propertyMap, output);
    if (obj != null) {
      int len = java.lang.reflect.Array.getLength(obj);
      for (int j = 0; j < len; ++j) {
        Object comp = java.lang.reflect.Array.get(obj, j);
        Class fieldType = (comp == null) ? _componentType : comp.getClass();
        ComponentSerializer ser =
          SerializerRegistry.getInstance().getSerializer(fieldType);
        ser.serialize(comp, fieldType, "el", propertyMap, objectIdMap, output);
      }
    }
    output.endElement(name);
  }

  /**
   * @see ComponentSerializer#getXMLTypeName()
   */
  public String getXMLTypeName() {
    return _xmlTypeName;
  }

  /**
   * @see ComponentSerializer#startDeserialize(String, Attributes, Object, Stack, ClassLoader)
   */
  public Object startDeserialize(
    String name,
    Attributes attrs,
    Object parent,
    Stack objStack,
    ClassLoader classLoader)
    throws DeserializerException {

    Vector helperVector = null;
    String nullAttr = attrs.getValue("xsi:nil");
    if (nullAttr == null || nullAttr.equals("false")) {
      helperVector = new Vector();
    }

    if (_type == null) {
      try {
        computeType(classLoader);
        _componentType = _type.getComponentType();
      }
      catch (DeserializerException ex) {
        if (!TYPENAME_PREFIX.equals(_xmlTypeName)) {
          throw ex;
        }
      }
    }

    Class componentType = _componentType;
    if (componentType == null && TYPENAME_PREFIX.equals(_xmlTypeName)) {
      // try to get the component type from the parent
      // this is for backward compatibility (typename was "array" only)
      componentType = getFieldType(parent, name).getComponentType();
      if (componentType == null) {
        throw new DeserializerException(
          "Can't get component type for: " + _xmlTypeName);
      }
    }

    return new ArrayHelper(helperVector, componentType);
  }

  /**
   * @see ComponentSerializer#setMember(Object, String, Object)
   */
  public void setMember(Object parent, String name, Object value)
    throws DeserializerException {


    checkSequence(parent);
    ArrayHelper helper = (ArrayHelper) parent;

    if (helper.getVector() == null) {
      throw new DeserializerException("child of null object is forbidden");
    }

    helper.add(value);
  }

  /**
   * @see ComponentSerializer#endDeserialize(Object, String)
   */
  public Object endDeserialize(Object obj, String text)
    throws DeserializerException {

    checkSequence(obj);
    ArrayHelper helper = (ArrayHelper) obj;

    return helper.getArray();
  }

  /**
   * Check if an object is of type ArrayHelper.
   * @param obj The object to check.
   * @throws DeserializerException If the object is not of type ArrayHelper.
   */
  private void checkSequence(Object obj) throws DeserializerException {
    if (!(obj instanceof ArrayHelper)) {
      throw new DeserializerException(
        "invalid sequence: array expected, but was: "
          + obj.getClass().getName());
    }
  }

  /**
   * @see com.skaringa.javaxml.serializers.ComponentSerializer#writeXMLTypeDefinition(Class, Map, DocumentOutputHandlerInterface)
   */
  public void writeXMLTypeDefinition(
    Class type,
    Map propertyMap,
    DocumentOutputHandlerInterface output)
    throws SerializerException {

    writeXMLCollectionDef("el", _componentType, output);
  }

  /**
   * @see ComponentSerializer#addUsedClasses(Class, Set)
   */
  public void addUsedClasses(Class base, Set usedClasses)
    throws SerializerException {

    usedClasses.add(base);
    if (_componentType != null) {
      ComponentSerializer ser =
        SerializerRegistry.getInstance().getSerializer(_componentType);
      ser.addUsedClasses(_componentType, usedClasses);
    }
  }

  /**
   * Compute the XML type name from the Java type.
   */
  private void computeXMLTypeName() {
    String javaTypeName = _type.getName();
    StringBuffer xmlTypeName = new StringBuffer(TYPENAME_PREFIX);
    int dim = 0;
    int i = 0;

    while (javaTypeName.charAt(i) == '[') {
      ++i;
      ++dim;
    }

    if (dim > 1) {
      xmlTypeName.append(dim);
    }

    xmlTypeName.append("_of_");

    switch (javaTypeName.charAt(i)) {
      case 'B' :
        xmlTypeName.append("byte");
        break;
      case 'C' :
        xmlTypeName.append("char");
        break;
      case 'D' :
        xmlTypeName.append("double");
        break;
      case 'F' :
        xmlTypeName.append("float");
        break;
      case 'I' :
        xmlTypeName.append("int");
        break;
      case 'J' :
        xmlTypeName.append("long");
        break;
      case 'S' :
        xmlTypeName.append("short");
        break;
      case 'Z' :
        xmlTypeName.append("boolean");
        break;
      case 'L' :
        computeXMLTypeNameForObject(javaTypeName, xmlTypeName, i);
        break;
      default :
        throw new RuntimeException("FATAL: unknown array type string");
    }

    _xmlTypeName = xmlTypeName.toString();
  }

  /**
   * Compute the XML type name from the special
   * Java array type string of objects.
   * @param javaTypeName The Java array type name.
   * @param xmlTypeName A buffer to append the XML type name to.
   * @param lpos The position of the 'L' in javaTypeName.
   */
  private void computeXMLTypeNameForObject(
    String javaTypeName,
    StringBuffer xmlTypeName,
    int lpos) {
    int j = ++lpos;
    while (javaTypeName.charAt(j) != ';') {
      ++j;
    }
    xmlTypeName.append(
      ObjectSerializer.fixXMLTypeNameForInnerClass(
        javaTypeName.substring(lpos, j)));
  }

  /**
   * Compute the Java type from the XML type name.
   * @param classLoader The class loader used to load the array components.
   * @throws DeserializerException If the XML type name is not a valid name
   * for an array.
   */
  private void computeType(ClassLoader classLoader) throws DeserializerException {

    if (!_xmlTypeName.startsWith(TYPENAME_PREFIX)) {
      throw new DeserializerException(
        "Invalid array type name prefix: " + _xmlTypeName);
    }
    String compTypeName = null;

    try {
      int i = TYPENAME_PREFIX.length();
      int s = i;

      // dimension
      while (_xmlTypeName.charAt(i) != '_') {
        ++i;
      }
      int dim;
      if (s == i) {
        dim = 1;
      }
      else {
        dim = Integer.parseInt(_xmlTypeName.substring(s, i));
      }
      int[] dimensions = new int[dim];

      // _of_
      s = i;
      i = s + "_of_".length();
      if (!_xmlTypeName.substring(s, i).equals("_of_")) {
        throw new DeserializerException(
          "Invalid array type name: _of_ expected: "
            + _xmlTypeName.substring(s, i));
      }

      // component type name
      compTypeName = _xmlTypeName.substring(i);

      Class compType;
      if (compTypeName.equals("byte")) {
        compType = byte.class;
      }
      else if (compTypeName.equals("char")) {
        compType = char.class;
      }
      else if (compTypeName.equals("double")) {
        compType = double.class;
      }
      else if (compTypeName.equals("float")) {
        compType = float.class;
      }
      else if (compTypeName.equals("int")) {
        compType = int.class;
      }
      else if (compTypeName.equals("long")) {
        compType = long.class;
      }
      else if (compTypeName.equals("short")) {
        compType = short.class;
      }
      else if (compTypeName.equals("boolean")) {
        compType = boolean.class;
      }
      else {
        compType =
          Class.forName(
            ObjectSerializer.fixJavaTypeNameForInnerClass(compTypeName),
            true,
            classLoader);
      }
      Object array = Array.newInstance(compType, dimensions);

      _type = array.getClass();
    }
    catch (ClassNotFoundException ex) {
      throw new DeserializerException(
        "can't get java class for: " + compTypeName + ": " + ex.toString());
    }
    catch (StringIndexOutOfBoundsException ex) {
      throw new DeserializerException(
        "Invalid array type name: " + _xmlTypeName);
    }
  }

  /**
   * @see CollectionSerializer#toJson(Object, Class, Map, PrintStream)
   */
  public void toJson(Object obj, Class type, Map propertyMap,
      PrintStream output) throws SerializerException {
    if (obj == null) {
      output.print("null");
    } else {
      output.print("[");
      int len = java.lang.reflect.Array.getLength(obj);
      for (int j = 0; j < len; ++j) {
        Object comp = java.lang.reflect.Array.get(obj, j);
        Class fieldType = (comp == null) ? _componentType : comp.getClass();
        ComponentSerializer ser =
          SerializerRegistry.getInstance().getSerializer(fieldType);
        ser.toJson(comp, fieldType, propertyMap, output);
        if (j < len - 1) {
          output.print(",");
        }
      }
      output.print("]");
    }
  }
 
 
}
TOP

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

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.