1 package org.sapia.util.xml.idefix; 2 3 4 import java.lang.reflect.Array ; 7 import java.lang.reflect.InvocationTargetException ; 8 import java.lang.reflect.Method ; 9 import java.lang.reflect.Modifier ; 10 11 import java.util.ArrayList ; 12 import java.util.Collection ; 13 import java.util.Iterator ; 14 import java.util.List ; 15 import java.util.Map ; 16 17 18 29 public class DynamicSerializer { 30 public static final String JAVA_NAMESPACE_URI = "http://java.sun.com"; 34 public static final String JAVA_NAMESPACE_PREFIX = "JAVA"; 35 public static final String JAVA_ARRAY_ELEMENT_NAME = "Array"; 36 public static final String JAVA_COLLECTION_ELEMENT_NAME = "Collection"; 37 public static final String JAVA_ITERATOR_ELEMENT_NAME = "Iterator"; 38 public static final String JAVA_MAP_ELEMENT_NAME = "Map"; 39 public static final String JAVA_ELEMENT_ELEMENT_NAME = "Element"; 40 public static final String JAVA_KEY_ELEMENT_NAME = "Key"; 41 public static final String JAVA_VALUE_ELEMENT_NAME = "Value"; 42 public static final String JAVA_TYPE_ATTRIBUTE_NAME = "type"; 43 public static final String JAVA_SIZE_ATTRIBUTE_NAME = "size"; 44 public static final String JAVA_INDEX_ATTRIBUTE_NAME = "index"; 45 public static final String JAVA_KEY_ATTRIBUTE_NAME = "key"; 46 public static final String JAVA_VALUE_ATTRIBUTE_NAME = "value"; 47 48 49 private static final List EMPTY_LIST = new ArrayList (0); 50 51 52 private static final Class [] EMPTY_CLASS_ARRAY = new Class [0]; 53 54 public DynamicSerializer() { 58 } 59 60 66 public String serialize(Object anObject) { 67 XmlBuffer anXmlBuffer = new XmlBuffer(); 68 serializeIter("Root", anObject, anXmlBuffer, new ArrayList ()); 69 70 return anXmlBuffer.toString(); 71 } 72 73 76 private void serializeIter(String anObjectName, Object anObject, 77 XmlBuffer anXmlBuffer, List someObjects) { 78 if (someObjects.contains(anObject)) { 80 throw new IllegalStateException ("Circular referenced objects detected: " + 81 anObject); 82 } else { 83 someObjects.add(anObject); 84 } 85 86 if (isLeafType(anObject.getClass())) { 87 encodeLeaf(anObjectName, anObject, anXmlBuffer); 88 } else if (anObject.getClass().isArray()) { 89 encodeArray(anObject, anXmlBuffer, someObjects); 90 } else if (anObject instanceof Collection ) { 91 encodeCollection((Collection ) anObject, anXmlBuffer, someObjects); 92 } else if (anObject instanceof Map ) { 93 encodeMap((Map ) anObject, anXmlBuffer, someObjects); 94 } else if (anObject instanceof Iterator ) { 95 encodeIterator((Iterator ) anObject, anXmlBuffer, someObjects); 96 } else { 97 encodeNode(anObject, anXmlBuffer, someObjects); 98 } 99 100 someObjects.remove(anObject); 101 } 102 103 106 private String getObjectName(Object anObject) { 107 if (anObject == null) { 108 return ""; 109 } 110 111 Class aClass = anObject.getClass(); 112 113 String aQualifiedClassName = aClass.getName(); 114 String aPackageName = aClass.getPackage().getName(); 115 String aLocalClassName = aQualifiedClassName.substring(aPackageName.length() + 116 1); 117 118 return aLocalClassName; 119 } 120 121 124 private List getMatchingMethods(Object anObject) { 125 if (anObject == null) { 126 return EMPTY_LIST; 127 } 128 129 Class aClass = anObject.getClass(); 130 Method [] allMethods = aClass.getMethods(); ArrayList someMatchingMethods = new ArrayList (allMethods.length); 132 133 for (int i = 0; i < allMethods.length; i++) { 134 Method aMethod = allMethods[i]; 135 136 if ((aMethod.getName().startsWith("get") || aMethod.getName().startsWith("is")) && !aMethod.getName().equals("getClass") && !Modifier.isStatic(aMethod.getModifiers()) && (aMethod.getParameterTypes().length == 0) && (aMethod.getReturnType() != Void.TYPE)) { someMatchingMethods.add(aMethod); 143 } 144 } 145 146 return someMatchingMethods; 147 } 148 149 152 private String getObjectName(Method aMethod) { 153 int aPrefixLength = 0; 154 String aMethodName = aMethod.getName(); 155 156 if (aMethodName.startsWith("get")) { 157 aPrefixLength = 3; 158 } else if (aMethodName.startsWith("is")) { 159 aPrefixLength = 2; 160 } else { 161 throw new IllegalArgumentException ( 162 "The method name does not starts with \'get\' or \'is\'"); 163 } 164 165 String anAttributeName = firstToLower(aMethodName, aPrefixLength); 166 167 return anAttributeName; 168 } 169 170 173 private String firstToLower(String aString, int aStartingIndex) { 174 char[] newChars = new char[aString.length() - aStartingIndex]; 175 newChars[0] = Character.toLowerCase(aString.charAt(aStartingIndex)); 176 aString.getChars(aStartingIndex + 1, aString.length(), newChars, 1); 177 178 return new String (newChars); 179 } 180 181 184 private String firstToUpper(String aString, int aStartingIndex) { 185 char[] newChars = new char[aString.length() - aStartingIndex]; 186 newChars[0] = Character.toUpperCase(aString.charAt(aStartingIndex)); 187 aString.getChars(aStartingIndex + 1, aString.length(), newChars, 1); 188 189 return new String (newChars); 190 } 191 192 195 private boolean isLeafType(Class aClass) { 196 return (aClass.isPrimitive() || (aClass == Character .class) || 197 (aClass == String .class) || (aClass == Boolean .class) || 198 (aClass == Byte .class) || (aClass == Short .class) || 199 (aClass == Integer .class) || (aClass == Long .class) || 200 (aClass == Float .class) || (aClass == Double .class)); 201 } 202 203 206 private void encodeLeaf(String aName, Object aValue, XmlBuffer anXmlBuffer) { 207 String aStringValue = String.valueOf(aValue); 208 anXmlBuffer.addAttribute(firstToLower(aName, 0), aStringValue); 209 } 210 211 214 private void encodeNode(Object anObject, XmlBuffer anXmlBuffer, 215 List someObjects) { 216 String anElementName = getObjectName(anObject); 218 anXmlBuffer.startElement(anElementName); 219 220 Method aMethod = null; 222 223 try { 224 List someMethods = getMatchingMethods(anObject); 225 226 for (Iterator it = someMethods.iterator(); it.hasNext();) { 227 aMethod = (Method ) it.next(); 228 229 Object aMethodValue = aMethod.invoke(anObject, EMPTY_CLASS_ARRAY); 230 231 if (aMethodValue != null) { 232 String anObjectName = getObjectName(aMethod); 233 serializeIter(anObjectName, aMethodValue, anXmlBuffer, someObjects); 234 } 235 } 236 } catch (IllegalAccessException iae) { 237 throw new org.sapia.util.CompositeRuntimeException( 238 "Unable to extract the value of the method: " + aMethod, iae); 239 } catch (InvocationTargetException ite) { 240 throw new org.sapia.util.CompositeRuntimeException( 241 "Error calling the method: " + aMethod, ite); 242 } 243 244 anXmlBuffer.endElement(anElementName); 246 } 247 248 251 private void encodeArray(Object anArray, XmlBuffer anXmlBuffer, 252 List someObjects) { 253 boolean isArrayOfLeafType = isLeafType(anArray.getClass().getComponentType()); 254 String anArrayTypeName = anArray.getClass().getComponentType().getName(); 255 int aLength = Array.getLength(anArray); 256 257 anXmlBuffer.addNamespace(JAVA_NAMESPACE_URI, JAVA_NAMESPACE_PREFIX) 259 .startElement(JAVA_NAMESPACE_URI, JAVA_ARRAY_ELEMENT_NAME) 260 .addAttribute(JAVA_TYPE_ATTRIBUTE_NAME, anArrayTypeName) 261 .addAttribute(JAVA_SIZE_ATTRIBUTE_NAME, Integer.toString(aLength)); 262 263 for (int i = 0; i < aLength; i++) { 264 Object anObject = Array.get(anArray, i); 265 266 if (anObject != null) { 267 anXmlBuffer.startElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME) 269 .addAttribute(JAVA_INDEX_ATTRIBUTE_NAME, Integer.toString(i)); 270 271 serializeIter(JAVA_VALUE_ATTRIBUTE_NAME, anObject, anXmlBuffer, 272 someObjects); 273 274 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME); 276 } 277 } 278 279 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ARRAY_ELEMENT_NAME) 281 .removeNamespace(JAVA_NAMESPACE_URI); 282 } 283 284 287 private void encodeCollection(Collection aCollection, XmlBuffer anXmlBuffer, 288 List someObjects) { 289 String aCollectionTypeName = aCollection.getClass().getName(); 290 int aCollectionLength = aCollection.size(); 291 292 anXmlBuffer.addNamespace(JAVA_NAMESPACE_URI, JAVA_NAMESPACE_PREFIX) 294 .startElement(JAVA_NAMESPACE_URI, JAVA_COLLECTION_ELEMENT_NAME) 295 .addAttribute(JAVA_TYPE_ATTRIBUTE_NAME, aCollectionTypeName) 296 .addAttribute(JAVA_SIZE_ATTRIBUTE_NAME, 297 Integer.toString(aCollectionLength)); 298 299 int anIndex = 0; 300 301 for (Iterator it = aCollection.iterator(); it.hasNext(); anIndex++) { 302 Object anObject = it.next(); 303 304 if (anObject != null) { 305 anXmlBuffer.startElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME) 307 .addAttribute(JAVA_INDEX_ATTRIBUTE_NAME, 308 Integer.toString(anIndex)); 309 310 serializeIter(JAVA_VALUE_ATTRIBUTE_NAME, anObject, anXmlBuffer, 311 someObjects); 312 313 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME); 315 } 316 } 317 318 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_COLLECTION_ELEMENT_NAME) 320 .removeNamespace(JAVA_NAMESPACE_URI); 321 } 322 323 326 private void encodeIterator(Iterator anIterator, XmlBuffer anXmlBuffer, 327 List someObjects) { 328 anXmlBuffer.addNamespace(JAVA_NAMESPACE_URI, JAVA_NAMESPACE_PREFIX) 330 .startElement(JAVA_NAMESPACE_URI, JAVA_ITERATOR_ELEMENT_NAME); 331 332 for (int anIndex = 0; anIterator.hasNext(); anIndex++) { 333 Object anObject = anIterator.next(); 334 335 if (anObject != null) { 336 anXmlBuffer.startElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME) 338 .addAttribute(JAVA_INDEX_ATTRIBUTE_NAME, 339 Integer.toString(anIndex)); 340 341 serializeIter(JAVA_VALUE_ATTRIBUTE_NAME, anObject, anXmlBuffer, 342 someObjects); 343 344 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME); 346 } 347 } 348 349 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ITERATOR_ELEMENT_NAME) 351 .removeNamespace(JAVA_NAMESPACE_URI); 352 } 353 354 357 private void encodeMap(Map aMap, XmlBuffer anXmlBuffer, List someObjects) { 358 String aMapTypeName = aMap.getClass().getName(); 359 int aMapLength = aMap.size(); 360 361 anXmlBuffer.addNamespace(JAVA_NAMESPACE_URI, JAVA_NAMESPACE_PREFIX) 363 .startElement(JAVA_NAMESPACE_URI, JAVA_MAP_ELEMENT_NAME) 364 .addAttribute(JAVA_TYPE_ATTRIBUTE_NAME, aMapTypeName) 365 .addAttribute(JAVA_SIZE_ATTRIBUTE_NAME, 366 Integer.toString(aMapLength)); 367 368 int anIndex = 0; 369 370 for (Iterator it = aMap.keySet().iterator(); it.hasNext(); anIndex++) { 371 Object aKey = it.next(); 372 Object aValue = aMap.get(aKey); 373 374 anXmlBuffer.startElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME) 376 .addAttribute(JAVA_INDEX_ATTRIBUTE_NAME, 377 Integer.toString(anIndex)); 378 379 if (isLeafType(aKey.getClass())) { 381 serializeIter(JAVA_KEY_ATTRIBUTE_NAME, aKey, anXmlBuffer, someObjects); 382 } else { 383 anXmlBuffer.startElement(JAVA_NAMESPACE_URI, JAVA_KEY_ELEMENT_NAME); 384 serializeIter(JAVA_KEY_ATTRIBUTE_NAME, aKey, anXmlBuffer, someObjects); 385 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_KEY_ELEMENT_NAME); 386 } 387 388 if (aValue != null) { 390 if (isLeafType(aValue.getClass())) { 391 serializeIter(JAVA_VALUE_ATTRIBUTE_NAME, aValue, anXmlBuffer, 392 someObjects); 393 } else { 394 anXmlBuffer.startElement(JAVA_NAMESPACE_URI, JAVA_VALUE_ELEMENT_NAME); 395 serializeIter(JAVA_VALUE_ATTRIBUTE_NAME, aValue, anXmlBuffer, 396 someObjects); 397 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_VALUE_ELEMENT_NAME); 398 } 399 } 400 401 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME); 403 } 404 405 anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_MAP_ELEMENT_NAME) 407 .removeNamespace(JAVA_NAMESPACE_URI); 408 } 409 } 410 | Popular Tags |