KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sapia > util > xml > idefix > DynamicSerializer


1 package org.sapia.util.xml.idefix;
2
3
4 // Import of Sun's JDK classes
5
// ---------------------------
6
import java.lang.reflect.Array JavaDoc;
7 import java.lang.reflect.InvocationTargetException JavaDoc;
8 import java.lang.reflect.Method JavaDoc;
9 import java.lang.reflect.Modifier JavaDoc;
10
11 import java.util.ArrayList JavaDoc;
12 import java.util.Collection JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.Map JavaDoc;
16
17
18 /**
19  *
20  *
21  * @author Jean-Cedric Desrochers
22  *
23  * <dl>
24  * <dt><b>Copyright:</b><dd>Copyright &#169; 2002-2003 <a HREF="http://www.sapia-oss.org">Sapia Open Source Software</a>. All Rights Reserved.</dd></dt>
25  * <dt><b>License:</b><dd>Read the license.txt file of the jar or visit the
26  * <a HREF="http://www.sapia-oss.org/license.html">license page</a> at the Sapia OSS web site</dd></dt>
27  * </dl>
28  */

29 public class DynamicSerializer {
30   /////////////////////////////////////////////////////////////////////////////////////////
31
////////////////////////////////// CLASS ATTRIBUTES ///////////////////////////////////
32
/////////////////////////////////////////////////////////////////////////////////////////
33
public static final String JavaDoc JAVA_NAMESPACE_URI = "http://java.sun.com";
34   public static final String JavaDoc JAVA_NAMESPACE_PREFIX = "JAVA";
35   public static final String JavaDoc JAVA_ARRAY_ELEMENT_NAME = "Array";
36   public static final String JavaDoc JAVA_COLLECTION_ELEMENT_NAME = "Collection";
37   public static final String JavaDoc JAVA_ITERATOR_ELEMENT_NAME = "Iterator";
38   public static final String JavaDoc JAVA_MAP_ELEMENT_NAME = "Map";
39   public static final String JavaDoc JAVA_ELEMENT_ELEMENT_NAME = "Element";
40   public static final String JavaDoc JAVA_KEY_ELEMENT_NAME = "Key";
41   public static final String JavaDoc JAVA_VALUE_ELEMENT_NAME = "Value";
42   public static final String JavaDoc JAVA_TYPE_ATTRIBUTE_NAME = "type";
43   public static final String JavaDoc JAVA_SIZE_ATTRIBUTE_NAME = "size";
44   public static final String JavaDoc JAVA_INDEX_ATTRIBUTE_NAME = "index";
45   public static final String JavaDoc JAVA_KEY_ATTRIBUTE_NAME = "key";
46   public static final String JavaDoc JAVA_VALUE_ATTRIBUTE_NAME = "value";
47
48   /** Defines an empty immutable list. */
49   private static final List JavaDoc EMPTY_LIST = new ArrayList JavaDoc(0);
50
51   /** Defines an empty Class array. */
52   private static final Class JavaDoc[] EMPTY_CLASS_ARRAY = new Class JavaDoc[0];
53
54   /////////////////////////////////////////////////////////////////////////////////////////
55
//////////////////////////////////// CONSTRUCTORS /////////////////////////////////////
56
/////////////////////////////////////////////////////////////////////////////////////////
57
public DynamicSerializer() {
58   }
59
60   /**
61    * Transforms the object passed in into an xml string.
62    *
63    * @param anObject The object to serialize to xml.
64    * @return A string representing the result xml.
65    */

66   public String JavaDoc serialize(Object JavaDoc anObject) {
67     XmlBuffer anXmlBuffer = new XmlBuffer();
68     serializeIter("Root", anObject, anXmlBuffer, new ArrayList JavaDoc());
69
70     return anXmlBuffer.toString();
71   }
72
73   /**
74    *
75    */

76   private void serializeIter(String JavaDoc anObjectName, Object JavaDoc anObject,
77     XmlBuffer anXmlBuffer, List JavaDoc someObjects) {
78     // Validate for circular references
79
if (someObjects.contains(anObject)) {
80       throw new IllegalStateException JavaDoc("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 JavaDoc) {
91       encodeCollection((Collection JavaDoc) anObject, anXmlBuffer, someObjects);
92     } else if (anObject instanceof Map JavaDoc) {
93       encodeMap((Map JavaDoc) anObject, anXmlBuffer, someObjects);
94     } else if (anObject instanceof Iterator JavaDoc) {
95       encodeIterator((Iterator JavaDoc) anObject, anXmlBuffer, someObjects);
96     } else {
97       encodeNode(anObject, anXmlBuffer, someObjects);
98     }
99
100     someObjects.remove(anObject);
101   }
102
103   /**
104    *
105    */

106   private String JavaDoc getObjectName(Object JavaDoc anObject) {
107     if (anObject == null) {
108       return "";
109     }
110
111     Class JavaDoc aClass = anObject.getClass();
112
113     String JavaDoc aQualifiedClassName = aClass.getName();
114     String JavaDoc aPackageName = aClass.getPackage().getName();
115     String JavaDoc aLocalClassName = aQualifiedClassName.substring(aPackageName.length() +
116         1);
117
118     return aLocalClassName;
119   }
120
121   /**
122    *
123    */

124   private List JavaDoc getMatchingMethods(Object JavaDoc anObject) {
125     if (anObject == null) {
126       return EMPTY_LIST;
127     }
128
129     Class JavaDoc aClass = anObject.getClass();
130     Method JavaDoc[] allMethods = aClass.getMethods(); // get all public methods
131
ArrayList JavaDoc someMatchingMethods = new ArrayList JavaDoc(allMethods.length);
132
133     for (int i = 0; i < allMethods.length; i++) {
134       Method JavaDoc aMethod = allMethods[i];
135
136       if ((aMethod.getName().startsWith("get") || // starts with 'get'
137
aMethod.getName().startsWith("is")) && // or 'is'
138
!aMethod.getName().equals("getClass") && // the method is not getClass()
139
!Modifier.isStatic(aMethod.getModifiers()) && // not static
140
(aMethod.getParameterTypes().length == 0) && // has no parameter
141
(aMethod.getReturnType() != Void.TYPE)) { // do not return void
142
someMatchingMethods.add(aMethod);
143       }
144     }
145
146     return someMatchingMethods;
147   }
148
149   /**
150    *
151    */

152   private String JavaDoc getObjectName(Method JavaDoc aMethod) {
153     int aPrefixLength = 0;
154     String JavaDoc 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 JavaDoc(
162         "The method name does not starts with \'get\' or \'is\'");
163     }
164
165     String JavaDoc anAttributeName = firstToLower(aMethodName, aPrefixLength);
166
167     return anAttributeName;
168   }
169
170   /**
171    *
172    */

173   private String JavaDoc firstToLower(String JavaDoc 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 JavaDoc(newChars);
179   }
180
181   /**
182    *
183    */

184   private String JavaDoc firstToUpper(String JavaDoc 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 JavaDoc(newChars);
190   }
191
192   /**
193    *
194    */

195   private boolean isLeafType(Class JavaDoc aClass) {
196     return (aClass.isPrimitive() || (aClass == Character JavaDoc.class) ||
197     (aClass == String JavaDoc.class) || (aClass == Boolean JavaDoc.class) ||
198     (aClass == Byte JavaDoc.class) || (aClass == Short JavaDoc.class) ||
199     (aClass == Integer JavaDoc.class) || (aClass == Long JavaDoc.class) ||
200     (aClass == Float JavaDoc.class) || (aClass == Double JavaDoc.class));
201   }
202
203   /**
204    *
205    */

206   private void encodeLeaf(String JavaDoc aName, Object JavaDoc aValue, XmlBuffer anXmlBuffer) {
207     String JavaDoc aStringValue = String.valueOf(aValue);
208     anXmlBuffer.addAttribute(firstToLower(aName, 0), aStringValue);
209   }
210
211   /**
212    *
213    */

214   private void encodeNode(Object JavaDoc anObject, XmlBuffer anXmlBuffer,
215     List JavaDoc someObjects) {
216     // Start the element
217
String JavaDoc anElementName = getObjectName(anObject);
218     anXmlBuffer.startElement(anElementName);
219
220     // Walk though the object tree
221
Method JavaDoc aMethod = null;
222
223     try {
224       List JavaDoc someMethods = getMatchingMethods(anObject);
225
226       for (Iterator JavaDoc it = someMethods.iterator(); it.hasNext();) {
227         aMethod = (Method JavaDoc) it.next();
228
229         Object JavaDoc aMethodValue = aMethod.invoke(anObject, EMPTY_CLASS_ARRAY);
230
231         if (aMethodValue != null) {
232           String JavaDoc anObjectName = getObjectName(aMethod);
233           serializeIter(anObjectName, aMethodValue, anXmlBuffer, someObjects);
234         }
235       }
236     } catch (IllegalAccessException JavaDoc iae) {
237       throw new org.sapia.util.CompositeRuntimeException(
238         "Unable to extract the value of the method: " + aMethod, iae);
239     } catch (InvocationTargetException JavaDoc ite) {
240       throw new org.sapia.util.CompositeRuntimeException(
241         "Error calling the method: " + aMethod, ite);
242     }
243
244     // End the element
245
anXmlBuffer.endElement(anElementName);
246   }
247
248   /**
249    *
250    */

251   private void encodeArray(Object JavaDoc anArray, XmlBuffer anXmlBuffer,
252     List JavaDoc someObjects) {
253     boolean isArrayOfLeafType = isLeafType(anArray.getClass().getComponentType());
254     String JavaDoc anArrayTypeName = anArray.getClass().getComponentType().getName();
255     int aLength = Array.getLength(anArray);
256
257     // Start Array element
258
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 JavaDoc anObject = Array.get(anArray, i);
265
266       if (anObject != null) {
267         // Start ArrayElement element
268
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         // Start ArrayElement element
275
anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME);
276       }
277     }
278
279     // End Array element
280
anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ARRAY_ELEMENT_NAME)
281                .removeNamespace(JAVA_NAMESPACE_URI);
282   }
283
284   /**
285    *
286    */

287   private void encodeCollection(Collection JavaDoc aCollection, XmlBuffer anXmlBuffer,
288     List JavaDoc someObjects) {
289     String JavaDoc aCollectionTypeName = aCollection.getClass().getName();
290     int aCollectionLength = aCollection.size();
291
292     // Start Collection element
293
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 JavaDoc it = aCollection.iterator(); it.hasNext(); anIndex++) {
302       Object JavaDoc anObject = it.next();
303
304       if (anObject != null) {
305         // Start Element element
306
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         // Start Element element
314
anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME);
315       }
316     }
317
318     // End Collection element
319
anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_COLLECTION_ELEMENT_NAME)
320                .removeNamespace(JAVA_NAMESPACE_URI);
321   }
322
323   /**
324    *
325    */

326   private void encodeIterator(Iterator JavaDoc anIterator, XmlBuffer anXmlBuffer,
327     List JavaDoc someObjects) {
328     // Start Iterator element
329
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 JavaDoc anObject = anIterator.next();
334
335       if (anObject != null) {
336         // Start Element element
337
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         // Start Element element
345
anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME);
346       }
347     }
348
349     // End Iterator element
350
anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ITERATOR_ELEMENT_NAME)
351                .removeNamespace(JAVA_NAMESPACE_URI);
352   }
353
354   /**
355    *
356    */

357   private void encodeMap(Map JavaDoc aMap, XmlBuffer anXmlBuffer, List JavaDoc someObjects) {
358     String JavaDoc aMapTypeName = aMap.getClass().getName();
359     int aMapLength = aMap.size();
360
361     // Start Collection element
362
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 JavaDoc it = aMap.keySet().iterator(); it.hasNext(); anIndex++) {
371       Object JavaDoc aKey = it.next();
372       Object JavaDoc aValue = aMap.get(aKey);
373
374       // Start Element element
375
anXmlBuffer.startElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME)
376                  .addAttribute(JAVA_INDEX_ATTRIBUTE_NAME,
377         Integer.toString(anIndex));
378
379       // Encode the key
380
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       // Encode the value
389
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       // Start Element element
402
anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_ELEMENT_ELEMENT_NAME);
403     }
404
405     // End Map element
406
anXmlBuffer.endElement(JAVA_NAMESPACE_URI, JAVA_MAP_ELEMENT_NAME)
407                .removeNamespace(JAVA_NAMESPACE_URI);
408   }
409 }
410
Popular Tags