001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.jaxb;
019:
020: import java.io.OutputStream;
021: import java.lang.reflect.Array;
022: import java.lang.reflect.GenericArrayType;
023: import java.lang.reflect.Modifier;
024: import java.lang.reflect.ParameterizedType;
025: import java.lang.reflect.Type;
026: import java.util.ArrayList;
027: import java.util.Arrays;
028: import java.util.Collection;
029: import java.util.List;
030: import java.util.ResourceBundle;
031:
032: import javax.xml.bind.JAXBContext;
033: import javax.xml.bind.JAXBElement;
034: import javax.xml.bind.JAXBException;
035: import javax.xml.bind.Marshaller;
036: import javax.xml.bind.Unmarshaller;
037: import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
038: import javax.xml.bind.attachment.AttachmentMarshaller;
039: import javax.xml.bind.attachment.AttachmentUnmarshaller;
040: import javax.xml.namespace.QName;
041: import javax.xml.stream.XMLEventReader;
042: import javax.xml.stream.XMLEventWriter;
043: import javax.xml.stream.XMLStreamReader;
044: import javax.xml.stream.XMLStreamWriter;
045: import javax.xml.validation.Schema;
046:
047: import org.w3c.dom.Element;
048: import org.w3c.dom.Node;
049:
050: import org.apache.cxf.common.i18n.BundleUtils;
051: import org.apache.cxf.common.i18n.Message;
052: import org.apache.cxf.helpers.CastUtils;
053: import org.apache.cxf.interceptor.Fault;
054: import org.apache.cxf.service.model.MessagePartInfo;
055: import org.apache.cxf.staxutils.StaxUtils;
056: import org.apache.ws.commons.schema.XmlSchemaElement;
057: import org.apache.ws.commons.schema.XmlSchemaSimpleType;
058: import org.apache.ws.commons.schema.XmlSchemaSimpleTypeList;
059:
060: /**
061: * Utility functions for JAXB.
062: */
063: public final class JAXBEncoderDecoder {
064: private static final ResourceBundle BUNDLE = BundleUtils
065: .getBundle(JAXBEncoderDecoder.class);
066:
067: private JAXBEncoderDecoder() {
068: }
069:
070: private static Marshaller createMarshaller(JAXBContext context,
071: Class<?> cls) throws JAXBException {
072: Marshaller jm = null;
073: if (context == null) {
074: context = JAXBContext.newInstance(cls);
075: }
076:
077: jm = context.createMarshaller();
078: jm.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
079: jm.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
080:
081: return jm;
082: }
083:
084: @SuppressWarnings("unchecked")
085: public static void marshall(JAXBContext context, Schema schema,
086: Object elValue, MessagePartInfo part, Object source,
087: AttachmentMarshaller am) {
088: Class<?> cls = null;
089: if (part != null) {
090: cls = part.getTypeClass();
091: }
092:
093: if (cls == null) {
094: cls = null != elValue ? elValue.getClass() : null;
095: }
096:
097: if (cls != null && cls.isArray()
098: && elValue instanceof Collection) {
099: Collection<?> col = (Collection<?>) elValue;
100: elValue = col.toArray((Object[]) Array.newInstance(cls
101: .getComponentType(), 0));
102: }
103:
104: try {
105: Marshaller u = createMarshaller(context, cls);
106: try {
107: // The Marshaller.JAXB_FRAGMENT will tell the Marshaller not to
108: // generate the xml declaration.
109: u.setProperty(Marshaller.JAXB_FRAGMENT, true);
110: u.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);
111: } catch (javax.xml.bind.PropertyException e) {
112: // intentionally empty.
113: }
114: Object mObj = elValue;
115: QName elName = null;
116: if (part != null) {
117: elName = part.getConcreteName();
118: }
119: u.setSchema(schema);
120: if (am != null) {
121: u.setAttachmentMarshaller(am);
122: }
123:
124: if (null != elName) {
125:
126: if (part != null
127: && part.getXmlSchema() instanceof XmlSchemaElement) {
128:
129: XmlSchemaElement el = (XmlSchemaElement) part
130: .getXmlSchema();
131:
132: if (mObj.getClass().isArray()
133: && el.getSchemaType() instanceof XmlSchemaSimpleType
134: && ((XmlSchemaSimpleType) el
135: .getSchemaType()).getContent() instanceof XmlSchemaSimpleTypeList) {
136: mObj = Arrays.asList((Object[]) mObj);
137: writeObject(u, source, new JAXBElement(elName,
138: cls, mObj));
139: } else if (part.getMessageInfo().getOperation()
140: .isUnwrapped()
141: && (mObj.getClass().isArray() || mObj instanceof List)
142: && el.getMaxOccurs() != 1) {
143: //Have to handle this ourselves.... which really sucks.... but what can we do?
144: Object objArray[];
145: if (mObj instanceof List) {
146: List l = (List) mObj;
147: objArray = l.toArray(new Object[l.size()]);
148: cls = null;
149: } else {
150: objArray = (Object[]) mObj;
151: cls = cls.getComponentType();
152: }
153: for (Object o : objArray) {
154: writeObject(u, source, new JAXBElement(
155: elName, cls == null ? o.getClass()
156: : cls, o));
157: }
158: } else {
159: writeObject(u, source, new JAXBElement(elName,
160: cls, mObj));
161: }
162: } else if (byte[].class == cls
163: && part.getTypeQName() != null
164: && part.getTypeQName().getLocalPart().equals(
165: "hexBinary")) {
166: mObj = new HexBinaryAdapter()
167: .marshal((byte[]) mObj);
168: writeObject(u, source, new JAXBElement(elName,
169: String.class, mObj));
170: } else {
171: writeObject(u, source, new JAXBElement(elName, cls,
172: mObj));
173: }
174: } else {
175: writeObject(u, source, mObj);
176: }
177: } catch (Fault ex) {
178: throw (Fault) ex.fillInStackTrace();
179: } catch (Exception ex) {
180: if (ex instanceof javax.xml.bind.MarshalException) {
181: javax.xml.bind.MarshalException marshalEx = (javax.xml.bind.MarshalException) ex;
182: Message faultMessage = new Message("MARSHAL_ERROR",
183: BUNDLE, marshalEx.getLinkedException()
184: .getMessage());
185: throw new Fault(faultMessage, ex);
186: } else {
187: throw new Fault(new Message("MARSHAL_ERROR", BUNDLE, ex
188: .getMessage()), ex);
189: }
190: }
191: }
192:
193: private static void writeObject(Marshaller u, Object source,
194: Object mObj) throws Fault, JAXBException {
195: if (source instanceof XMLStreamWriter) {
196: u.marshal(mObj, (XMLStreamWriter) source);
197: } else if (source instanceof OutputStream) {
198: u.marshal(mObj, (OutputStream) source);
199: } else if (source instanceof Node) {
200: u.marshal(mObj, (Node) source);
201: } else if (source instanceof XMLEventWriter) {
202: u.marshal(mObj, (XMLEventWriter) source);
203: } else {
204: throw new Fault(new Message("UNKNOWN_SOURCE", BUNDLE,
205: source.getClass().getName()));
206: }
207: }
208:
209: public static void marshall(JAXBContext context, Schema schema,
210: Object elValue, Object source) {
211: marshall(context, schema, elValue, null, source, null);
212: }
213:
214: public static void marshall(JAXBContext context, Schema schema,
215: Object elValue, MessagePartInfo part, Object source) {
216: marshall(context, schema, elValue, part, source, null);
217: }
218:
219: private static Unmarshaller createUnmarshaller(JAXBContext context,
220: Class<?> cls) throws JAXBException {
221: Unmarshaller um = null;
222: if (context == null) {
223: if (cls == null) {
224: throw new IllegalStateException(
225: "A JAXBContext or Class to unmarshal must be provided!");
226: }
227: context = JAXBContext.newInstance(cls);
228: }
229:
230: um = context.createUnmarshaller();
231:
232: return um;
233: }
234:
235: public static Object unmarshall(JAXBContext context, Schema schema,
236: Object source) {
237: return unmarshall(context, schema, source, null, null, true);
238: }
239:
240: @SuppressWarnings("unchecked")
241: public static Object unmarshall(JAXBContext context, Schema schema,
242: Object source, MessagePartInfo part,
243: AttachmentUnmarshaller au, boolean unwrap) {
244: Class<?> clazz = part != null ? (Class) part.getTypeClass()
245: : null;
246: QName elName = part != null ? part.getConcreteName() : null;
247: if (clazz != null && clazz.isArray() && part != null
248: && part.getXmlSchema() instanceof XmlSchemaElement) {
249: XmlSchemaElement el = (XmlSchemaElement) part
250: .getXmlSchema();
251:
252: if (el.getSchemaType() instanceof XmlSchemaSimpleType
253: && ((XmlSchemaSimpleType) el.getSchemaType())
254: .getContent() instanceof XmlSchemaSimpleTypeList) {
255:
256: Object obj = unmarshall(context, schema, source,
257: elName, null, au, unwrap);
258: if (clazz.isArray() && obj instanceof List) {
259: return ((List) obj).toArray((Object[]) Array
260: .newInstance(clazz.getComponentType(),
261: ((List) obj).size()));
262: }
263:
264: return obj;
265: } else if (part.getMessageInfo().getOperation()
266: .isUnwrapped()
267: && el.getMaxOccurs() != 1) {
268: //must read ourselves....
269: Collection<Object> ret = unmarshallArray(context,
270: schema, source, elName, clazz
271: .getComponentType(), au,
272: createList(part));
273: if (isList(part)) {
274: return ret;
275: }
276: return ret.toArray((Object[]) java.lang.reflect.Array
277: .newInstance(clazz.getComponentType(), ret
278: .size()));
279: }
280: } else if (byte[].class == clazz
281: && part != null
282: && part.getTypeQName() != null
283: && part.getTypeQName().getLocalPart().equals(
284: "hexBinary")) {
285:
286: String obj = (String) unmarshall(context, schema, source,
287: elName, String.class, au, unwrap);
288: return new HexBinaryAdapter().unmarshal(obj);
289: }
290:
291: Object o = unmarshall(context, schema, source, elName, clazz,
292: au, unwrap);
293: if (o != null && o.getClass().isArray() && isList(part)) {
294: Collection<Object> ret = createList(part);
295: ret.addAll(Arrays.asList((Object[]) o));
296: o = ret;
297: }
298: return o;
299: }
300:
301: private static Collection<Object> createList(MessagePartInfo part) {
302: Type genericType = (Type) part.getProperty("generic.type");
303: if (genericType instanceof ParameterizedType) {
304: Type tp2 = ((ParameterizedType) genericType).getRawType();
305: if (tp2 instanceof Class) {
306: Class<?> cls = (Class) tp2;
307: if (!cls.isInterface()
308: && Collection.class
309: .isAssignableFrom((Class<?>) cls)) {
310: try {
311: return CastUtils.cast((Collection) cls
312: .newInstance());
313: } catch (Exception e) {
314: //ignore, just return an ArrayList
315: }
316: }
317: }
318: }
319:
320: return new ArrayList<Object>();
321: }
322:
323: private static boolean isList(MessagePartInfo part) {
324: if (part.getTypeClass().isArray()
325: && !part.getTypeClass().getComponentType()
326: .isPrimitive()) {
327: //&& Collection.class.isAssignableFrom(part.getTypeClass())) {
328: //it's List Para
329: //
330: Type genericType = (Type) part.getProperty("generic.type");
331:
332: if (genericType instanceof ParameterizedType) {
333: Type tp2 = ((ParameterizedType) genericType)
334: .getRawType();
335: if (tp2 instanceof Class) {
336: return Collection.class
337: .isAssignableFrom((Class<?>) tp2);
338: }
339: }
340: }
341: return false;
342: }
343:
344: public static Object unmarshall(JAXBContext context, Schema schema,
345: Object source, QName elName, Class<?> clazz,
346: AttachmentUnmarshaller au, boolean unwrap) {
347: Object obj = null;
348:
349: try {
350: Unmarshaller u = createUnmarshaller(context, clazz);
351: u.setSchema(schema);
352: if (au != null) {
353: u.setAttachmentUnmarshaller(au);
354: }
355: boolean unmarshalWithClass = true;
356:
357: if (clazz == null
358: || (!clazz.isPrimitive() && !clazz.isArray()
359: && !clazz.isEnum() && (Modifier
360: .isAbstract(clazz.getModifiers()) || Modifier
361: .isInterface(clazz.getModifiers())))) {
362: unmarshalWithClass = false;
363: }
364:
365: if (clazz != null
366: && (clazz.getName().equals(
367: "javax.xml.datatype.XMLGregorianCalendar") || clazz
368: .getName().equals(
369: "javax.xml.datatype.Duration"))) {
370: //special treat two jaxb defined built-in abstract types
371: unmarshalWithClass = true;
372: }
373: if (source instanceof Node) {
374: obj = unmarshalWithClass ? u.unmarshal((Node) source,
375: clazz) : u.unmarshal((Node) source);
376: } else if (source instanceof XMLStreamReader) {
377:
378: obj = unmarshalWithClass ? u.unmarshal(
379: (XMLStreamReader) source, clazz) : u
380: .unmarshal((XMLStreamReader) source);
381: } else if (source instanceof XMLEventReader) {
382: obj = unmarshalWithClass ? u.unmarshal(
383: (XMLEventReader) source, clazz) : u
384: .unmarshal((XMLEventReader) source);
385: } else {
386: throw new Fault(new Message("UNKNOWN_SOURCE", BUNDLE,
387: source.getClass().getName()));
388: }
389: } catch (Fault ex) {
390: ex.fillInStackTrace();
391: throw ex;
392: } catch (Exception ex) {
393: if (ex instanceof javax.xml.bind.UnmarshalException) {
394: javax.xml.bind.UnmarshalException unmarshalEx = (javax.xml.bind.UnmarshalException) ex;
395: throw new Fault(new Message("UNMARSHAL_ERROR", BUNDLE,
396: unmarshalEx.getLinkedException().getMessage()),
397: ex);
398: } else {
399: throw new Fault(new Message("UNMARSHAL_ERROR", BUNDLE,
400: ex.getMessage()), ex);
401: }
402: }
403: return unwrap ? getElementValue(obj) : obj;
404: }
405:
406: public static Object getElementValue(Object obj) {
407: if (null == obj) {
408: return null;
409: }
410:
411: if (obj instanceof JAXBElement) {
412: return ((JAXBElement<?>) obj).getValue();
413: }
414: return obj;
415: }
416:
417: public static Class<?> getClassFromType(Type t) {
418: if (t instanceof Class) {
419: return (Class) t;
420: } else if (t instanceof GenericArrayType) {
421: GenericArrayType g = (GenericArrayType) t;
422: return Array.newInstance(
423: getClassFromType(g.getGenericComponentType()), 0)
424: .getClass();
425: } else if (t instanceof ParameterizedType) {
426: ParameterizedType p = (ParameterizedType) t;
427: return getClassFromType(p.getRawType());
428: }
429: // TypeVariable and WildCardType are not handled as it is unlikely such
430: // Types will
431: // JAXB Code Generated.
432: assert false;
433: throw new IllegalArgumentException(
434: "Cannot get Class object from unknown Type");
435: }
436:
437: public static Collection<Object> unmarshallArray(
438: JAXBContext context, Schema schema, Object source,
439: QName elName, Class<?> clazz, AttachmentUnmarshaller au,
440: Collection<Object> ret) {
441: try {
442: Unmarshaller u = createUnmarshaller(context, clazz);
443: u.setSchema(schema);
444: if (au != null) {
445: u.setAttachmentUnmarshaller(au);
446: }
447: XMLStreamReader reader;
448: if (source instanceof XMLStreamReader) {
449: reader = (XMLStreamReader) source;
450: } else if (source instanceof Element) {
451: reader = StaxUtils
452: .createXMLStreamReader((Element) source);
453: } else {
454: throw new Fault(new Message("UNKNOWN_SOURCE", BUNDLE,
455: source.getClass().getName()));
456: }
457: while (reader.getName().equals(elName)) {
458: Object obj = u.unmarshal(reader, clazz);
459: if (obj instanceof JAXBElement) {
460: obj = ((JAXBElement) obj).getValue();
461: }
462: ret.add(obj);
463: }
464: return ret;
465: } catch (Fault ex) {
466: ex.fillInStackTrace();
467: throw ex;
468: } catch (Exception ex) {
469: if (ex instanceof javax.xml.bind.UnmarshalException) {
470: javax.xml.bind.UnmarshalException unmarshalEx = (javax.xml.bind.UnmarshalException) ex;
471: throw new Fault(new Message("UNMARSHAL_ERROR", BUNDLE,
472: unmarshalEx.getLinkedException().getMessage()),
473: ex);
474: } else {
475: throw new Fault(new Message("UNMARSHAL_ERROR", BUNDLE,
476: ex.getMessage()), ex);
477: }
478: }
479: }
480: }
|