KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > jaxb > skeleton > ClassSkeleton


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Adam Megacz
28  */

29
30 package com.caucho.jaxb.skeleton;
31
32 import com.caucho.jaxb.JAXBContextImpl;
33 import com.caucho.jaxb.JAXBUtil;
34 import com.caucho.util.L10N;
35
36 import javax.xml.bind.JAXBException;
37 import javax.xml.bind.Marshaller;
38 import javax.xml.bind.Unmarshaller;
39 import javax.xml.bind.annotation.*;
40
41 import javax.xml.namespace.QName JavaDoc;
42
43 import javax.xml.stream.XMLStreamException;
44 import javax.xml.stream.XMLStreamReader;
45 import javax.xml.stream.XMLStreamWriter;
46
47 import java.beans.BeanInfo JavaDoc;
48 import java.beans.Introspector JavaDoc;
49 import java.beans.PropertyDescriptor JavaDoc;
50
51 import java.io.IOException JavaDoc;
52
53 import java.lang.reflect.AccessibleObject JavaDoc;
54 import java.lang.reflect.Constructor JavaDoc;
55 import java.lang.reflect.Field JavaDoc;
56 import java.lang.reflect.InvocationTargetException JavaDoc;
57 import java.lang.reflect.Method JavaDoc;
58 import java.lang.reflect.Modifier JavaDoc;
59
60 import java.util.Collection JavaDoc;
61 import java.util.HashMap JavaDoc;
62 import java.util.List JavaDoc;
63 import java.util.Set JavaDoc;
64 import java.util.logging.Logger JavaDoc;
65
66 public class ClassSkeleton<C> extends Skeleton {
67   public static final String JavaDoc XML_SCHEMA_NS = "http://www.w3.org/2001/XMLSchema";
68   public static final String JavaDoc XML_SCHEMA_PREFIX = "xsd";
69
70   private static final L10N L = new L10N(ClassSkeleton.class);
71   private static final Logger JavaDoc log = Logger.getLogger(Skeleton.class.getName());
72
73   private static final Class JavaDoc[] NO_PARAMS = new Class JavaDoc[0];
74   private static final Object JavaDoc[] NO_ARGS = new Object JavaDoc[0];
75
76   private Class JavaDoc<C> _class;
77
78   private Method JavaDoc _beforeUnmarshal;
79   private Method JavaDoc _afterUnmarshal;
80   private Method JavaDoc _beforeMarshal;
81   private Method JavaDoc _afterMarshal;
82
83   private QName JavaDoc _elementName;
84
85   private Constructor JavaDoc _constructor;
86
87   /**
88    * The value @XmlValue.
89    *
90    **/

91   private Accessor _value;
92
93   public Class JavaDoc<C> getType()
94   {
95     return _class;
96   }
97
98   public String JavaDoc toString()
99   {
100     return "ClassSkeleton[" + _class + "]";
101   }
102   
103   public ClassSkeleton(JAXBContextImpl context, Class JavaDoc<C> c)
104     throws JAXBException
105   {
106     super(context);
107
108     try {
109       _class = c;
110
111       try {
112         _beforeUnmarshal =
113           c.getMethod("beforeUnmarshal", Unmarshaller.class, Object JavaDoc.class);
114       } catch (NoSuchMethodException JavaDoc _) {
115         // deliberate
116
}
117
118       try {
119         _afterUnmarshal =
120           c.getMethod("afterUnmarshal", Unmarshaller.class, Object JavaDoc.class);
121       } catch (NoSuchMethodException JavaDoc _) {
122         // deliberate
123
}
124
125       try {
126         _beforeMarshal =
127           c.getMethod("beforeMarshal", Marshaller.class, Object JavaDoc.class);
128       } catch (NoSuchMethodException JavaDoc _) {
129         // deliberate
130
}
131
132       try {
133         _afterMarshal =
134           c.getMethod("afterMarshal", Marshaller.class, Object JavaDoc.class);
135       } catch (NoSuchMethodException JavaDoc _) {
136         // deliberate
137
}
138
139       
140       if (List JavaDoc.class.isAssignableFrom(_class)) {
141         // XXX:
142
}
143       if (Set JavaDoc.class.isAssignableFrom(_class)) {
144         // XXX:
145
}
146       if (HashMap JavaDoc.class.isAssignableFrom(_class)) {
147         // XXX:
148
}
149       
150       // XXX: @XmlJavaTypeAdapter
151

152       // Find the zero-parameter constructor
153
try {
154         _constructor = c.getConstructor(NO_PARAMS);
155         _constructor.setAccessible(true);
156       }
157       catch (Exception JavaDoc e1) {
158         try {
159           _constructor = c.getDeclaredConstructor(NO_PARAMS);
160           _constructor.setAccessible(true);
161         }
162         catch (Exception JavaDoc e2) {
163           throw new JAXBException(L.l("Zero-arg constructor not found for class {0}", c.getName()), e2);
164         }
165       }
166
167       _typeName = new QName JavaDoc(JAXBUtil.getXmlSchemaDatatype(_class));
168       
169       if (c.isAnnotationPresent(XmlRootElement.class)) {
170         XmlRootElement xre = c.getAnnotation(XmlRootElement.class);
171
172         String JavaDoc localName = null;
173         
174         if ("##default".equals(xre.name()))
175           localName = JAXBUtil.identifierToXmlName(_class);
176         else
177           localName = xre.name();
178
179         if ("##default".equals(xre.namespace()))
180           _elementName = new QName JavaDoc(localName);
181         else
182           _elementName = new QName JavaDoc(xre.namespace(), localName);
183
184         _typeName = _elementName;
185
186         _context.addRootElement(this);
187       }
188
189       XmlAccessorType accessorType = c.getAnnotation(XmlAccessorType.class);
190       XmlAccessType accessType = (accessorType == null ?
191                                   XmlAccessType.PUBLIC_MEMBER :
192                                   accessorType.value());
193
194       if (accessType != XmlAccessType.FIELD) {
195         // getter/setter
196
BeanInfo JavaDoc beanInfo = Introspector.getBeanInfo(c);
197
198         for (PropertyDescriptor JavaDoc property : beanInfo.getPropertyDescriptors()) {
199           // JAXB specifies that a "class" property must be specified as "clazz"
200
// because of Object.getClass()
201
if ("class".equals(property.getName()))
202             continue;
203
204           Method JavaDoc get = property.getReadMethod();
205           Method JavaDoc set = property.getWriteMethod();
206
207           if (property.getPropertyType() == null) {
208             continue;
209           }
210
211           if (get != null && get.isAnnotationPresent(XmlTransient.class))
212             continue;
213           if (set != null && set.isAnnotationPresent(XmlTransient.class))
214             continue;
215
216           addAccessor(new GetterSetterAccessor(property, _context));
217         }
218       }
219
220       if (accessType != XmlAccessType.PROPERTY) {
221         Field JavaDoc[] fields = c.getDeclaredFields();
222         AccessibleObject.setAccessible(fields, true);
223
224         for (Field JavaDoc f : fields) {
225           if (Modifier.isStatic(f.getModifiers()))
226             continue;
227           if (f.isAnnotationPresent(XmlTransient.class))
228             continue;
229           // jaxb/0176: transient modifier ignored
230

231           if (accessType == XmlAccessType.PUBLIC_MEMBER
232               && ! Modifier.isPublic(f.getModifiers()))
233             continue;
234
235           // XXX : XmlAccessType.NONE
236

237           addAccessor(new FieldAccessor(f, _context));
238         }
239       }
240     }
241     catch (Exception JavaDoc e) {
242       throw new JAXBException(e);
243     }
244   }
245
246   private void addAccessor(Accessor a)
247     throws JAXBException
248   {
249     if (a.getAnnotation(XmlValue.class) != null) {
250       if (_value != null)
251         throw new JAXBException(L.l("Cannot have two @XmlValue annotated fields or properties"));
252
253       if (! a.isXmlPrimitiveType() &&
254           ! Collection JavaDoc.class.isAssignableFrom(a.getType()))
255         throw new JAXBException(L.l("XmlValue must be either a collection or a simple type"));
256
257       _value = a;
258     }
259     else if (a.getAnnotation(XmlAttribute.class) != null)
260       _attributeAccessors.put(a.getName(), a);
261     else {
262       if (_value != null)
263         throw new JAXBException(L.l("Cannot have both @XmlValue and elements in a JAXB element"));
264
265       _elementAccessors.put(a.getName(), a);
266     }
267
268     // Make sure the field's type is in the context so that the
269
// schema generates correctly
270
/*
271     if ((a instanceof IterableProperty) &&
272         ! ((IterableProperty) p).getComponentProperty().isXmlPrimitiveType()) {
273       Property compProp = ((IterableProperty) p).getComponentProperty();
274       _context.createSkeleton(compProp.getAccessor().getType());
275     }
276     else */

277
278
279     if (! a.isXmlPrimitiveType()) {
280       _context.createSkeleton(a.getType());
281     }
282   }
283
284   public C newInstance()
285     throws JAXBException
286   {
287     try {
288       XmlType xmlType = getXmlType();
289       
290       if (xmlType != null) {
291         Class JavaDoc factoryClass = xmlType.factoryClass();
292         
293         if (xmlType.factoryClass() == XmlType.DEFAULT.class)
294           factoryClass = _class;
295         
296         if (! "".equals(xmlType.factoryMethod())) {
297           Method JavaDoc m = factoryClass.getMethod(xmlType.factoryMethod(), NO_PARAMS);
298
299           if (! Modifier.isStatic(m.getModifiers()))
300             throw new JAXBException(L.l("Factory method not static"));
301
302           return (C) m.invoke(null);
303         }
304       }
305       
306       Constructor JavaDoc con = _class.getConstructor(NO_PARAMS);
307
308       return (C)con.newInstance(NO_ARGS);
309     }
310     catch (Exception JavaDoc e) {
311       throw new JAXBException(e);
312     }
313   }
314
315   public XmlType getXmlType()
316   {
317     return (XmlType)_class.getAnnotation(XmlType.class);
318   }
319
320   public Object JavaDoc read(Unmarshaller u, XMLStreamReader in)
321     throws IOException JavaDoc, XMLStreamException, JAXBException
322   {
323     // XXX: sequences/choice/etc
324
try {
325       C ret = (C) _constructor.newInstance();
326       in.next();
327
328       if (_beforeUnmarshal != null)
329         _beforeUnmarshal.invoke(ret, /*FIXME*/ null, null);
330       if (u.getListener() != null)
331         u.getListener().beforeUnmarshal(ret, null);
332
333       while (in.getEventType() == in.START_ELEMENT) {
334         Accessor a = getAccessor(in.getName());
335         Object JavaDoc val = a.read(u, in);
336         a.set(ret, val);
337       }
338
339       if (_afterUnmarshal != null)
340         _afterUnmarshal.invoke(ret, /*FIXME*/ null, null);
341       if (u.getListener() != null)
342         u.getListener().afterUnmarshal(ret, null);
343       
344       return ret;
345     }
346     catch (InstantiationException JavaDoc e) {
347       throw new JAXBException(e);
348     }
349     catch (InvocationTargetException JavaDoc e) {
350       throw new JAXBException(e);
351     }
352     catch (IllegalAccessException JavaDoc e) {
353       throw new JAXBException(e);
354     }
355   }
356   
357   public void write(Marshaller m, XMLStreamWriter out,
358                     Object JavaDoc obj, QName JavaDoc fieldName)
359     throws IOException JavaDoc, XMLStreamException, JAXBException
360   {
361     try {
362       if (_beforeMarshal != null)
363         _beforeMarshal.invoke(obj, /*FIXME*/ null, /*FIXME*/ null);
364
365       if (m.getListener() != null)
366         m.getListener().beforeMarshal(obj);
367       
368       QName JavaDoc tagName = _elementName; //getElementName((C) obj);
369

370       if (tagName == null)
371         tagName = fieldName;
372       
373       if (tagName.getNamespaceURI() == null ||
374           tagName.getNamespaceURI().equals(""))
375         out.writeStartElement(tagName.getLocalPart());
376       else
377         out.writeStartElement(tagName.getNamespaceURI(),
378                               tagName.getLocalPart());
379
380       for (Accessor a : _elementAccessors.values())
381         a.write(m, out, a.get(obj));
382       
383       out.writeEndElement();
384       
385       if (_afterMarshal != null)
386         _afterMarshal.invoke(obj, /*FIXME*/ null, /*FIXME*/ null);
387       if (m.getListener() != null)
388         m.getListener().afterMarshal(obj);
389     }
390     catch (InvocationTargetException JavaDoc e) {
391       throw new JAXBException(e);
392     }
393     catch (IllegalAccessException JavaDoc e) {
394       throw new JAXBException(e);
395     }
396   }
397
398   public QName JavaDoc getElementName()
399   {
400     return _elementName;
401     /*
402     QName tagName = null;
403
404     if (tagName==null && _class.isAnnotationPresent(XmlRootElement.class)) {
405       XmlRootElement annotation = _class.getAnnotation(XmlRootElement.class);
406       String localname = annotation.name();
407       String namespace = annotation.namespace();
408
409       if (localname.equals("##default"))
410         tagName = null;
411       else if (namespace.equals("##default"))
412         tagName = new QName(localname);
413       else
414         tagName = new QName(namespace, localname);
415     }
416
417     if (tagName == null && _class.isAnnotationPresent(XmlElement.class)) {
418       XmlElement annotation = _class.getAnnotation(XmlElement.class);
419       String localname = annotation.name();
420       String namespace = annotation.namespace();
421
422       if (localname.equals("##default"))
423         tagName = null;
424       else if (namespace.equals("##default"))
425         tagName = new QName(localname);
426       else
427         tagName = new QName(namespace, localname);
428     }
429
430     return tagName;
431     */

432   }
433
434   public void generateSchema(XMLStreamWriter out)
435     throws JAXBException, XMLStreamException
436   {
437     if (_elementName != null) {
438
439       if ("".equals(_typeName.getLocalPart()))
440         out.writeStartElement(XML_SCHEMA_PREFIX, "element", XML_SCHEMA_NS);
441       else {
442         out.writeEmptyElement(XML_SCHEMA_PREFIX, "element", XML_SCHEMA_NS);
443         out.writeAttribute("type", _typeName.getLocalPart());
444       }
445
446       out.writeAttribute("name", _elementName.getLocalPart());
447     }
448
449     generateSchemaType(out);
450
451     if (_elementName != null && "".equals(_typeName.getLocalPart()))
452       out.writeEndElement(); // element
453
}
454
455   public void generateSchemaType(XMLStreamWriter out)
456     throws JAXBException, XMLStreamException
457   {
458     if (_value != null) {
459       out.writeStartElement(XML_SCHEMA_PREFIX, "simpleType", XML_SCHEMA_NS);
460
461       if (! "".equals(_typeName.getLocalPart()))
462         out.writeAttribute("name", _typeName.getLocalPart());
463
464       out.writeEmptyElement(XML_SCHEMA_PREFIX, "restriction", XML_SCHEMA_NS);
465       out.writeAttribute("base", _value.getSchemaType());
466
467       for (Accessor accessor : _attributeAccessors.values())
468         accessor.generateSchema(out);
469
470       out.writeEndElement(); // simpleType
471
}
472     else {
473       out.writeStartElement(XML_SCHEMA_PREFIX, "complexType", XML_SCHEMA_NS);
474
475       if (! "".equals(_typeName.getLocalPart()))
476         out.writeAttribute("name", _typeName.getLocalPart());
477
478       out.writeStartElement(XML_SCHEMA_PREFIX, "sequence", XML_SCHEMA_NS);
479
480       for (Accessor accessor : _elementAccessors.values())
481         accessor.generateSchema(out);
482
483       out.writeEndElement(); // sequence
484

485       for (Accessor accessor : _attributeAccessors.values())
486         accessor.generateSchema(out);
487
488       out.writeEndElement(); // complexType
489
}
490   }
491 }
492
Popular Tags