/******************************************************************************* | |
* Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved. | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Oracle - initial API and implementation from Oracle TopLink | |
******************************************************************************/ | |
package org.eclipse.persistence.jaxb; | |
import java.io.FileOutputStream; | |
import java.io.OutputStream; | |
import java.io.Writer; | |
import java.io.File; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import javax.xml.bind.JAXBElement; | |
import javax.xml.bind.JAXBException; | |
import javax.xml.bind.MarshalException; | |
import javax.xml.bind.Marshaller; | |
import javax.xml.bind.PropertyException; | |
import javax.xml.bind.ValidationEventHandler; | |
import javax.xml.bind.annotation.adapters.XmlAdapter; | |
import javax.xml.bind.attachment.AttachmentMarshaller; | |
import javax.xml.namespace.QName; | |
import javax.xml.stream.XMLEventWriter; | |
import javax.xml.stream.XMLStreamWriter; | |
import javax.xml.transform.Result; | |
import javax.xml.validation.Schema; | |
import java.lang.reflect.Array; | |
import java.lang.reflect.Type; | |
import org.w3c.dom.Node; | |
import org.xml.sax.ContentHandler; | |
import org.eclipse.persistence.oxm.CharacterEscapeHandler; | |
import org.eclipse.persistence.oxm.JSONWithPadding; | |
import org.eclipse.persistence.oxm.MediaType; | |
import org.eclipse.persistence.oxm.NamespacePrefixMapper; | |
import org.eclipse.persistence.oxm.XMLMarshalListener; | |
import org.eclipse.persistence.oxm.XMLMarshaller; | |
import org.eclipse.persistence.oxm.record.MarshalRecord; | |
import org.eclipse.persistence.oxm.record.XMLEventWriterRecord; | |
import org.eclipse.persistence.oxm.record.XMLStreamWriterRecord; | |
import org.eclipse.persistence.core.queries.CoreAttributeGroup; | |
import org.eclipse.persistence.descriptors.ClassDescriptor; | |
import org.eclipse.persistence.exceptions.XMLMarshalException; | |
import org.eclipse.persistence.internal.core.helper.CoreClassConstants; | |
import org.eclipse.persistence.internal.helper.ClassConstants; | |
import org.eclipse.persistence.internal.jaxb.many.ManyValue; | |
import org.eclipse.persistence.internal.jaxb.ObjectGraphImpl; | |
import org.eclipse.persistence.internal.jaxb.WrappedValue; | |
import org.eclipse.persistence.internal.oxm.Constants; | |
import org.eclipse.persistence.internal.oxm.Root; | |
import org.eclipse.persistence.internal.oxm.record.CharacterEscapeHandlerWrapper; | |
import org.eclipse.persistence.internal.oxm.record.namespaces.MapNamespacePrefixMapper; | |
import org.eclipse.persistence.internal.oxm.record.namespaces.NamespacePrefixMapperWrapper; | |
import org.eclipse.persistence.jaxb.JAXBContext.RootLevelXmlAdapter; | |
import org.eclipse.persistence.jaxb.attachment.*; | |
/** | |
* INTERNAL: | |
* <p> | |
* <b>Purpose:</b>To Provide an implementation of the JAXB 2.0 Marshaller | |
* Interface | |
* <p> | |
* <b>Responsibilities:</b> | |
* <ul> | |
* <li>Provide a JAXB wrapper on the XMLMarshaller API</li> | |
* <li>Perform Object to XML Conversions</li> | |
* </ul> | |
* <p>This implementation of the JAXB 2.1/2.2 Marshaller interface provides the | |
* required functionality by acting as a thin wrapper on the existing | |
* XMLMarshaller API.</p> | |
* | |
* @author mmacivor | |
* @since Oracle TopLink 11.1.1.0.0 | |
* @see javax.xml.bind.Marshaller | |
* @see org.eclipse.persistence.jaxb.MarshallerProperties | |
* @see org.eclipse.persistence.oxm.XMLMarshaller | |
*/ | |
public class JAXBMarshaller implements javax.xml.bind.Marshaller { | |
private ValidationEventHandler validationEventHandler; | |
private XMLMarshaller xmlMarshaller; | |
private JAXBContext jaxbContext; | |
public static final String XML_JAVATYPE_ADAPTERS = "xml-javatype-adapters"; | |
private static final String SUN_NAMESPACE_PREFIX_MAPPER = "com.sun.xml.bind.namespacePrefixMapper"; | |
private static final String SUN_JSE_NAMESPACE_PREFIX_MAPPER = "com.sun.xml.internal.bind.namespacePrefixMapper"; | |
private static final String SUN_INDENT_STRING = "com.sun.xml.bind.indentString"; | |
private static final String SUN_JSE_INDENT_STRING = "com.sun.xml.internal.bind.indentString"; | |
private static final String SUN_CHARACTER_ESCAPE_HANDLER_MARSHALLER = "com.sun.xml.bind.marshaller.CharacterEscapeHandler"; | |
private static final String SUN_JSE_CHARACTER_ESCAPE_HANDLER_MARSHALLER = "com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler"; | |
private static final String SUN_CHARACTER_ESCAPE_HANDLER= "com.sun.xml.bind.characterEscapeHandler"; | |
private static final String SUN_JSE_CHARACTER_ESCAPE_HANDLER = "com.sun.xml.internal.bind.characterEscapeHandler"; | |
// XML_DECLARATION is the "opposite" to JAXB_FRAGMENT. If XML_DECLARATION is set to false it means JAXB_FRAGMENT should be set to true. | |
private static final String XML_DECLARATION = "com.sun.xml.bind.xmlDeclaration"; | |
private static final String XML_HEADERS = "com.sun.xml.bind.xmlHeaders"; | |
private static final String OBJECT_IDENTITY_CYCLE_DETECTION = "com.sun.xml.bind.objectIdentitityCycleDetection"; | |
/** | |
* This constructor initializes various settings on the XML marshaller, and | |
* stores the provided JAXBIntrospector instance for usage in marshal() | |
* calls. | |
* | |
* @param newXMLMarshaller | |
* @param newIntrospector | |
*/ | |
public JAXBMarshaller(XMLMarshaller newXMLMarshaller, JAXBIntrospector newIntrospector) { | |
super(); | |
validationEventHandler = JAXBContext.DEFAULT_VALIDATION_EVENT_HANDER; | |
xmlMarshaller = newXMLMarshaller; | |
xmlMarshaller.setErrorHandler(new JAXBErrorHandler(validationEventHandler)); | |
xmlMarshaller.setEncoding("UTF-8"); | |
xmlMarshaller.setFormattedOutput(false); | |
xmlMarshaller.getProperties().put(Constants.JAXB_MARSHALLER, this); | |
} | |
/** | |
* Create an instance of XMLRoot populated from the contents of the provided | |
* JAXBElement. XMLRoot will be used to hold the contents of the JAXBElement | |
* while the marshal operation is performed by TopLink OXM. This will avoid | |
* adding any runtime dependencies to TopLink. | |
* | |
* @param elt | |
* @return | |
*/ | |
private Root createXMLRootFromJAXBElement(JAXBElement elt) { | |
// create an XMLRoot to hand into the marshaller | |
Root xmlroot = new Root(); | |
Object objectValue = elt.getValue(); | |
xmlroot.setObject(objectValue); | |
QName qname = elt.getName(); | |
xmlroot.setLocalName(qname.getLocalPart()); | |
xmlroot.setNamespaceURI(qname.getNamespaceURI()); | |
xmlroot.setDeclaredType(elt.getDeclaredType()); | |
xmlroot.setNil(elt.isNil()); | |
if (elt.getDeclaredType() == CoreClassConstants.ABYTE || elt.getDeclaredType() == CoreClassConstants.APBYTE || | |
elt.getDeclaredType().getCanonicalName().equals("javax.activation.DataHandler") || | |
elt.getDeclaredType().isEnum()) { | |
// need a binary data mapping so need to wrap | |
Class generatedClass = getClassToGeneratedClasses().get(elt.getDeclaredType().getCanonicalName()); | |
if(!elt.getDeclaredType().isEnum()) { | |
xmlroot.setSchemaType(Constants.BASE_64_BINARY_QNAME); | |
} | |
if (generatedClass != null && WrappedValue.class.isAssignableFrom(generatedClass)) { | |
ClassDescriptor desc = xmlMarshaller.getXMLContext().getSession(generatedClass).getDescriptor(generatedClass); | |
Object newObject = desc.getInstantiationPolicy().buildNewInstance(); | |
((WrappedValue) newObject).setValue(objectValue); | |
xmlroot.setObject(newObject); | |
return xmlroot; | |
} | |
} else { | |
xmlroot.setSchemaType((QName) org.eclipse.persistence.internal.oxm.XMLConversionManager.getDefaultJavaTypes().get(elt.getDeclaredType())); | |
} | |
if (elt instanceof WrappedValue) { | |
xmlroot.setObject(elt); | |
return xmlroot; | |
} | |
Map<QName, Class> qNameToGeneratedClasses = jaxbContext.getQNameToGeneratedClasses(); | |
if (qNameToGeneratedClasses != null) { | |
Class theClass = qNameToGeneratedClasses.get(qname); | |
if (theClass != null && WrappedValue.class.isAssignableFrom(theClass)) { | |
ClassDescriptor desc = xmlMarshaller.getXMLContext().getSession(theClass).getDescriptor(theClass); | |
Object newObject = desc.getInstantiationPolicy().buildNewInstance(); | |
((WrappedValue) newObject).setValue(objectValue); | |
xmlroot.setObject(newObject); | |
return xmlroot; | |
} | |
} | |
Class generatedClass = null; | |
if (jaxbContext.getTypeMappingInfoToGeneratedType() != null) { | |
if (jaxbContext.getTypeToTypeMappingInfo() != null) { | |
if (elt.getDeclaredType() != null && elt.getDeclaredType().isArray()) { | |
TypeMappingInfo tmi = jaxbContext.getTypeToTypeMappingInfo().get(elt.getDeclaredType()); | |
generatedClass = jaxbContext.getTypeMappingInfoToGeneratedType().get(tmi); | |
} else if (elt instanceof JAXBTypeElement) { | |
Type objectType = ((JAXBTypeElement) elt).getType(); | |
TypeMappingInfo tmi = jaxbContext.getTypeToTypeMappingInfo().get(objectType); | |
generatedClass = jaxbContext.getTypeMappingInfoToGeneratedType().get(tmi); | |
} | |
} | |
} else { | |
if (elt.getDeclaredType() != null && elt.getDeclaredType().isArray()) { | |
if (jaxbContext.getArrayClassesToGeneratedClasses() != null) { | |
generatedClass = jaxbContext.getArrayClassesToGeneratedClasses().get(elt.getDeclaredType().getCanonicalName()); | |
} | |
} else if (elt instanceof JAXBTypeElement) { | |
Type objectType = ((JAXBTypeElement) elt).getType(); | |
generatedClass = jaxbContext.getCollectionClassesToGeneratedClasses().get(objectType); | |
} | |
} | |
if (generatedClass != null) { | |
ClassDescriptor desc = xmlMarshaller.getXMLContext().getSession(generatedClass).getDescriptor(generatedClass); | |
Object newObject = desc.getInstantiationPolicy().buildNewInstance(); | |
((ManyValue) newObject).setItem(objectValue); | |
xmlroot.setObject(newObject); | |
} | |
return xmlroot; | |
} | |
public XmlAdapter getAdapter(Class javaClass) { | |
HashMap result = (HashMap) xmlMarshaller.getProperty(XML_JAVATYPE_ADAPTERS); | |
if (result == null) { | |
return null; | |
} | |
return (XmlAdapter) result.get(javaClass); | |
} | |
public AttachmentMarshaller getAttachmentMarshaller() { | |
if (xmlMarshaller.getAttachmentMarshaller() == null) { | |
return null; | |
} | |
return ((AttachmentMarshallerAdapter) xmlMarshaller.getAttachmentMarshaller()).getAttachmentMarshaller(); | |
} | |
public ValidationEventHandler getEventHandler() throws JAXBException { | |
return validationEventHandler; | |
} | |
public Marshaller.Listener getListener() { | |
XMLMarshalListener xmlMarshalListener = xmlMarshaller.getMarshalListener(); | |
if(null != xmlMarshalListener) { | |
return ((JAXBMarshalListener) xmlMarshalListener).getListener(); | |
} | |
return null; | |
} | |
public Node getNode(Object object) throws JAXBException { | |
throw new UnsupportedOperationException(); | |
} | |
/** | |
* Get a property from the JAXBMarshaller. Attempting to get any unsupported | |
* property will result in a javax.xml.bind.PropertyException | |
* @see org.eclipse.persistence.jaxb.MarshallerProperties | |
*/ | |
public Object getProperty(String key) throws PropertyException { | |
if (key == null) { | |
throw new IllegalArgumentException(); | |
} else if (JAXB_FORMATTED_OUTPUT.equals(key)) { | |
return xmlMarshaller.isFormattedOutput(); | |
} else if (JAXB_ENCODING.equals(key)) { | |
return xmlMarshaller.getEncoding(); | |
} else if (JAXB_SCHEMA_LOCATION.equals(key)) { | |
return xmlMarshaller.getSchemaLocation(); | |
} else if (JAXB_NO_NAMESPACE_SCHEMA_LOCATION.equals(key)) { | |
return xmlMarshaller.getNoNamespaceSchemaLocation(); | |
} else if (Constants.JAXB_FRAGMENT.equals(key)) { | |
return xmlMarshaller.isFragment(); | |
} else if (MarshallerProperties.MEDIA_TYPE.equals(key)) { | |
return xmlMarshaller.getMediaType(); | |
} else if (MarshallerProperties.NAMESPACE_PREFIX_MAPPER.equals(key)) { | |
return xmlMarshaller.getNamespacePrefixMapper(); | |
} else if (MarshallerProperties.INDENT_STRING.equals(key) || SUN_INDENT_STRING.equals(key) || SUN_JSE_INDENT_STRING.equals(key)) { | |
return xmlMarshaller.getIndentString(); | |
} else if (MarshallerProperties.CHARACTER_ESCAPE_HANDLER.equals(key)) { | |
return xmlMarshaller.getCharacterEscapeHandler(); | |
} else if (XML_DECLARATION.equals(key)) { | |
return !xmlMarshaller.isFragment(); | |
} else if (XML_HEADERS.equals(key)) { | |
return xmlMarshaller.getXmlHeader(); | |
} else if (OBJECT_IDENTITY_CYCLE_DETECTION.equals(key)) { | |
return xmlMarshaller.isEqualUsingIdenity(); | |
} else if (MarshallerProperties.JSON_ATTRIBUTE_PREFIX.equals(key)) { | |
return xmlMarshaller.getAttributePrefix(); | |
} else if (MarshallerProperties.JSON_INCLUDE_ROOT.equals(key)) { | |
return xmlMarshaller.isIncludeRoot(); | |
} else if (MarshallerProperties.JSON_VALUE_WRAPPER.equals(key)) { | |
return xmlMarshaller.getValueWrapper(); | |
} else if (MarshallerProperties.JSON_NAMESPACE_SEPARATOR.equals(key)) { | |
return xmlMarshaller.getNamespaceSeparator(); | |
} else if (MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME.equals(key)) { | |
return xmlMarshaller.isWrapperAsCollectionName(); | |
} else if (SUN_CHARACTER_ESCAPE_HANDLER.equals(key) || SUN_JSE_CHARACTER_ESCAPE_HANDLER.equals(key) ||SUN_CHARACTER_ESCAPE_HANDLER_MARSHALLER.equals(key) || SUN_JSE_CHARACTER_ESCAPE_HANDLER_MARSHALLER.equals(key)) { | |
if (xmlMarshaller.getCharacterEscapeHandler() instanceof CharacterEscapeHandlerWrapper) { | |
CharacterEscapeHandlerWrapper wrapper = (CharacterEscapeHandlerWrapper) xmlMarshaller.getCharacterEscapeHandler(); | |
return wrapper.getHandler(); | |
} | |
return xmlMarshaller.getCharacterEscapeHandler(); | |
} else if (SUN_NAMESPACE_PREFIX_MAPPER.equals(key) || SUN_JSE_NAMESPACE_PREFIX_MAPPER.equals(key)) { | |
NamespacePrefixMapperWrapper wrapper = (NamespacePrefixMapperWrapper) xmlMarshaller.getNamespacePrefixMapper(); | |
if(wrapper == null){ | |
return null; | |
} | |
return wrapper.getPrefixMapper(); | |
} else if (MarshallerProperties.OBJECT_GRAPH.equals(key)) { | |
Object graph = xmlMarshaller.getMarshalAttributeGroup(); | |
if(graph instanceof CoreAttributeGroup) { | |
return new ObjectGraphImpl((CoreAttributeGroup)graph); | |
} | |
return graph; | |
} | |
throw new PropertyException(key); | |
} | |
public Schema getSchema() { | |
return xmlMarshaller.getSchema(); | |
} | |
public void marshal(Object object, ContentHandler contentHandler) throws JAXBException { | |
if (object == null || contentHandler == null) { | |
throw new IllegalArgumentException(); | |
} | |
Listener listener = getListener(); | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.beforeMarshal(object); | |
} | |
} | |
Object oxmObject = modifyObjectIfNeeded(object); | |
try { | |
xmlMarshaller.marshal(oxmObject, contentHandler); | |
} catch (Exception e) { | |
throw new MarshalException(e); | |
} | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.afterMarshal(object); | |
} | |
} | |
} | |
private Object wrapEnumeration(Object object, Class enumerationClass) { | |
Class generatedClass = this.getClassToGeneratedClasses().get(enumerationClass.getName()); | |
if (generatedClass != null && WrappedValue.class.isAssignableFrom(generatedClass)) { | |
ClassDescriptor desc = xmlMarshaller.getXMLContext().getSession(generatedClass).getDescriptor(generatedClass); | |
Object newObject = desc.getInstantiationPolicy().buildNewInstance(); | |
((WrappedValue) newObject).setValue(object); | |
object = newObject; | |
} | |
return object; | |
} | |
public void marshal(Object object, XMLEventWriter eventWriter) throws JAXBException { | |
if (object == null || eventWriter == null) { | |
throw new IllegalArgumentException(); | |
} | |
Listener listener = getListener(); | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.beforeMarshal(object); | |
} | |
} | |
Object oxmObject = modifyObjectIfNeeded(object); | |
try { | |
XMLEventWriterRecord record = new XMLEventWriterRecord(eventWriter); | |
record.setMarshaller(this.xmlMarshaller); | |
this.xmlMarshaller.marshal(oxmObject, record); | |
} catch (Exception ex) { | |
throw new MarshalException(ex); | |
} | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.afterMarshal(object); | |
} | |
} | |
} | |
public void marshal(Object object, XMLEventWriter eventWriter, TypeMappingInfo type) throws JAXBException { | |
if (jaxbContext.getTypeMappingInfoToGeneratedType() == null) { | |
marshal(object, eventWriter); | |
} else { | |
JAXBElement element = null; | |
Object value = object; | |
if (object instanceof JAXBElement) { | |
// use the JAXBElement's properties to populate an XMLRoot | |
element = (JAXBElement) object; | |
value = element.getValue(); | |
} | |
RootLevelXmlAdapter adapter = jaxbContext.getTypeMappingInfoToJavaTypeAdapters().get(type); | |
if (adapter != null) { | |
try { | |
value = adapter.getXmlAdapter().marshal(value); | |
} catch (Exception ex) { | |
throw new JAXBException(XMLMarshalException.marshalException(ex)); | |
} | |
} | |
value = wrapObject(value, element, type); | |
marshal(value, eventWriter); | |
} | |
} | |
public void marshal(Object object, Node node) throws JAXBException { | |
if (object == null || node == null) { | |
throw new IllegalArgumentException(); | |
} | |
Listener listener = getListener(); | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.beforeMarshal(object); | |
} | |
} | |
Object oxmObject = modifyObjectIfNeeded(object); | |
try { | |
xmlMarshaller.marshal(oxmObject, node); | |
} catch (Exception e) { | |
throw new MarshalException(e); | |
} | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.afterMarshal(object); | |
} | |
} | |
} | |
public void marshal(Object object, OutputStream outputStream) throws JAXBException { | |
if (object == null || outputStream == null) { | |
throw new IllegalArgumentException(); | |
} | |
Listener listener = getListener(); | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.beforeMarshal(object); | |
} | |
} | |
Object oxmObject = modifyObjectIfNeeded(object); | |
try { | |
xmlMarshaller.marshal(oxmObject, outputStream); | |
} catch (Exception e) { | |
throw new MarshalException(e); | |
} | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.afterMarshal(object); | |
} | |
} | |
} | |
public void marshal(Object object, File file) throws JAXBException { | |
try { | |
FileOutputStream outputStream = new FileOutputStream(file); | |
try { | |
marshal(object, outputStream); | |
} finally { | |
outputStream.close(); | |
} | |
} catch (Exception ex) { | |
throw new MarshalException(ex); | |
} | |
} | |
public void marshal(Object object, Result result) throws JAXBException { | |
if (object == null || result == null) { | |
throw new IllegalArgumentException(); | |
} | |
object = modifyObjectIfNeeded(object); | |
try { | |
xmlMarshaller.marshal(object, result); | |
} catch (Exception e) { | |
throw new MarshalException(e); | |
} | |
} | |
public void marshal(Object object, Result result, TypeMappingInfo type) throws JAXBException { | |
if (jaxbContext.getTypeMappingInfoToGeneratedType() == null) { | |
marshal(object, result); | |
} else { | |
JAXBElement element = null; | |
Object value = object; | |
if (object instanceof JAXBElement) { | |
// use the JAXBElement's properties to populate an XMLRoot | |
element = (JAXBElement) object; | |
value = element.getValue(); | |
} | |
if(jaxbContext.getTypeMappingInfoToJavaTypeAdapters().size() > 0){ | |
RootLevelXmlAdapter adapter = jaxbContext.getTypeMappingInfoToJavaTypeAdapters().get(type); | |
if (adapter != null) { | |
try { | |
value = adapter.getXmlAdapter().marshal(value); | |
} catch (Exception ex) { | |
throw new JAXBException(XMLMarshalException.marshalException(ex)); | |
} | |
} | |
} | |
value = wrapObject(value, element, type); | |
marshal(value, result); | |
} | |
} | |
public void marshal(Object object, XMLStreamWriter streamWriter) throws JAXBException { | |
if (object == null || streamWriter == null) { | |
throw new IllegalArgumentException(); | |
} | |
Listener listener = getListener(); | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.beforeMarshal(object); | |
} | |
} | |
Object oxmObject = modifyObjectIfNeeded(object); | |
try { | |
XMLStreamWriterRecord record = new XMLStreamWriterRecord(streamWriter); | |
record.setMarshaller(this.xmlMarshaller); | |
this.xmlMarshaller.marshal(oxmObject, record); | |
} catch (Exception ex) { | |
throw new MarshalException(ex); | |
} | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.afterMarshal(object); | |
} | |
} | |
} | |
private Object modifyObjectIfNeeded(Object obj){ | |
if(obj instanceof Collection){ | |
Collection objectList = (Collection)obj; | |
List newList = new ArrayList(objectList.size()); | |
for(Object o:objectList){ | |
newList.add(modifySingleObjectIfNeeded(o)); | |
} | |
return newList; | |
}else if(obj.getClass().isArray()){ | |
int arraySize = Array.getLength(obj); | |
List newList = new ArrayList(arraySize); | |
for(int x=0; x<arraySize; x++) { | |
newList.add(modifySingleObjectIfNeeded(Array.get(obj, x))); | |
} | |
return newList; | |
}else{ | |
return modifySingleObjectIfNeeded(obj); | |
} | |
} | |
private Object modifySingleObjectIfNeeded(Object obj){ | |
// let the JAXBIntrospector determine if the object is a JAXBElement | |
if (obj instanceof JAXBElement) { | |
// use the JAXBElement's properties to populate an XMLRoot | |
return createXMLRootFromJAXBElement((JAXBElement) obj); | |
} else if(obj != null && obj.getClass().isEnum()) { | |
return wrapEnumeration(obj, obj.getClass()); | |
} else if (obj instanceof JSONWithPadding){ | |
Object nestedObject = ((JSONWithPadding)obj).getObject(); | |
if(nestedObject != null){ | |
Object newNestedObject = modifyObjectIfNeeded(nestedObject); | |
if(nestedObject != newNestedObject){ | |
return new JSONWithPadding(newNestedObject,((JSONWithPadding)obj).getCallbackName()); | |
} | |
} | |
} | |
return obj; | |
} | |
public void marshal(Object object, XMLStreamWriter streamWriter, TypeMappingInfo type) throws JAXBException { | |
if (jaxbContext.getTypeMappingInfoToGeneratedType() == null) { | |
marshal(object, streamWriter); | |
} else { | |
JAXBElement element = null; | |
Object value = object; | |
if (object instanceof JAXBElement) { | |
// use the JAXBElement's properties to populate an XMLRoot | |
element = (JAXBElement) object; | |
value = element.getValue(); | |
} | |
if(jaxbContext.getTypeMappingInfoToJavaTypeAdapters().size() > 0){ | |
RootLevelXmlAdapter adapter = jaxbContext.getTypeMappingInfoToJavaTypeAdapters().get(type); | |
if (adapter != null) { | |
try { | |
value = adapter.getXmlAdapter().marshal(value); | |
} catch (Exception ex) { | |
throw new JAXBException(XMLMarshalException.marshalException(ex)); | |
} | |
} | |
} | |
value = wrapObject(value, element, type); | |
marshal(value, streamWriter); | |
} | |
} | |
private Object wrapObject(Object object, JAXBElement wrapperElement, TypeMappingInfo typeMappingInfo) { | |
if(jaxbContext.getTypeMappingInfoToGeneratedType().size() > 0){ | |
Class generatedClass = jaxbContext.getTypeMappingInfoToGeneratedType().get(typeMappingInfo); | |
if(generatedClass != null && object == null && wrapperElement != null) { | |
return wrapObjectInXMLRoot(wrapperElement, object, typeMappingInfo); | |
} | |
if (generatedClass != null && WrappedValue.class.isAssignableFrom(generatedClass)) { | |
ClassDescriptor desc = xmlMarshaller.getXMLContext().getSession(generatedClass).getDescriptor(generatedClass); | |
Object newObject = desc.getInstantiationPolicy().buildNewInstance(); | |
((WrappedValue) newObject).setValue(object); | |
object = newObject; | |
} else if (generatedClass != null) { | |
// should be a many value | |
ClassDescriptor desc = xmlMarshaller.getXMLContext().getSession(generatedClass).getDescriptor(generatedClass); | |
Object newObject = desc.getInstantiationPolicy().buildNewInstance(); | |
((ManyValue) newObject).setItem(object); | |
object = newObject; | |
} | |
} | |
if (null == wrapperElement) { | |
Root xmlRoot = new Root(); | |
QName xmlTagName = typeMappingInfo.getXmlTagName(); | |
if (null == xmlTagName) { | |
return object; | |
} | |
xmlRoot.setNamespaceURI(typeMappingInfo.getXmlTagName().getNamespaceURI()); | |
xmlRoot.setLocalName(typeMappingInfo.getXmlTagName().getLocalPart()); | |
xmlRoot.setObject(object); | |
return xmlRoot; | |
} | |
return wrapObjectInXMLRoot(wrapperElement, object, typeMappingInfo); | |
} | |
private Root wrapObjectInXMLRoot(JAXBElement wrapperElement, Object value, TypeMappingInfo typeMappingInfo) { | |
Root xmlroot = new Root(); | |
Object objectValue = value; | |
xmlroot.setObject(objectValue); | |
QName qname = wrapperElement.getName(); | |
xmlroot.setLocalName(qname.getLocalPart()); | |
xmlroot.setNamespaceURI(qname.getNamespaceURI()); | |
xmlroot.setDeclaredType(wrapperElement.getDeclaredType()); | |
if(typeMappingInfo != null){ | |
xmlroot.setSchemaType(typeMappingInfo.getSchemaType()); | |
} else if(value != null) { | |
if (value.getClass() == CoreClassConstants.ABYTE || value.getClass() == CoreClassConstants.APBYTE || | |
value.getClass().getCanonicalName().equals("javax.activation.DataHandler")) { | |
xmlroot.setSchemaType(Constants.BASE_64_BINARY_QNAME); | |
} | |
} | |
return xmlroot; | |
} | |
public void marshal(Object object, Writer writer) throws JAXBException { | |
if (object == null || writer == null) { | |
throw new IllegalArgumentException(); | |
} | |
Listener listener = getListener(); | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.beforeMarshal(object); | |
} | |
} | |
Object oxmObject = modifyObjectIfNeeded(object); | |
try { | |
xmlMarshaller.marshal(oxmObject, writer); | |
} catch (Exception e) { | |
throw new MarshalException(e); | |
} | |
if(listener != null) { | |
if(object instanceof JAXBElement) { | |
listener.afterMarshal(object); | |
} | |
} | |
} | |
public void marshal(Object object, MarshalRecord record) throws JAXBException { | |
if (object == null || record == null) { | |
throw new IllegalArgumentException(); | |
} | |
object = modifyObjectIfNeeded(object); | |
try { | |
record.setMarshaller(xmlMarshaller); | |
xmlMarshaller.marshal(object, record); | |
} catch (Exception e) { | |
throw new MarshalException(e); | |
} | |
} | |
public void marshal(Object object, MarshalRecord record, TypeMappingInfo type) throws JAXBException { | |
if (jaxbContext.getTypeMappingInfoToGeneratedType() == null) { | |
marshal(object, record); | |
} else { | |
JAXBElement element = null; | |
Object value = object; | |
if (object instanceof JAXBElement) { | |
// use the JAXBElement's properties to populate an XMLRoot | |
element = (JAXBElement) object; | |
value = element.getValue(); | |
} | |
RootLevelXmlAdapter adapter = jaxbContext.getTypeMappingInfoToJavaTypeAdapters().get(type); | |
if (adapter != null) { | |
try { | |
value = adapter.getXmlAdapter().marshal(value); | |
} catch (Exception ex) { | |
throw new JAXBException(XMLMarshalException.marshalException(ex)); | |
} | |
} | |
value = wrapObject(value, element, type); | |
marshal(value, record); | |
} | |
} | |
public void setAdapter(Class javaClass, XmlAdapter adapter) { | |
HashMap result = (HashMap) xmlMarshaller.getProperty(XML_JAVATYPE_ADAPTERS); | |
if (result == null) { | |
result = new HashMap(); | |
xmlMarshaller.getProperties().put(XML_JAVATYPE_ADAPTERS, result); | |
} | |
result.put(javaClass, adapter); | |
} | |
public void setAdapter(XmlAdapter adapter) { | |
setAdapter(adapter.getClass(), adapter); | |
} | |
public void setAttachmentMarshaller(AttachmentMarshaller attachmentMarshaller) { | |
if (attachmentMarshaller == null) { | |
xmlMarshaller.setAttachmentMarshaller(null); | |
} else { | |
xmlMarshaller.setAttachmentMarshaller(new AttachmentMarshallerAdapter(attachmentMarshaller)); | |
} | |
} | |
public void setEventHandler(ValidationEventHandler newValidationEventHandler) throws JAXBException { | |
if (null == newValidationEventHandler) { | |
validationEventHandler = JAXBContext.DEFAULT_VALIDATION_EVENT_HANDER; | |
} else { | |
validationEventHandler = newValidationEventHandler; | |
} | |
xmlMarshaller.setErrorHandler(new JAXBErrorHandler(validationEventHandler)); | |
} | |
public void setListener(Marshaller.Listener listener) { | |
if(xmlMarshaller.getMarshalListener() == null) { | |
xmlMarshaller.setMarshalListener(new JAXBMarshalListener(jaxbContext, this)); | |
} | |
((JAXBMarshalListener) xmlMarshaller.getMarshalListener()).setListener(listener); | |
} | |
public void setMarshalCallbacks(java.util.HashMap callbacks) { | |
if(callbacks == null || callbacks.isEmpty()) { | |
return; | |
} | |
if(xmlMarshaller.getMarshalListener() == null) { | |
xmlMarshaller.setMarshalListener(new JAXBMarshalListener(jaxbContext, this)); | |
} | |
((JAXBMarshalListener) xmlMarshaller.getMarshalListener()).setClassBasedMarshalEvents(callbacks); | |
} | |
/** | |
* Set a property on the JAXBMarshaller. Attempting to set any unsupported | |
* property will result in a javax.xml.bind.PropertyException | |
* @see org.eclipse.persistence.jaxb.MarshallerProperties | |
*/ | |
public void setProperty(String key, Object value) throws PropertyException { | |
try { | |
if (key == null) { | |
throw new IllegalArgumentException(); | |
} else if (Constants.JAXB_FRAGMENT.equals(key)) { | |
if(value == null){ | |
throw new PropertyException(key, Constants.EMPTY_STRING); | |
} | |
Boolean fragment = (Boolean) value; | |
xmlMarshaller.setFragment(fragment.booleanValue()); | |
} else if (JAXB_FORMATTED_OUTPUT.equals(key)) { | |
if(value == null){ | |
throw new PropertyException(key, Constants.EMPTY_STRING); | |
} | |
Boolean formattedOutput = (Boolean) value; | |
xmlMarshaller.setFormattedOutput(formattedOutput.booleanValue()); | |
} else if (JAXB_ENCODING.equals(key)) { | |
xmlMarshaller.setEncoding((String) value); | |
} else if (JAXB_SCHEMA_LOCATION.equals(key)) { | |
xmlMarshaller.setSchemaLocation((String) value); | |
} else if (JAXB_NO_NAMESPACE_SCHEMA_LOCATION.equals(key)) { | |
xmlMarshaller.setNoNamespaceSchemaLocation((String) value); | |
} else if(MarshallerProperties.NAMESPACE_PREFIX_MAPPER.equals(key)) { | |
if(value == null){ | |
xmlMarshaller.setNamespacePrefixMapper(null); | |
}else if(value instanceof Map){ | |
NamespacePrefixMapper namespacePrefixMapper = new MapNamespacePrefixMapper((Map)value); | |
xmlMarshaller.setNamespacePrefixMapper(namespacePrefixMapper); | |
}else{ | |
xmlMarshaller.setNamespacePrefixMapper((NamespacePrefixMapper)value); | |
} | |
} else if(SUN_NAMESPACE_PREFIX_MAPPER.equals(key) || SUN_JSE_NAMESPACE_PREFIX_MAPPER.equals(key)) { | |
if(value == null){ | |
xmlMarshaller.setNamespacePrefixMapper(null); | |
}else{ | |
xmlMarshaller.setNamespacePrefixMapper(new NamespacePrefixMapperWrapper(value)); | |
} | |
} else if (MarshallerProperties.INDENT_STRING.equals(key) || SUN_INDENT_STRING.equals(key) || SUN_JSE_INDENT_STRING.equals(key)) { | |
xmlMarshaller.setIndentString((String) value); | |
} else if (MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS.equals(key)){ | |
xmlMarshaller.setMarshalEmptyCollections((Boolean) value); | |
} else if (MarshallerProperties.JSON_REDUCE_ANY_ARRAYS.equals(key)){ | |
xmlMarshaller.setReduceAnyArrays((Boolean) value); | |
} else if (MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME.equals(key)) { | |
xmlMarshaller.setWrapperAsCollectionName((Boolean) value); | |
} else if (MarshallerProperties.CHARACTER_ESCAPE_HANDLER.equals(key)) { | |
xmlMarshaller.setCharacterEscapeHandler((CharacterEscapeHandler) value); | |
} else if (SUN_CHARACTER_ESCAPE_HANDLER.equals(key) || SUN_JSE_CHARACTER_ESCAPE_HANDLER.equals(key) ||SUN_CHARACTER_ESCAPE_HANDLER_MARSHALLER.equals(key) || SUN_JSE_CHARACTER_ESCAPE_HANDLER_MARSHALLER.equals(key)) { | |
if (value == null) { | |
xmlMarshaller.setCharacterEscapeHandler(null); | |
} else { | |
xmlMarshaller.setCharacterEscapeHandler(new CharacterEscapeHandlerWrapper(value)); | |
} | |
} else if (XML_DECLARATION.equals(key)) { | |
if(value == null){ | |
throw new PropertyException(key, Constants.EMPTY_STRING); | |
} | |
Boolean fragment = !(Boolean) value; | |
xmlMarshaller.setFragment(fragment.booleanValue()); | |
} else if (XML_HEADERS.equals(key)) { | |
xmlMarshaller.setXmlHeader((String) value); | |
} else if (OBJECT_IDENTITY_CYCLE_DETECTION.equals(key)) { | |
if(value == null){ | |
throw new PropertyException(key, Constants.EMPTY_STRING); | |
} | |
xmlMarshaller.setEqualUsingIdenity(((Boolean) value).booleanValue()); | |
} else if (MarshallerProperties.MEDIA_TYPE.equals(key)) { | |
MediaType mType = null; | |
if(value instanceof MediaType) { | |
mType = (MediaType) value; | |
} else if(value instanceof String) { | |
mType = MediaType.getMediaType((String)value); | |
} | |
if(mType == null){ | |
throw new PropertyException(key, Constants.EMPTY_STRING); | |
} | |
xmlMarshaller.setMediaType(mType); | |
} else if (MarshallerProperties.JSON_ATTRIBUTE_PREFIX.equals(key)) { | |
xmlMarshaller.setAttributePrefix((String)value); | |
} else if (MarshallerProperties.JSON_INCLUDE_ROOT.equals(key)) { | |
if(value == null){ | |
throw new PropertyException(key, Constants.EMPTY_STRING); | |
} | |
xmlMarshaller.setIncludeRoot((Boolean)value); | |
} else if(MarshallerProperties.JSON_VALUE_WRAPPER.equals(key)){ | |
if(value == null || (((String)value).length() == 0)){ | |
throw new PropertyException(key, Constants.EMPTY_STRING); | |
} | |
xmlMarshaller.setValueWrapper((String)value); | |
} else if(MarshallerProperties.JSON_NAMESPACE_SEPARATOR.equals(key)){ | |
if(value == null){ | |
throw new PropertyException(key, Constants.EMPTY_STRING); | |
} | |
xmlMarshaller.setNamespaceSeparator((Character)value); | |
} else if(MarshallerProperties.OBJECT_GRAPH.equals(key)) { | |
if(value == null) { | |
xmlMarshaller.setMarshalAttributeGroup(null); | |
} else if(value instanceof ObjectGraphImpl) { | |
xmlMarshaller.setMarshalAttributeGroup(((ObjectGraphImpl)value).getAttributeGroup()); | |
} else if(value.getClass() == ClassConstants.STRING){ | |
xmlMarshaller.setMarshalAttributeGroup(value); | |
} else { | |
throw org.eclipse.persistence.exceptions.JAXBException.invalidValueForObjectGraph(value); | |
} | |
} else { | |
throw new PropertyException(key, value); | |
} | |
} catch (ClassCastException exception) { | |
throw new PropertyException(key, exception); | |
} | |
} | |
public void setSchema(Schema schema) { | |
this.xmlMarshaller.setSchema(schema); | |
} | |
private HashMap<String, Class> getClassToGeneratedClasses() { | |
return jaxbContext.getClassToGeneratedClasses(); | |
} | |
public JAXBContext getJaxbContext() { | |
return jaxbContext; | |
} | |
public void setJaxbContext(JAXBContext jaxbContext) { | |
this.jaxbContext = jaxbContext; | |
} | |
public XMLMarshaller getXMLMarshaller() { | |
return this.xmlMarshaller; | |
} | |
} |