diff -r 000000000000 -r 373ffda63c9a src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/MarshallerImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/MarshallerImpl.java Wed Apr 27 01:27:09 2016 +0800 @@ -0,0 +1,619 @@ +/* + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.bind.v2.runtime; + +import java.io.BufferedWriter; +import java.io.Closeable; +import java.io.FileOutputStream; +import java.io.Flushable; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import java.net.URI; +import javax.xml.bind.JAXBException; +import javax.xml.bind.MarshalException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.PropertyException; +import javax.xml.bind.ValidationEvent; +import javax.xml.bind.ValidationEventHandler; +import javax.xml.bind.annotation.adapters.XmlAdapter; +import javax.xml.bind.attachment.AttachmentMarshaller; +import javax.xml.bind.helpers.AbstractMarshallerImpl; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamResult; +import javax.xml.validation.Schema; +import javax.xml.validation.ValidatorHandler; +import javax.xml.namespace.NamespaceContext; + +import com.sun.xml.internal.bind.api.JAXBRIContext; +import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler; +import com.sun.xml.internal.bind.marshaller.DataWriter; +import com.sun.xml.internal.bind.marshaller.DumbEscapeHandler; +import com.sun.xml.internal.bind.marshaller.MinimumEscapeHandler; +import com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper; +import com.sun.xml.internal.bind.marshaller.NioEscapeHandler; +import com.sun.xml.internal.bind.marshaller.SAX2DOMEx; +import com.sun.xml.internal.bind.marshaller.XMLWriter; +import com.sun.xml.internal.bind.v2.runtime.output.C14nXmlOutput; +import com.sun.xml.internal.bind.v2.runtime.output.Encoded; +import com.sun.xml.internal.bind.v2.runtime.output.ForkXmlOutput; +import com.sun.xml.internal.bind.v2.runtime.output.IndentingUTF8XmlOutput; +import com.sun.xml.internal.bind.v2.runtime.output.NamespaceContextImpl; +import com.sun.xml.internal.bind.v2.runtime.output.SAXOutput; +import com.sun.xml.internal.bind.v2.runtime.output.UTF8XmlOutput; +import com.sun.xml.internal.bind.v2.runtime.output.XMLEventWriterOutput; +import com.sun.xml.internal.bind.v2.runtime.output.XMLStreamWriterOutput; +import com.sun.xml.internal.bind.v2.runtime.output.XmlOutput; +import com.sun.xml.internal.bind.v2.util.FatalAdapter; + +import java.net.URISyntaxException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.XMLFilterImpl; + +/** + * Implementation of {@link Marshaller} interface for the JAXB RI. + * + *

+ * Eventually all the {@link #marshal} methods call into + * the {@link #write} method. + * + * @author Kohsuke Kawaguchi + * @author Vivek Pandey + */ +public /*to make unit tests happy*/ final class MarshallerImpl extends AbstractMarshallerImpl implements ValidationEventHandler +{ + /** Indentation string. Default is four whitespaces. */ + private String indent = " "; + + /** Used to assign prefixes to namespace URIs. */ + private NamespacePrefixMapper prefixMapper = null; + + /** Object that handles character escaping. */ + private CharacterEscapeHandler escapeHandler = null; + + /** XML BLOB written after the XML declaration. */ + private String header=null; + + /** reference to the context that created this object */ + final JAXBContextImpl context; + + protected final XMLSerializer serializer; + + /** + * Non-null if we do the marshal-time validation. + */ + private Schema schema; + + /** Marshaller.Listener */ + private Listener externalListener = null; + + /** Configured for c14n? */ + private boolean c14nSupport; + + // while createing XmlOutput those values may be set. + // if these are non-null they need to be cleaned up + private Flushable toBeFlushed; + private Closeable toBeClosed; + + /** + * @param assoc + * non-null if the marshaller is working inside {@link BinderImpl}. + */ + public MarshallerImpl( JAXBContextImpl c, AssociationMap assoc ) { + context = c; + serializer = new XMLSerializer(this); + c14nSupport = context.c14nSupport; + + try { + setEventHandler(this); + } catch (JAXBException e) { + throw new AssertionError(e); // impossible + } + } + + public JAXBContextImpl getContext() { + return context; + } + + /** + * Marshals to {@link OutputStream} with the given in-scope namespaces + * taken into account. + * + * @since 2.1.5 + */ + public void marshal(Object obj, OutputStream out, NamespaceContext inscopeNamespace) throws JAXBException { + write(obj, createWriter(out), new StAXPostInitAction(inscopeNamespace,serializer)); + } + + @Override + public void marshal(Object obj, XMLStreamWriter writer) throws JAXBException { + write(obj, XMLStreamWriterOutput.create(writer,context), new StAXPostInitAction(writer,serializer)); + } + + @Override + public void marshal(Object obj, XMLEventWriter writer) throws JAXBException { + write(obj, new XMLEventWriterOutput(writer), new StAXPostInitAction(writer,serializer)); + } + + public void marshal(Object obj, XmlOutput output) throws JAXBException { + write(obj, output, null ); + } + + /** + * Creates {@link XmlOutput} from the given {@link Result} object. + */ + final XmlOutput createXmlOutput(Result result) throws JAXBException { + if (result instanceof SAXResult) + return new SAXOutput(((SAXResult) result).getHandler()); + + if (result instanceof DOMResult) { + final Node node = ((DOMResult) result).getNode(); + + if (node == null) { + Document doc = JAXBContextImpl.createDom(getContext().disableSecurityProcessing); + ((DOMResult) result).setNode(doc); + return new SAXOutput(new SAX2DOMEx(doc)); + } else { + return new SAXOutput(new SAX2DOMEx(node)); + } + } + if (result instanceof StreamResult) { + StreamResult sr = (StreamResult) result; + + if (sr.getWriter() != null) + return createWriter(sr.getWriter()); + else if (sr.getOutputStream() != null) + return createWriter(sr.getOutputStream()); + else if (sr.getSystemId() != null) { + String fileURL = sr.getSystemId(); + + try { + fileURL = new URI(fileURL).getPath(); + } catch (URISyntaxException use) { + // otherwise assume that it's a file name + } + + try { + FileOutputStream fos = new FileOutputStream(fileURL); + assert toBeClosed==null; + toBeClosed = fos; + return createWriter(fos); + } catch (IOException e) { + throw new MarshalException(e); + } + } + } + + // unsupported parameter type + throw new MarshalException(Messages.UNSUPPORTED_RESULT.format()); + } + + /** + * Creates an appropriate post-init action object. + */ + final Runnable createPostInitAction(Result result) { + if (result instanceof DOMResult) { + Node node = ((DOMResult) result).getNode(); + return new DomPostInitAction(node,serializer); + } + return null; + } + + public void marshal(Object target,Result result) throws JAXBException { + write(target, createXmlOutput(result), createPostInitAction(result)); + } + + + /** + * Used by {@link BridgeImpl} to write an arbitrary object as a fragment. + */ + protected final void write(Name rootTagName, JaxBeanInfo bi, T obj, XmlOutput out,Runnable postInitAction) throws JAXBException { + try { + try { + prewrite(out, true, postInitAction); + serializer.startElement(rootTagName,null); + if(bi.jaxbType==Void.class || bi.jaxbType==void.class) { + // special case for void + serializer.endNamespaceDecls(null); + serializer.endAttributes(); + } else { // normal cases + if(obj==null) + serializer.writeXsiNilTrue(); + else + serializer.childAsXsiType(obj,"root",bi, false); + } + serializer.endElement(); + postwrite(); + } catch( SAXException e ) { + throw new MarshalException(e); + } catch (IOException e) { + throw new MarshalException(e); + } catch (XMLStreamException e) { + throw new MarshalException(e); + } finally { + serializer.close(); + } + } finally { + cleanUp(); + } + } + + /** + * All the marshal method invocation eventually comes down to this call. + */ + private void write(Object obj, XmlOutput out, Runnable postInitAction) throws JAXBException { + try { + if( obj == null ) + throw new IllegalArgumentException(Messages.NOT_MARSHALLABLE.format()); + + if( schema!=null ) { + // send the output to the validator as well + ValidatorHandler validator = schema.newValidatorHandler(); + validator.setErrorHandler(new FatalAdapter(serializer)); + // work around a bug in JAXP validator in Tiger + XMLFilterImpl f = new XMLFilterImpl() { + @Override + public void startPrefixMapping(String prefix, String uri) throws SAXException { + super.startPrefixMapping(prefix.intern(), uri.intern()); + } + }; + f.setContentHandler(validator); + out = new ForkXmlOutput( new SAXOutput(f) { + @Override + public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws SAXException, IOException, XMLStreamException { + super.startDocument(serializer, false, nsUriIndex2prefixIndex, nsContext); + } + @Override + public void endDocument(boolean fragment) throws SAXException, IOException, XMLStreamException { + super.endDocument(false); + } + }, out ); + } + + try { + prewrite(out,isFragment(),postInitAction); + serializer.childAsRoot(obj); + postwrite(); + } catch( SAXException e ) { + throw new MarshalException(e); + } catch (IOException e) { + throw new MarshalException(e); + } catch (XMLStreamException e) { + throw new MarshalException(e); + } finally { + serializer.close(); + } + } finally { + cleanUp(); + } + } + + private void cleanUp() { + if(toBeFlushed!=null) + try { + toBeFlushed.flush(); + } catch (IOException e) { + // ignore + } + if(toBeClosed!=null) + try { + toBeClosed.close(); + } catch (IOException e) { + // ignore + } + toBeFlushed = null; + toBeClosed = null; + } + + // common parts between two write methods. + + private void prewrite(XmlOutput out, boolean fragment, Runnable postInitAction) throws IOException, SAXException, XMLStreamException { + serializer.startDocument(out,fragment,getSchemaLocation(),getNoNSSchemaLocation()); + if(postInitAction!=null) postInitAction.run(); + if(prefixMapper!=null) { + // be defensive as we work with the user's code + String[] decls = prefixMapper.getContextualNamespaceDecls(); + if(decls!=null) { // defensive check + for( int i=0; i void setAdapter(Class type, A adapter) { + if(type==null) + throw new IllegalArgumentException(); + serializer.putAdapter(type,adapter); + } + + @Override + public A getAdapter(Class type) { + if(type==null) + throw new IllegalArgumentException(); + if(serializer.containsAdapter(type)) + // so as not to create a new instance when this method is called + return serializer.getAdapter(type); + else + return null; + } + + @Override + public void setAttachmentMarshaller(AttachmentMarshaller am) { + serializer.attachmentMarshaller = am; + } + + @Override + public AttachmentMarshaller getAttachmentMarshaller() { + return serializer.attachmentMarshaller; + } + + @Override + public Schema getSchema() { + return schema; + } + + @Override + public void setSchema(Schema s) { + this.schema = s; + } + + /** + * Default error handling behavior fot {@link Marshaller}. + */ + public boolean handleEvent(ValidationEvent event) { + // draconian by default + return false; + } + + @Override + public Listener getListener() { + return externalListener; + } + + @Override + public void setListener(Listener listener) { + externalListener = listener; + } + + // features supported + protected static final String INDENT_STRING = "com.sun.xml.internal.bind.indentString"; + protected static final String PREFIX_MAPPER = "com.sun.xml.internal.bind.namespacePrefixMapper"; + protected static final String ENCODING_HANDLER = "com.sun.xml.internal.bind.characterEscapeHandler"; + protected static final String ENCODING_HANDLER2 = "com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler"; + protected static final String XMLDECLARATION = "com.sun.xml.internal.bind.xmlDeclaration"; + protected static final String XML_HEADERS = "com.sun.xml.internal.bind.xmlHeaders"; + protected static final String C14N = JAXBRIContext.CANONICALIZATION_SUPPORT; + protected static final String OBJECT_IDENTITY_CYCLE_DETECTION = "com.sun.xml.internal.bind.objectIdentitityCycleDetection"; +}