001: /*
002: * Copyright (c) 1998-2007 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Emil Ong, Adam Megacz
028: */
029:
030: package com.caucho.jaxb;
031:
032: import com.caucho.jaxb.skeleton.*;
033: import com.caucho.jaxb.property.*;
034: import com.caucho.server.util.CauchoSystem;
035: import com.caucho.util.L10N;
036: import com.caucho.xml.QNode;
037:
038: import org.w3c.dom.Node;
039:
040: import javax.activation.DataHandler;
041: import javax.xml.bind.*;
042: import javax.xml.bind.annotation.*;
043: import javax.xml.datatype.*;
044: import javax.xml.namespace.QName;
045: import javax.xml.stream.XMLInputFactory;
046: import javax.xml.stream.XMLOutputFactory;
047: import javax.xml.stream.XMLStreamException;
048: import javax.xml.stream.XMLStreamReader;
049: import javax.xml.stream.XMLStreamWriter;
050: import javax.xml.transform.Source;
051: import javax.xml.transform.Result;
052: import java.awt.Image;
053: import java.io.IOException;
054: import java.io.InputStream;
055: import java.io.InputStreamReader;
056: import java.io.LineNumberReader;
057: import java.lang.reflect.GenericArrayType;
058: import java.lang.reflect.Method;
059: import java.lang.reflect.ParameterizedType;
060: import java.lang.reflect.Type;
061: import java.math.BigDecimal;
062: import java.math.BigInteger;
063: import java.net.URI;
064: import java.util.*;
065:
066: /**
067: * Entry point to API
068: */
069: public class JAXBContextImpl extends JAXBContext {
070: public static final String XML_SCHEMA_NS = "http://www.w3.org/2001/XMLSchema";
071:
072: public static final String TARGET_NAMESPACE = "com.caucho.jaxb.targetNamespace";
073:
074: static final ValidationEventHandler DEFAULT_VALIDATION_EVENT_HANDLER = new DefaultValidationEventHandler();
075:
076: private static final L10N L = new L10N(JAXBContextImpl.class);
077:
078: private static final HashSet<Class> _specialClasses = new HashSet<Class>();
079:
080: static {
081: _specialClasses.add(Object.class);
082: _specialClasses.add(Class.class);
083: _specialClasses.add(String.class);
084: _specialClasses.add(Double.class);
085: _specialClasses.add(Float.class);
086: _specialClasses.add(Integer.class);
087: _specialClasses.add(Long.class);
088: _specialClasses.add(Boolean.class);
089: _specialClasses.add(Character.class);
090: _specialClasses.add(Short.class);
091: _specialClasses.add(Byte.class);
092: _specialClasses.add(BigDecimal.class);
093: _specialClasses.add(BigInteger.class);
094: _specialClasses.add(QName.class);
095: _specialClasses.add(Date.class);
096: _specialClasses.add(Calendar.class);
097: _specialClasses.add(XMLGregorianCalendar.class);
098: _specialClasses.add(UUID.class);
099: _specialClasses.add(DataHandler.class);
100: }
101:
102: private String _targetNamespace = null;
103:
104: private String[] _packages;
105: private JAXBIntrospector _jaxbIntrospector;
106:
107: private XMLInputFactory _staxInputFactory;
108: private XMLOutputFactory _staxOutputFactory;
109:
110: private final ArrayList<ObjectFactorySkeleton> _objectFactories = new ArrayList<ObjectFactorySkeleton>();
111:
112: private final HashMap<String, Object> _properties = new HashMap<String, Object>();
113:
114: private final LinkedHashMap<Class, ClassSkeleton> _classSkeletons = new LinkedHashMap<Class, ClassSkeleton>();
115:
116: private final LinkedHashMap<Class, JAXBElementSkeleton> _jaxbElementSkeletons = new LinkedHashMap<Class, JAXBElementSkeleton>();
117:
118: private final HashMap<QName, ClassSkeleton> _roots = new HashMap<QName, ClassSkeleton>();
119: private final HashMap<QName, ClassSkeleton> _types = new HashMap<QName, ClassSkeleton>();
120:
121: private final ArrayList<EnumProperty> _enums = new ArrayList<EnumProperty>();
122:
123: private HashSet<Class> _pendingSkeletons = new HashSet<Class>();
124:
125: private DynamicJAXBElementSkeleton _dynamicSkeleton;
126: private Property _laxAnyTypeProperty = null;
127:
128: private boolean _isDiscoveryFinished = false;
129:
130: public static JAXBContext createContext(String contextPath,
131: ClassLoader classLoader, Map<String, ?> properties)
132: throws JAXBException {
133: return new JAXBContextImpl(contextPath, classLoader, properties);
134: }
135:
136: public JAXBContextImpl(String contextPath, ClassLoader classLoader,
137: Map<String, ?> properties) throws JAXBException {
138: _jaxbIntrospector = new JAXBIntrospectorImpl(this );
139: StringTokenizer st = new StringTokenizer(contextPath, ":");
140:
141: if (properties != null)
142: _targetNamespace = (String) properties
143: .get(TARGET_NAMESPACE);
144:
145: do {
146: String packageName = st.nextToken();
147: loadPackage(packageName, classLoader);
148: } while (st.hasMoreTokens());
149:
150: init(properties);
151: }
152:
153: public static JAXBContext createContext(Class[] classes,
154: Map<String, ?> properties) throws JAXBException {
155: return new JAXBContextImpl(classes, properties);
156: }
157:
158: public JAXBContextImpl(Class[] classes, Map<String, ?> properties)
159: throws JAXBException {
160: _jaxbIntrospector = new JAXBIntrospectorImpl(this );
161: _packages = new String[0];
162:
163: if (properties != null)
164: _targetNamespace = (String) properties
165: .get(TARGET_NAMESPACE);
166:
167: for (Class c : classes) {
168: if (c.getName().endsWith(".ObjectFactory"))
169: introspectObjectFactory(c);
170: else if (!c.isPrimitive() && // XXX pull out to JAX-WS?
171: !c.isArray() && !_specialClasses.contains(c))
172: createSkeleton(c);
173: }
174:
175: init(properties);
176: }
177:
178: private void init(Map<String, ?> properties) throws JAXBException {
179: if (properties != null) {
180: for (Map.Entry<String, ?> e : properties.entrySet())
181: setProperty(e.getKey(), e.getValue());
182: }
183:
184: DatatypeConverter
185: .setDatatypeConverter(new DatatypeConverterImpl());
186:
187: _dynamicSkeleton = new DynamicJAXBElementSkeleton(this );
188:
189: _isDiscoveryFinished = true;
190:
191: for (ClassSkeleton skeleton : _classSkeletons.values())
192: skeleton.postProcess();
193: }
194:
195: public boolean isDiscoveryFinished() {
196: return _isDiscoveryFinished;
197: }
198:
199: public Marshaller createMarshaller() throws JAXBException {
200: return new MarshallerImpl(this );
201: }
202:
203: public Unmarshaller createUnmarshaller() throws JAXBException {
204: return new UnmarshallerImpl(this );
205: }
206:
207: public Validator createValidator() throws JAXBException {
208: throw new UnsupportedOperationException();
209: }
210:
211: XMLStreamReader getXMLStreamReader(InputStream is)
212: throws XMLStreamException {
213: if (_staxInputFactory == null)
214: _staxInputFactory = XMLInputFactory.newInstance();
215:
216: return _staxInputFactory.createXMLStreamReader(is);
217: }
218:
219: public XMLInputFactory getXMLInputFactory() {
220: if (_staxInputFactory == null)
221: _staxInputFactory = XMLInputFactory.newInstance();
222:
223: return _staxInputFactory;
224: }
225:
226: public XMLOutputFactory getXMLOutputFactory() {
227: if (_staxOutputFactory == null) {
228: _staxOutputFactory = XMLOutputFactory.newInstance();
229: _staxOutputFactory.setProperty(
230: XMLOutputFactory.IS_REPAIRING_NAMESPACES,
231: Boolean.TRUE);
232: }
233:
234: return _staxOutputFactory;
235: }
236:
237: public String getTargetNamespace() {
238: return _targetNamespace;
239: }
240:
241: public String toString() {
242: StringBuilder sb = new StringBuilder();
243: sb.append("JAXBContext[");
244:
245: for (Class c : _classSkeletons.keySet())
246: sb.append(c.getName() + ":");
247:
248: for (int i = 0; i < _packages.length; i++) {
249: String p = _packages[i];
250: sb.append(p + (i < _packages.length - 1 ? ":" : ""));
251: }
252:
253: sb.append("]");
254: return sb.toString();
255: }
256:
257: private void setProperty(String key, Object val) {
258: _properties.put(key, val);
259: }
260:
261: public Binder<Node> createBinder() {
262: return (Binder<Node>) new BinderImpl(this );
263: }
264:
265: public <T> Binder<T> createBinder(Class<T> domType) {
266: if (!domType.equals(QNode.class))
267: throw new UnsupportedOperationException(
268: "Unsupported implementation: " + domType);
269:
270: return (Binder) new BinderImpl(this );
271: }
272:
273: public JAXBIntrospector createJAXBIntrospector() {
274: return _jaxbIntrospector;
275: }
276:
277: public void generateSchema(SchemaOutputResolver outputResolver)
278: throws IOException {
279: Result result = outputResolver.createOutput("", "schema1.xsd");
280:
281: XMLStreamWriter out = null;
282:
283: try {
284: XMLOutputFactory factory = getXMLOutputFactory();
285: out = factory.createXMLStreamWriter(result);
286:
287: out.writeStartDocument("UTF-8", "1.0");
288:
289: out.writeStartElement("xsd", "schema", XML_SCHEMA_NS);
290: out.writeAttribute("version", "1.0");
291:
292: generateSchemaWithoutHeader(out);
293:
294: out.writeEndElement(); // schema
295: } catch (Exception e) {
296: IOException ioException = new IOException();
297:
298: ioException.initCause(e);
299:
300: throw ioException;
301: } finally {
302: try {
303: out.close();
304: } catch (XMLStreamException e) {
305: throw new IOException(e.toString());
306: }
307: }
308: }
309:
310: public void generateSchemaWithoutHeader(XMLStreamWriter out)
311: throws JAXBException, XMLStreamException {
312: for (ClassSkeleton skeleton : _classSkeletons.values())
313: skeleton.generateSchema(out);
314:
315: for (int i = 0; i < _enums.size(); i++)
316: ((EnumProperty) _enums.get(i)).generateSchema(out);
317: }
318:
319: public ClassSkeleton createSkeleton(Class c) throws JAXBException {
320: ClassSkeleton skeleton = _classSkeletons.get(c);
321:
322: if (skeleton != null)
323: return skeleton;
324:
325: if (Object.class.equals(c)) {
326: skeleton = new AnyTypeSkeleton(this );
327: _classSkeletons.put(c, skeleton);
328: } else {
329: // XXX
330: if (c.isEnum() || c.isInterface()) {
331: return null;
332: /*
333: throw new IllegalStateException(L.l("{0}: Can't create skeleton for an interface or enum",
334: c.getName()));
335: */
336: }
337:
338: skeleton = new ClassSkeleton(this , c);
339:
340: // Breadcrumb to prevent problems with recursion
341: _classSkeletons.put(c, skeleton);
342:
343: _pendingSkeletons.add(c);
344:
345: skeleton.init();
346:
347: _pendingSkeletons.remove(c);
348: }
349:
350: return skeleton;
351: }
352:
353: public ClassSkeleton getSkeleton(Class c) throws JAXBException {
354: return createSkeleton(c);
355: }
356:
357: public boolean hasSkeleton(Class c) {
358: return _classSkeletons.containsKey(c);
359: }
360:
361: public ClassSkeleton findSkeletonForClass(Class cl)
362: throws JAXBException {
363: return findSkeletonForClass(cl, _jaxbElementSkeletons);
364: }
365:
366: public ClassSkeleton findSkeletonForClass(Class cl,
367: Map<Class, ? extends ClassSkeleton> map) {
368: Class givenClass = cl;
369:
370: while (!cl.equals(Object.class)) {
371: ClassSkeleton skeleton = map.get(cl);
372:
373: if (skeleton != null)
374: return skeleton;
375:
376: cl = cl.getSuperclass();
377: }
378:
379: return null;
380: }
381:
382: public ClassSkeleton findSkeletonForObject(Object obj) {
383: if (obj instanceof JAXBElement) {
384: JAXBElement element = (JAXBElement) obj;
385:
386: obj = element.getValue();
387:
388: ClassSkeleton skeleton = findSkeletonForClass(obj
389: .getClass(), _jaxbElementSkeletons);
390:
391: if (skeleton == null)
392: skeleton = _dynamicSkeleton;
393:
394: return skeleton;
395: } else
396: return findSkeletonForClass(obj.getClass(), _classSkeletons);
397: }
398:
399: /**
400: * Finds all ClassSkeletons that are subclasses of the given class and
401: * are root elements.
402: **/
403: public List<ClassSkeleton> getRootElements(Class cl) {
404: ArrayList<ClassSkeleton> list = new ArrayList<ClassSkeleton>();
405:
406: for (Map.Entry<Class, ClassSkeleton> entry : _classSkeletons
407: .entrySet()) {
408: if (cl.isAssignableFrom(entry.getKey())
409: && entry.getValue().isRootElement())
410: list.add(entry.getValue());
411: }
412:
413: return list;
414: }
415:
416: public Property getLaxAnyTypeProperty() throws JAXBException {
417: if (_laxAnyTypeProperty == null)
418: _laxAnyTypeProperty = new LaxAnyTypeProperty(this );
419:
420: return _laxAnyTypeProperty;
421: }
422:
423: // XXX clean up all this argument tiering
424:
425: public Property createProperty(Type type) throws JAXBException {
426: return createProperty(type, false);
427: }
428:
429: public Property createProperty(Type type, boolean anyType)
430: throws JAXBException {
431: return createProperty(type, anyType, null);
432: }
433:
434: public Property createProperty(Type type, boolean anyType,
435: String mimeType) throws JAXBException {
436: return createProperty(type, anyType, mimeType, false);
437: }
438:
439: public Property createProperty(Type type, boolean anyType,
440: String mimeType, boolean xmlList) throws JAXBException {
441: return createProperty(type, anyType, mimeType, xmlList, false);
442: }
443:
444: public Property createProperty(Type type, boolean anyType,
445: String mimeType, boolean xmlList, boolean xmlValue)
446: throws JAXBException {
447: if (type instanceof Class) {
448: if (anyType && Object.class.equals(type))
449: return getLaxAnyTypeProperty();
450:
451: Property simpleTypeProperty = getSimpleTypeProperty(
452: (Class) type, mimeType);
453:
454: if (simpleTypeProperty != null) {
455: // jaxb/12gb
456: if (simpleTypeProperty == ByteArrayProperty.PROPERTY
457: && xmlList && !xmlValue)
458: throw new JAXBException(
459: L
460: .l("@XmlList applied to byte[] valued fields or properties"));
461:
462: return simpleTypeProperty;
463: }
464:
465: Class cl = (Class) type;
466:
467: if (cl.isArray()) {
468: Property componentProperty = createProperty(cl
469: .getComponentType(), anyType);
470:
471: if (xmlList) {
472: if (!(componentProperty instanceof CDataProperty))
473: throw new JAXBException(
474: L
475: .l("Elements annotated with @XmlList or @XmlValue must be simple XML types"));
476:
477: Class componentType = cl.getComponentType();
478: CDataProperty cdataProperty = (CDataProperty) componentProperty;
479:
480: return XmlListArrayProperty
481: .createXmlListArrayProperty(cdataProperty,
482: componentType);
483: } else
484: return ArrayProperty.createArrayProperty(
485: componentProperty, cl.getComponentType());
486: }
487:
488: if (cl.isEnum()) {
489: EnumProperty enumProperty = new EnumProperty(cl, this );
490: _enums.add(enumProperty);
491:
492: return enumProperty;
493: }
494:
495: // XXX Map
496:
497: if (List.class.isAssignableFrom(cl)) {
498: Property property = new SkeletonProperty(
499: getSkeleton(Object.class));
500:
501: if (xmlList) {
502: throw new JAXBException(
503: L
504: .l("Elements annotated with @XmlList or @XmlValue must be simple XML types"));
505: } else
506: return new ListProperty(property);
507: }
508:
509: if (Collection.class.isAssignableFrom(cl)) {
510: Property property = new SkeletonProperty(
511: getSkeleton(Object.class));
512:
513: if (xmlList) {
514: throw new JAXBException(
515: L
516: .l("Elements annotated with @XmlList or @XmlValue must be simple XML types"));
517: } else
518: return new CollectionProperty(property);
519: }
520:
521: ClassSkeleton skel = getSkeleton(cl);
522:
523: // XXX: interfaces
524: if (skel != null)
525: return new SkeletonProperty(skel);
526: else
527: return null;
528: } else if (type instanceof ParameterizedType) {
529: ParameterizedType ptype = (ParameterizedType) type;
530: Type rawType = ptype.getRawType();
531:
532: if (rawType instanceof Class) {
533: Class rawClass = (Class) rawType;
534:
535: if (Map.class.isAssignableFrom(rawClass)) {
536: Type[] args = ptype.getActualTypeArguments();
537:
538: if (args.length != 2)
539: throw new JAXBException(
540: L
541: .l(
542: "unexpected number of generic arguments for Map<>: {0}",
543: args.length));
544:
545: Property keyProperty = createProperty(args[0],
546: anyType);
547: Property valueProperty = createProperty(args[1],
548: anyType);
549:
550: return new MapProperty(rawClass, keyProperty,
551: valueProperty);
552: }
553:
554: if (Collection.class.isAssignableFrom(rawClass)) {
555: Type[] args = ptype.getActualTypeArguments();
556:
557: if (args.length != 1)
558: throw new JAXBException(
559: L
560: .l(
561: "unexpected number of generic arguments for List<>: {0}",
562: args.length));
563:
564: Property componentProperty = createProperty(
565: args[0], anyType);
566:
567: if (xmlList) {
568: if (!(componentProperty instanceof CDataProperty))
569: throw new JAXBException(
570: L
571: .l("Elements annotated with @XmlList or @XmlValue must be simple XML types"));
572:
573: CDataProperty cdataProperty = (CDataProperty) componentProperty;
574:
575: return new XmlListCollectionProperty(
576: cdataProperty, rawClass);
577: } else if (List.class.isAssignableFrom(rawClass))
578: return new ListProperty(componentProperty);
579: else
580: return new CollectionProperty(componentProperty);
581: }
582: }
583: } else if (type instanceof GenericArrayType) {
584: Type component = ((GenericArrayType) type)
585: .getGenericComponentType();
586:
587: if (byte.class.equals(component))
588: return ByteArrayProperty.PROPERTY;
589:
590: // XXX other component types?
591: }
592:
593: throw new JAXBException(L.l("Unrecognized type: {0}", type
594: .toString()));
595: }
596:
597: public Property getSimpleTypeProperty(Class type)
598: throws JAXBException {
599: return getSimpleTypeProperty(type, null);
600: }
601:
602: public Property getSimpleTypeProperty(Class type, String mimeType)
603: throws JAXBException {
604: if (String.class.equals(type))
605: return StringProperty.PROPERTY;
606:
607: if (URI.class.equals(type))
608: return URIProperty.PROPERTY;
609:
610: if (UUID.class.equals(type))
611: return UUIDProperty.PROPERTY;
612:
613: if (Double.class.equals(type))
614: return DoubleProperty.OBJECT_PROPERTY;
615:
616: if (Double.TYPE.equals(type))
617: return DoubleProperty.PRIMITIVE_PROPERTY;
618:
619: if (Float.class.equals(type))
620: return FloatProperty.OBJECT_PROPERTY;
621:
622: if (Float.TYPE.equals(type))
623: return FloatProperty.PRIMITIVE_PROPERTY;
624:
625: if (Integer.class.equals(type))
626: return IntProperty.OBJECT_PROPERTY;
627:
628: if (Integer.TYPE.equals(type))
629: return IntProperty.PRIMITIVE_PROPERTY;
630:
631: if (Long.class.equals(type))
632: return LongProperty.OBJECT_PROPERTY;
633:
634: if (Long.TYPE.equals(type))
635: return LongProperty.PRIMITIVE_PROPERTY;
636:
637: if (Boolean.class.equals(type))
638: return BooleanProperty.OBJECT_PROPERTY;
639:
640: if (Boolean.TYPE.equals(type))
641: return BooleanProperty.PRIMITIVE_PROPERTY;
642:
643: if (Character.class.equals(type))
644: return CharacterProperty.OBJECT_PROPERTY;
645:
646: if (Character.TYPE.equals(type))
647: return CharacterProperty.PRIMITIVE_PROPERTY;
648:
649: if (Short.class.equals(type))
650: return ShortProperty.OBJECT_PROPERTY;
651:
652: if (Short.TYPE.equals(type))
653: return ShortProperty.PRIMITIVE_PROPERTY;
654:
655: if (Byte.class.equals(type))
656: return ByteProperty.OBJECT_PROPERTY;
657:
658: if (Byte.TYPE.equals(type))
659: return ByteProperty.PRIMITIVE_PROPERTY;
660:
661: if (BigDecimal.class.equals(type))
662: return BigDecimalProperty.PROPERTY;
663:
664: if (BigInteger.class.equals(type))
665: return BigIntegerProperty.PROPERTY;
666:
667: if (QName.class.equals(type))
668: return QNameProperty.PROPERTY;
669:
670: if (Date.class.equals(type))
671: return DateTimeProperty.PROPERTY;
672:
673: if (Calendar.class.equals(type))
674: return CalendarProperty.PROPERTY;
675:
676: if (Duration.class.equals(type))
677: return DurationProperty.PROPERTY;
678:
679: if (XMLGregorianCalendar.class.equals(type))
680: return XMLGregorianCalendarProperty.PROPERTY;
681:
682: if (Image.class.equals(type))
683: return ImageProperty.getImageProperty(mimeType);
684:
685: if (DataHandler.class.equals(type))
686: return DataHandlerProperty.PROPERTY;
687:
688: if (Source.class.equals(type))
689: return SourceProperty.PROPERTY;
690:
691: if (byte[].class.equals(type))
692: return ByteArrayProperty.PROPERTY;
693:
694: return null;
695: }
696:
697: public void addXmlType(QName typeName, ClassSkeleton skeleton)
698: throws JAXBException {
699: if (_types.containsKey(typeName)) {
700: ClassSkeleton existing = _types.get(typeName);
701:
702: if (!_pendingSkeletons.contains(existing.getType())) {
703: throw new JAXBException(
704: L
705: .l(
706: "Duplicate type name {0} for types {1} and {2}",
707: typeName, skeleton.getType(),
708: existing.getType()));
709: }
710: }
711:
712: _types.put(typeName, skeleton);
713: }
714:
715: public void addRootElement(ClassSkeleton s) throws JAXBException {
716: ClassSkeleton old = _roots.get(s.getElementName());
717:
718: // Use != here to check duplicate puts; equals() isn't necessary
719: if (old != null && old != s
720: && !_pendingSkeletons.contains(s.getType())) {
721: throw new JAXBException(L.l(
722: "Duplicate name {0} for classes {1} and {2}", s
723: .getElementName(), s.getType(), _roots.get(
724: s.getElementName()).getType()));
725: }
726:
727: _roots.put(s.getElementName(), s);
728: }
729:
730: public boolean hasXmlType(QName typeName) {
731: return _types.containsKey(typeName);
732: }
733:
734: public boolean hasRootElement(QName elementName) {
735: return _roots.containsKey(elementName);
736: }
737:
738: public ClassSkeleton getRootElement(QName q) {
739: return _roots.get(q);
740: }
741:
742: private void loadPackage(String packageName, ClassLoader classLoader)
743: throws JAXBException {
744: boolean success = false;
745:
746: try {
747: Class cl = Class.forName(packageName + ".ObjectFactory");
748: introspectObjectFactory(cl);
749:
750: success = true;
751: } catch (ClassNotFoundException e) {
752: // we can still try for jaxb.index
753: }
754:
755: String resourceName = packageName.replace('.', '/')
756: + "/jaxb.index";
757:
758: // For some reason, this approach works when running resin...
759: InputStream is = this .getClass().getResourceAsStream(
760: '/' + resourceName);
761:
762: // ...and this approach works in QA
763: if (is == null)
764: is = classLoader.getResourceAsStream(resourceName);
765:
766: if (is == null) {
767: if (success)
768: return;
769:
770: throw new JAXBException(L.l(
771: "Unable to open jaxb.index for package {0}",
772: packageName));
773: }
774:
775: try {
776: InputStreamReader isr = new InputStreamReader(is, "utf-8");
777: LineNumberReader in = new LineNumberReader(isr);
778:
779: for (String line = in.readLine(); line != null; line = in
780: .readLine()) {
781: String[] parts = line.split("#", 2);
782: String className = parts[0].trim();
783:
784: if (!"".equals(className)) {
785: Class cl = classLoader.loadClass(packageName + "."
786: + className);
787:
788: createSkeleton(cl);
789: }
790: }
791: } catch (IOException e) {
792: throw new JAXBException(L.l(
793: "Error while reading jaxb.index for package {0}",
794: packageName), e);
795: } catch (ClassNotFoundException e) {
796: throw new JAXBException(e);
797: }
798: }
799:
800: private void introspectObjectFactory(Class factoryClass)
801: throws JAXBException {
802: Object objectFactory = null;
803:
804: try {
805: objectFactory = factoryClass.newInstance();
806: } catch (Exception e) {
807: throw new JAXBException(e);
808: }
809:
810: String namespace = null;
811: Package pkg = factoryClass.getPackage();
812:
813: if (pkg.isAnnotationPresent(XmlSchema.class)) {
814: XmlSchema schema = (XmlSchema) pkg
815: .getAnnotation(XmlSchema.class);
816:
817: if (!"".equals(schema.namespace()))
818: namespace = schema.namespace();
819: }
820:
821: Method[] methods = factoryClass.getMethods();
822:
823: for (Method method : methods) {
824: if (method.getName().startsWith("create")) {
825: XmlElementDecl decl = method
826: .getAnnotation(XmlElementDecl.class);
827: Class cl = method.getReturnType();
828:
829: ClassSkeleton skeleton = null;
830: QName root = null;
831:
832: if (cl.equals(JAXBElement.class)) {
833: ParameterizedType type = (ParameterizedType) method
834: .getGenericReturnType();
835: cl = (Class) type.getActualTypeArguments()[0];
836:
837: skeleton = new JAXBElementSkeleton(this , cl,
838: method, objectFactory);
839: _jaxbElementSkeletons.put(cl,
840: (JAXBElementSkeleton) skeleton);
841: } else {
842: skeleton = getSkeleton(cl);
843:
844: if (skeleton == null)
845: skeleton = createSkeleton(cl);
846:
847: skeleton.setCreateMethod(method, objectFactory);
848:
849: root = skeleton.getElementName();
850: }
851:
852: if (decl != null) {
853: String localName = decl.name();
854:
855: if (!"##default".equals(decl.namespace()))
856: namespace = decl.namespace();
857:
858: if (namespace == null)
859: root = new QName(localName);
860: else
861: root = new QName(namespace, localName);
862: }
863:
864: skeleton.setElementName(root);
865: addRootElement(skeleton);
866: } else if (method.getName().equals("newInstance")) {
867: // XXX
868: } else if (method.getName().equals("getProperty")) {
869: // XXX
870: } else if (method.getName().equals("setProperty")) {
871: // XXX
872: }
873: }
874: }
875:
876: static class DefaultValidationEventHandler implements
877: ValidationEventHandler {
878: public boolean handleEvent(ValidationEvent event) {
879: if (event == null)
880: throw new IllegalArgumentException(
881: "Event may not be null");
882:
883: return event.getSeverity() != ValidationEvent.FATAL_ERROR;
884: }
885: }
886: }
|