1 package de.timroes.axmlrpc.serializer; 2 3 import de.timroes.axmlrpc.XMLRPCClient; 4 import de.timroes.axmlrpc.XMLRPCException; 5 import de.timroes.axmlrpc.XMLUtil; 6 import de.timroes.axmlrpc.xmlcreator.XmlElement; 7 import java.math.BigDecimal; 8 import java.util.Calendar; 9 import java.util.Date; 10 import java.util.Map; 11 import org.w3c.dom.Element; 12 13 /** 14 * The serializer handler serializes and deserializes objects. 15 * It takes an object, determine its type and let the responsible handler serialize it. 16 * For deserialization it looks at the xml tag around the element. 17 * 18 * @author Tim Roes 19 */ 20 public class SerializerHandler { 21 22 public static final String TYPE_STRING = "string"; 23 public static final String TYPE_BOOLEAN = "boolean"; 24 public static final String TYPE_INT = "int"; 25 public static final String TYPE_INT2 = "i4"; 26 public static final String TYPE_LONG = "i8"; 27 public static final String TYPE_DOUBLE = "double"; 28 public static final String TYPE_DATETIME = "dateTime.iso8601"; 29 public static final String TYPE_STRUCT = "struct"; 30 public static final String TYPE_ARRAY = "array"; 31 public static final String TYPE_BASE64 = "base64"; 32 public static final String TYPE_NULL = "nil"; 33 34 private StringSerializer string; 35 private BooleanSerializer bool = new BooleanSerializer(); 36 private IntSerializer integer = new IntSerializer(); 37 private LongSerializer long8 = new LongSerializer(); 38 private StructSerializer struct; 39 private DoubleSerializer floating = new DoubleSerializer(); 40 private DateTimeSerializer datetime; 41 private ArraySerializer array; 42 private Base64Serializer base64 = new Base64Serializer(); 43 private NullSerializer nil = new NullSerializer(); 44 45 private int flags; 46 SerializerHandler()47 public SerializerHandler(){ 48 this(XMLRPCClient.FLAGS_DEBUG); 49 } 50 SerializerHandler(int flags)51 public SerializerHandler(int flags) { this(flags, DateTimeSerializer.DEFAULT_DATETIME_FORMAT); } 52 SerializerHandler(int flags, String datetimeFormat)53 public SerializerHandler(int flags, String datetimeFormat) { 54 this.flags = flags; 55 string = new StringSerializer( 56 (flags & XMLRPCClient.FLAGS_NO_STRING_ENCODE) == 0, 57 (flags & XMLRPCClient.FLAGS_NO_STRING_DECODE) == 0 58 ); 59 struct = new StructSerializer(this); 60 array = new ArraySerializer(this); 61 boolean accepts_null_input = (flags & XMLRPCClient.FLAGS_ACCEPT_NULL_DATES) != 0; 62 datetime = new DateTimeSerializer(accepts_null_input, datetimeFormat); 63 } 64 65 /** 66 * Deserializes an incoming xml element to an java object. 67 * The xml element must be the value element around the type element. 68 * The type of the returning object depends on the type tag. 69 * 70 * @param element An type element from within a value tag. 71 * @return The deserialized object. 72 * @throws XMLRPCException Will be thrown whenever an error occurs. 73 */ deserialize(Element element)74 public Object deserialize(Element element) throws XMLRPCException { 75 76 if(!XMLRPCClient.VALUE.equals(element.getNodeName())) { 77 throw new XMLRPCException("Value tag is missing around value."); 78 } 79 80 if(!XMLUtil.hasChildElement(element.getChildNodes())) { 81 // Value element doesn't contain a child element 82 if((flags & XMLRPCClient.FLAGS_DEFAULT_TYPE_STRING) != 0) { 83 return string.deserialize(element); 84 } else { 85 throw new XMLRPCException("Missing type element inside of value element."); 86 } 87 } 88 89 // Grep type element from inside value element 90 Element childElement = XMLUtil.getOnlyChildElement(element.getChildNodes()); 91 92 Serializer s; 93 94 String type; 95 96 // If FLAGS_IGNORE_NAMESPACE has been set, only use local name. 97 if((flags & XMLRPCClient.FLAGS_IGNORE_NAMESPACES) != 0) { 98 type = childElement.getLocalName() == null ? childElement.getNodeName() : childElement.getLocalName(); 99 } else { 100 type = childElement.getNodeName(); 101 } 102 103 if((flags & XMLRPCClient.FLAGS_NIL) != 0 && TYPE_NULL.equals(type)) { 104 s = nil; 105 } else if(TYPE_STRING.equals(type)) { 106 s = string; 107 } else if(TYPE_BOOLEAN.equals(type)) { 108 s = bool; 109 } else if(TYPE_DOUBLE.equals(type)) { 110 s = floating; 111 } else if (TYPE_INT.equals(type) || TYPE_INT2.equals(type)) { 112 s = integer; 113 } else if(TYPE_DATETIME.equals(type)) { 114 s = datetime; 115 } else if (TYPE_LONG.equals(type)) { 116 if((flags & XMLRPCClient.FLAGS_8BYTE_INT) != 0) { 117 s = long8; 118 } else { 119 throw new XMLRPCException("8 byte integer is not in the specification. " 120 + "You must use FLAGS_8BYTE_INT to enable the i8 tag."); 121 } 122 } else if(TYPE_STRUCT.equals(type)) { 123 s = struct; 124 } else if(TYPE_ARRAY.equals(type)) { 125 s = array; 126 } else if(TYPE_BASE64.equals(type)) { 127 s = base64; 128 } else { 129 throw new XMLRPCException("No deserializer found for type '" + type + "'."); 130 } 131 132 return s.deserialize(childElement); 133 134 } 135 136 /** 137 * Serialize an object to its representation as an xml element. 138 * The xml element will be the type element for the use within a value tag. 139 * 140 * @param object The object that should be serialized. 141 * @return The xml representation of this object. 142 * @throws XMLRPCException Will be thrown, if an error occurs (e.g. the object 143 * cannot be serialized to an xml element. 144 */ serialize(Object object)145 public XmlElement serialize(Object object) throws XMLRPCException { 146 147 Serializer s; 148 149 if((flags & XMLRPCClient.FLAGS_NIL) != 0 && object == null) { 150 s = nil; 151 } else if(object instanceof String) { 152 s = string; 153 } else if(object instanceof Boolean) { 154 s = bool; 155 } else if(object instanceof Double || object instanceof Float 156 || object instanceof BigDecimal) { 157 s = floating; 158 } else if (object instanceof Integer || object instanceof Short 159 || object instanceof Byte) { 160 s = integer; 161 } else if(object instanceof Long) { 162 // Check whether the 8 byte integer flag was set. 163 if((flags & XMLRPCClient.FLAGS_8BYTE_INT) != 0) { 164 s = long8; 165 } else { 166 // Allow long values as long as their fit within the 4 byte integer range. 167 long l = (Long)object; 168 if(l > Integer.MAX_VALUE || l < Integer.MIN_VALUE) { 169 throw new XMLRPCException("FLAGS_8BYTE_INT must be set, if values " 170 + "outside the 4 byte integer range should be transfered."); 171 } else { 172 s = integer; 173 } 174 } 175 } else if(object instanceof Date) { 176 s = datetime; 177 } else if(object instanceof Calendar) { 178 object = ((Calendar)object).getTime(); 179 s = datetime; 180 } else if (object instanceof Map) { 181 s = struct; 182 } else if(object instanceof byte[]) { 183 byte[] old = (byte[])object; 184 Byte[] boxed = new Byte[old.length]; 185 for(int i = 0; i < boxed.length; i++) { 186 boxed[i] = Byte.valueOf(old[i]); 187 } 188 object = boxed; 189 s = base64; 190 } else if(object instanceof Byte[]) { 191 s = base64; 192 } else if(object instanceof Iterable<?> || object instanceof Object[]) { 193 s = array; 194 } else { 195 throw new XMLRPCException("No serializer found for type '" 196 + object.getClass().getName() + "'."); 197 } 198 199 return s.serialize(object); 200 201 } 202 203 } 204