KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > gulden > util > xml > serializer > smart > SmartReflectionXMLSerializer


1 /*
2  * Project: Gulden Utilies
3  * Class: de.gulden.util.xml.serializer.smart.SmartReflectionXMLSerializer
4  * Version: snapshot-beautyj-1.1
5  *
6  * Date: 2004-09-29
7  *
8  * This is a snapshot version of the Gulden Utilities,
9  * it is not released as a seperate version.
10  *
11  * Note: Contains auto-generated Javadoc comments created by BeautyJ.
12  *
13  * This is licensed under the GNU Lesser General Public License (LGPL)
14  * and comes with NO WARRANTY.
15  *
16  * Author: Jens Gulden
17  * Email: amoda@jensgulden.de
18  */

19
20 package de.gulden.util.xml.serializer.smart;
21
22 import de.gulden.util.Toolbox;
23 import de.gulden.util.xml.*;
24 import de.gulden.util.xml.serializer.*;
25 import java.lang.reflect.*;
26 import java.lang.reflect.Field JavaDoc;
27 import java.lang.reflect.InvocationTargetException JavaDoc;
28 import java.util.*;
29 import org.w3c.dom.Document JavaDoc;
30 import org.w3c.dom.Element JavaDoc;
31
32 /**
33  * Class SmartReflectionXMLSerializer.
34  *
35  * @author Jens Gulden
36  * @version snapshot-beautyj-1.1
37  */

38 public class SmartReflectionXMLSerializer implements XMLSerializer {
39
40     // ------------------------------------------------------------------------
41
// --- final static field ---
42
// ------------------------------------------------------------------------
43

44     /**
45      * Constant DEFAULT_COLLECTION_CLASS.
46      */

47     public static final Class JavaDoc DEFAULT_COLLECTION_CLASS = ArrayList.class;
48
49
50     // ------------------------------------------------------------------------
51
// --- static field ---
52
// ------------------------------------------------------------------------
53

54     /**
55      * The d e f a u l t_ m a p_ c l a s s.
56      */

57     public static Class JavaDoc DEFAULT_MAP_CLASS = de.gulden.util.OrderedHashMap.class;
58
59
60     // ------------------------------------------------------------------------
61
// --- field ---
62
// ------------------------------------------------------------------------
63

64     /**
65      * <p>
66      * </p>
67      */

68     protected SmartReflectionXMLSerializerFactory factory;
69
70
71     // ------------------------------------------------------------------------
72
// --- constructor ---
73
// ------------------------------------------------------------------------
74

75     /**
76      * Creates a new instance of SmartReflectionXMLSerializer.
77      */

78     SmartReflectionXMLSerializer(SmartReflectionXMLSerializerFactory factory) {
79         super();
80         setFactory(factory);
81     }
82
83
84     // ------------------------------------------------------------------------
85
// --- methods ---
86
// ------------------------------------------------------------------------
87

88     /**
89      * Returns the factory.
90      */

91     public SmartReflectionXMLSerializerFactory getFactory() {
92         return factory;
93     }
94
95     /**
96      * Sets the factory.
97      */

98     public void setFactory(SmartReflectionXMLSerializerFactory smartReflectionXMLSerializerFactory) {
99         this.factory = smartReflectionXMLSerializerFactory;
100     }
101
102     public Element JavaDoc xmlSerialize(Object JavaDoc object, Document JavaDoc document) throws XMLException {
103         // TODO
104
throw new Error JavaDoc("NOT IMPLEMENTED YET");
105     }
106
107     public Object JavaDoc xmlDeserialize(Element JavaDoc element) throws XMLException {
108         Class JavaDoc clazz=getFactory().mapToClass(element.getTagName(), element.getAttribute("class"));
109         Object JavaDoc o;
110         try {
111             o=clazz.newInstance();
112         } catch (InstantiationException JavaDoc ie) {
113             throw new XMLException(ie);
114         } catch (IllegalAccessException JavaDoc iae) {
115             throw new XMLException(iae);
116         }
117         xmlDeserialize(o,element);
118         return o;
119     }
120
121     public void xmlDeserialize(Object JavaDoc object, Element JavaDoc element) throws XMLException {
122         xmlDeserialize(object,element,true);
123     }
124
125     public void xmlDeserialize(Object JavaDoc object, Element JavaDoc element, boolean enableSerializableActive) throws XMLException {
126         // object does its own serialization
127
if ((enableSerializableActive)&&(object instanceof XMLSerializableActive)) {
128             ((XMLSerializableActive)object).xmlDeserialize(element,this);
129         // no own serialization by object, auto-reflection
130
} else if (object instanceof XMLSerializable) {
131             Class JavaDoc clazz=object.getClass();
132             try {
133                 // iterate over fields
134
java.lang.reflect.Field JavaDoc[] fields=clazz.getFields();
135                 for (int i=0;i<fields.length;i++) {
136                     int fieldModifiers=fields[i].getModifiers();
137                     if (!(
138                           java.lang.reflect.Modifier.isTransient(fieldModifiers)
139                           ||java.lang.reflect.Modifier.isStatic(fieldModifiers)
140                           ||java.lang.reflect.Modifier.isFinal(fieldModifiers)
141                           ||java.lang.reflect.Modifier.isVolatile(fieldModifiers)
142                        )) {
143                         String JavaDoc fieldName=fields[i].getName();
144                         Class JavaDoc fieldType=fields[i].getType();
145                         Object JavaDoc fieldObject=fields[i].get(object);
146                         String JavaDoc xmlName=XMLToolbox.translateJavaNameToXMLName(fieldName);
147
148                         // primitive type or String
149
if (fieldType.isPrimitive()||(fieldType==String JavaDoc.class)) {
150                             String JavaDoc attr=element.getAttribute(xmlName);
151                             String JavaDoc valueStr=null;
152                             // attribute with corresponding name?
153
if ((attr!=null)&&(!attr.equals(""))) {
154                                 valueStr=attr;
155                             // sub-element with corresponding name?
156
} else {
157                                 Element JavaDoc e=XMLToolbox.getChild(element,xmlName);
158                                 // yes...
159
if (e!=null) {
160                                     if (fieldType==String JavaDoc.class) {
161                                         // might be langstring...
162
valueStr=XMLToolbox.getLangstring(e); // might stay null if no langstring
163
}
164                                     if (valueStr==null) {
165                                         valueStr=XMLToolbox.getText(e);
166                                     }
167                                 // special field name "text" allows direct element content
168
} else if ((fieldType==String JavaDoc.class)&&(fieldName.equals("text"))) {
169                                     valueStr=XMLToolbox.getLangstring(element); // might stay null if no langstring
170
if (valueStr==null) {
171                                         valueStr=XMLToolbox.getText(element);
172                                     }
173                                 // no element found
174
} else {
175                                     valueStr=null; // ignore, leave initial value of attribute (if any)
176
}
177                             }
178                             if (valueStr!=null) {
179                                 // set field
180
fieldType=convertPrimitiveClassToWrapperClass(fieldType);
181                                 Object JavaDoc fieldValue;
182                                 if (fieldType==String JavaDoc.class) {
183                                     fieldValue=valueStr;
184                                 } else if (Boolean JavaDoc.class.isAssignableFrom(fieldType)) {
185                                     fieldValue=Boolean.valueOf(de.gulden.util.Toolbox.parseBoolean(valueStr));
186                                 } else if (Number JavaDoc.class.isAssignableFrom(fieldType)) {
187                                     Class JavaDoc[] valueOfParamType={String JavaDoc.class};
188                                     java.lang.reflect.Method JavaDoc valueOfMethod=fieldType.getMethod("valueOf",valueOfParamType);
189                                     Object JavaDoc[] valueOfParamValue={valueStr};
190                                     fieldValue=valueOfMethod.invoke(null,valueOfParamValue);
191                                 } else {
192                                     throw new XMLException("can't deserialize attribute of type "+fieldType.getName());
193                                 }
194                                 setFieldValue(fields[i],object,fieldValue);
195                             }
196                         // Collection type
197
} else if (Collection.class.isAssignableFrom(fieldType)) {
198                             Collection c = (Collection)fieldObject;
199                             if (c == null) {
200                                 // create new instance to hold collection
201
Class JavaDoc t;
202                                 if (fieldType.isInterface()||java.lang.reflect.Modifier.isAbstract(fieldModifiers)) {
203                                     t=DEFAULT_COLLECTION_CLASS; // use this if cannot create instance if type
204
// **** MIGHT NOT WORK ALL THE TIME, if fieldType is a subclass of Collection but not impl. by DEFAULT_COLLECTION_CLASS
205
} else {
206                                     t=fieldType;
207                                 }
208                                 c = (Collection)t.newInstance(); // create the collection instance to hold the elements
209
}
210                             String JavaDoc[] childrenTagNames=getChildrenTagNames(clazz,fieldName,xmlName);
211                             org.w3c.dom.NodeList JavaDoc nl=XMLToolbox.getChildren(element,childrenTagNames);
212                             for (int j=0;j<nl.getLength();j++) {
213                                 Element JavaDoc childTag=(Element JavaDoc)nl.item(j);
214                                 //xmlDeserialize(child,childTag); // recursion
215
Object JavaDoc child=xmlDeserialize(childTag); // recursion
216
c.add(child);
217                             }
218                             if (fieldObject==null) {
219                                 setFieldValue(fields[i],object,c);
220                             }
221                         // Map type
222
} else if (Map.class.isAssignableFrom(fieldType)) {
223                             Map m = (Map)fieldObject;
224                             if (m == null) {
225                                 // create new instance to hold map (keep original Map with values if already there)
226
Class JavaDoc t;
227                                 if (fieldType.isInterface()||java.lang.reflect.Modifier.isAbstract(fieldModifiers)) {
228                                     t=DEFAULT_MAP_CLASS; // use this if cannot create instance if type
229
// **** MIGHT NOT WORK ALL THE TIME, see above
230
} else {
231                                     t=fieldType;
232                                 }
233                                 m=(Map)t.newInstance(); // create the map instance to hold the elements
234
}
235                             String JavaDoc[] childrenTagNames=getChildrenTagNames(clazz,fieldName,xmlName);
236                             org.w3c.dom.NodeList JavaDoc nl=XMLToolbox.getChildren(element,childrenTagNames);
237                             for (int j=0;j<nl.getLength();j++) {
238                                 Element JavaDoc childTag=(Element JavaDoc)nl.item(j);
239                                 //xmlDeserialize(child,childTag); // recursion
240
Object JavaDoc child=xmlDeserialize(childTag); // recursion
241
// obtain map key by reflectively calling "getId():String"
242
// **** THIS IS HARD-WIRED and inflexible
243
Class JavaDoc[] getIdParamType={};
244                                 java.lang.reflect.Method JavaDoc getIdMethod;
245                                 try {
246                                     getIdMethod=child.getClass().getMethod("getId",getIdParamType);
247                                 } catch (NoSuchMethodException JavaDoc nsme0) {
248                                     throw new XMLException("mapped objects must contain a getId():String method to be return a key ("+child.getClass().getName()+")");
249                                 }
250                                 Object JavaDoc[] getIdParamValue={};
251                                 String JavaDoc key=(String JavaDoc)getIdMethod.invoke(child,getIdParamValue);
252                                 m.put(key,child);
253                             }
254                             if (fieldObject==null) {
255                                 setFieldValue(fields[i],object,m);
256                             }
257                         // Array type
258
} else if (fieldType.isArray()) {
259                             throw new XMLException("NOT IMPLEMENTED YET: array types cannot be XML-deserialized");
260                         // complex type: use smart reflection recursively
261
} else {
262                             Element JavaDoc e=XMLToolbox.getChild(element,xmlName);
263                             if (e==null) {
264                                 // ignore, leave initial value
265
} else {
266                                 //xmlDeserialize(o,e); // recursion
267
Object JavaDoc o;
268                                 if (fieldObject==null) {
269                                     o = xmlDeserialize(e); // recursion
270
} else {
271                                     o = fieldObject; // keep original value if exists
272
xmlDeserialize(o, e, true);
273                                 }
274                                 setFieldValue(fields[i],object,o);
275                             }
276                         }
277                     }
278                 }
279             } catch (NoSuchMethodException JavaDoc nsme) {
280                 throw new XMLException(nsme);
281             } catch (IllegalAccessException JavaDoc iae) {
282                 throw new XMLException(iae);
283             } catch (InstantiationException JavaDoc ie) {
284                 throw new XMLException(ie);
285             } catch (java.lang.reflect.InvocationTargetException JavaDoc ite) {
286                 throw new XMLException(ite.getTargetException());
287             }
288         } else {
289             throw new XMLException("object of type '"+object.getClass().getName()+"' cannot be deserialized from XML - it does not implement XMLSerializable");
290         }
291     }
292
293
294     // ------------------------------------------------------------------------
295
// --- static methods ---
296
// ------------------------------------------------------------------------
297

298     /**
299      * Sets the field value.
300      */

301     protected static void setFieldValue(Field JavaDoc field, Object JavaDoc object, Object JavaDoc value) throws InvocationTargetException JavaDoc, IllegalAccessException JavaDoc {
302         String JavaDoc fieldName=field.getName();
303         String JavaDoc setterName="set"+Toolbox.capitalize(fieldName);
304         Class JavaDoc[] setterParams={field.getType()};
305         try {
306             java.lang.reflect.Method JavaDoc m=object.getClass().getMethod(setterName,setterParams);
307             // if no exception thrown, there is a setter method for this field
308
Object JavaDoc[] setterValues={value};
309             m.invoke(object,setterValues);
310         } catch (NoSuchMethodException JavaDoc nsme) {
311             // set field directly, no setter method
312
field.set(object,value);
313         }
314     }
315
316     /**
317      * Returns the children tag names.
318      */

319     protected static String JavaDoc[] getChildrenTagNames(Class JavaDoc clazz, String JavaDoc fieldName, String JavaDoc xmlName) {
320         // fieldName might be a plural form which gets converted to singular
321
String JavaDoc[] result=null;
322         try {
323             Field JavaDoc xmlMapAssignField=clazz.getField("XML_COLLECTION_ELEMENTS");
324             Object JavaDoc[][] xmlMapAssign=(Object JavaDoc[][])xmlMapAssignField.get(null);
325             if (xmlMapAssign!=null) {
326                 for (int i=0;(result==null)&&(i<xmlMapAssign.length);i++) {
327                     String JavaDoc key=(String JavaDoc)xmlMapAssign[i][0];
328                     if (key.equals(fieldName)) { // found explicit map assignment
329
String JavaDoc[] assignedFields=(String JavaDoc[])xmlMapAssign[i][1];
330                         return assignedFields;
331                     }
332                 }
333             }
334         } catch (NoSuchFieldException JavaDoc nsfe) {
335             //fallthrough
336
} catch (IllegalAccessException JavaDoc iae) {
337             //fallthrough
338
}
339         if (result==null) { // not found yet
340
// get singular form of xmlName
341
if (xmlName.endsWith("ies")) {
342                 xmlName=xmlName.substring(0,xmlName.length()-3)+"y";
343             } else if (xmlName.endsWith("s")) {
344                 xmlName=xmlName.substring(0,xmlName.length()-1);
345             }
346             result=new String JavaDoc[1];
347             result[0]=xmlName;
348         }
349         return result;
350     }
351
352     protected static Class JavaDoc convertPrimitiveClassToWrapperClass(Class JavaDoc c) {
353         // returns same class if not primitive
354
if (c.isPrimitive()) {
355             try {
356                 return Class.forName("java.lang."+Toolbox.capitalize(c.getName()));
357             } catch (ClassNotFoundException JavaDoc cnfe) { // (should never happen)
358
return null;
359             }
360         } else {
361             return c;
362         }
363     }
364
365 } // end SmartReflectionXMLSerializer
366
Popular Tags