/*
 * Copyright (c) 1997, 2013, 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.unmarshaller;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.PropertyException;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.UnmarshallerHandler;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.attachment.AttachmentUnmarshaller;
import javax.xml.bind.helpers.AbstractUnmarshallerImpl;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;

import com.sun.xml.internal.bind.IDResolver;
import com.sun.xml.internal.bind.api.ClassResolver;
import com.sun.xml.internal.bind.unmarshaller.DOMScanner;
import com.sun.xml.internal.bind.unmarshaller.InfosetScanner;
import com.sun.xml.internal.bind.unmarshaller.Messages;
import com.sun.xml.internal.bind.v2.ClassFactory;
import com.sun.xml.internal.bind.v2.runtime.AssociationMap;
import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo;
import com.sun.xml.internal.bind.v2.util.XmlFactory;

import java.io.Closeable;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

Default Unmarshaller implementation.

This class can be extended by the generated code to provide type-safe unmarshall methods.

Author: Kohsuke KAWAGUCHI
/** * Default Unmarshaller implementation. * * <p> * This class can be extended by the generated code to provide * type-safe unmarshall methods. * * @author * <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> */
public final class UnmarshallerImpl extends AbstractUnmarshallerImpl implements ValidationEventHandler, Closeable {
Owning JAXBContext
/** Owning {@link JAXBContext} */
protected final JAXBContextImpl context;
schema which will be used to validate during calls to unmarshal
/** * schema which will be used to validate during calls to unmarshal */
private Schema schema; public final UnmarshallingContext coordinator;
Unmarshaller.Listener
/** Unmarshaller.Listener */
private Listener externalListener;
The attachment unmarshaller used to support MTOM and swaRef.
/** * The attachment unmarshaller used to support MTOM and swaRef. */
private AttachmentUnmarshaller attachmentUnmarshaller; private IDResolver idResolver = new DefaultIDResolver(); public UnmarshallerImpl( JAXBContextImpl context, AssociationMap assoc ) { this.context = context; this.coordinator = new UnmarshallingContext( this, assoc ); try { setEventHandler(this); } catch (JAXBException e) { throw new AssertionError(e); // impossible } } public UnmarshallerHandler getUnmarshallerHandler() { return getUnmarshallerHandler(true,null); } private XMLReader reader = null;
Obtains a configured XMLReader. This method is used when the client-specified SAXSource object doesn't have XMLReader. Unmarshaller is not re-entrant, so we will only use one instance of XMLReader. Overriden in order to fix potential security issue.
/** * Obtains a configured XMLReader. * * This method is used when the client-specified * {@link SAXSource} object doesn't have XMLReader. * * {@link Unmarshaller} is not re-entrant, so we will * only use one instance of XMLReader. * * Overriden in order to fix potential security issue. */
@Override protected XMLReader getXMLReader() throws JAXBException { if (reader == null) { try { SAXParserFactory parserFactory = XmlFactory.createParserFactory(context.disableSecurityProcessing); // there is no point in asking a validation because // there is no guarantee that the document will come with // a proper schemaLocation. parserFactory.setValidating(false); reader = parserFactory.newSAXParser().getXMLReader(); } catch (ParserConfigurationException e) { throw new JAXBException(e); } catch (SAXException e) { throw new JAXBException(e); } } return reader; } private SAXConnector getUnmarshallerHandler( boolean intern, JaxBeanInfo expectedType ) { XmlVisitor h = createUnmarshallerHandler(null, false, expectedType); if (intern) { h = new InterningXmlVisitor(h); } return new SAXConnector(h,null); }
Creates and configures a new unmarshalling pipe line. Depending on the setting, we put a validator as a filter.
Returns: A component that implements both UnmarshallerHandler and ValidationEventHandler. All the parsing errors should be reported to this error handler for the unmarshalling process to work correctly. Also, returned handler expects all the XML names to be interned.
/** * Creates and configures a new unmarshalling pipe line. * Depending on the setting, we put a validator as a filter. * * @return * A component that implements both {@link UnmarshallerHandler} * and {@link ValidationEventHandler}. All the parsing errors * should be reported to this error handler for the unmarshalling * process to work correctly. * * Also, returned handler expects all the XML names to be interned. * */
public final XmlVisitor createUnmarshallerHandler(InfosetScanner scanner, boolean inplace, JaxBeanInfo expectedType ) { coordinator.reset(scanner,inplace,expectedType,idResolver); XmlVisitor unmarshaller = coordinator; // delegate to JAXP 1.3 for validation if the client provided a schema if (schema != null) { unmarshaller = new ValidatingUnmarshaller(schema,unmarshaller); } if(attachmentUnmarshaller!=null && attachmentUnmarshaller.isXOPPackage()) { unmarshaller = new MTOMDecorator(this,unmarshaller,attachmentUnmarshaller); } return unmarshaller; } private static final DefaultHandler dummyHandler = new DefaultHandler(); public static boolean needsInterning( XMLReader reader ) { // attempt to set it to true, which could fail try { reader.setFeature("http://xml.org/sax/features/string-interning",true); } catch (SAXException e) { // if it fails that's fine. we'll work around on our side } try { if (reader.getFeature("http://xml.org/sax/features/string-interning")) { return false; // no need for intern } } catch (SAXException e) { // unrecognized/unsupported } // otherwise we need intern return true; } protected Object unmarshal( XMLReader reader, InputSource source ) throws JAXBException { return unmarshal0(reader,source,null); } protected <T> JAXBElement<T> unmarshal( XMLReader reader, InputSource source, Class<T> expectedType ) throws JAXBException { if(expectedType==null) { throw new IllegalArgumentException(); } return (JAXBElement)unmarshal0(reader,source,getBeanInfo(expectedType)); } private Object unmarshal0( XMLReader reader, InputSource source, JaxBeanInfo expectedType ) throws JAXBException { SAXConnector connector = getUnmarshallerHandler(needsInterning(reader),expectedType); reader.setContentHandler(connector); // saxErrorHandler will be set by the getUnmarshallerHandler method. // configure XMLReader so that the error will be sent to it. // This is essential for the UnmarshallerHandler to be able to abort // unmarshalling when an error is found. // // Note that when this XMLReader is provided by the client code, // it might be already configured to call a client error handler. // This will clobber such handler, if any. // // Ryan noted that we might want to report errors to such a client // error handler as well. reader.setErrorHandler(coordinator); try { reader.parse(source); } catch( IOException e ) { coordinator.clearStates(); throw new UnmarshalException(e); } catch( SAXException e ) { coordinator.clearStates(); throw createUnmarshalException(e); } Object result = connector.getResult(); // avoid keeping unnecessary references too long to let the GC // reclaim more memory. // setting null upsets some parsers, so use a dummy instance instead. reader.setContentHandler(dummyHandler); reader.setErrorHandler(dummyHandler); return result; } @Override public <T> JAXBElement<T> unmarshal( Source source, Class<T> expectedType ) throws JAXBException { if (source instanceof SAXSource) { SAXSource ss = (SAXSource) source; XMLReader locReader = ss.getXMLReader(); if (locReader == null) { locReader = getXMLReader(); } return unmarshal(locReader, ss.getInputSource(), expectedType); } if (source instanceof StreamSource) { return unmarshal(getXMLReader(), streamSourceToInputSource((StreamSource) source), expectedType); } if (source instanceof DOMSource) { return unmarshal(((DOMSource) source).getNode(), expectedType); } // we don't handle other types of Source throw new IllegalArgumentException(); } public Object unmarshal0( Source source, JaxBeanInfo expectedType ) throws JAXBException { if (source instanceof SAXSource) { SAXSource ss = (SAXSource) source; XMLReader locReader = ss.getXMLReader(); if (locReader == null) { locReader = getXMLReader(); } return unmarshal0(locReader, ss.getInputSource(), expectedType); } if (source instanceof StreamSource) { return unmarshal0(getXMLReader(), streamSourceToInputSource((StreamSource) source), expectedType); } if (source instanceof DOMSource) { return unmarshal0(((DOMSource) source).getNode(), expectedType); } // we don't handle other types of Source throw new IllegalArgumentException(); } @Override public final ValidationEventHandler getEventHandler() { try { return super.getEventHandler(); } catch (JAXBException e) { // impossible throw new AssertionError(); } }
Returns true if an event handler is installed.

The default handler ignores any errors, and for that this method returns false.

/** * Returns true if an event handler is installed. * <p> * The default handler ignores any errors, and for that this method returns false. */
public final boolean hasEventHandler() { return getEventHandler()!=this; } @Override public <T> JAXBElement<T> unmarshal(Node node, Class<T> expectedType) throws JAXBException { if (expectedType == null) { throw new IllegalArgumentException(); } return (JAXBElement)unmarshal0(node,getBeanInfo(expectedType)); } public final Object unmarshal( Node node ) throws JAXBException { return unmarshal0(node,null); } // just to make the the test harness happy by making this method accessible @Deprecated public final Object unmarshal( SAXSource source ) throws JAXBException { return super.unmarshal(source); } public final Object unmarshal0( Node node, JaxBeanInfo expectedType ) throws JAXBException { try { final DOMScanner scanner = new DOMScanner(); InterningXmlVisitor handler = new InterningXmlVisitor(createUnmarshallerHandler(null,false,expectedType)); scanner.setContentHandler(new SAXConnector(handler,scanner)); if(node.getNodeType() == Node.ELEMENT_NODE) { scanner.scan((Element)node); } else if(node.getNodeType() == Node.DOCUMENT_NODE) { scanner.scan((Document)node); } else { throw new IllegalArgumentException("Unexpected node type: "+node); } Object retVal = handler.getContext().getResult(); handler.getContext().clearResult(); return retVal; } catch( SAXException e ) { throw createUnmarshalException(e); } } @Override public Object unmarshal(XMLStreamReader reader) throws JAXBException { return unmarshal0(reader,null); } @Override public <T> JAXBElement<T> unmarshal(XMLStreamReader reader, Class<T> expectedType) throws JAXBException { if (expectedType==null) { throw new IllegalArgumentException(); } return (JAXBElement)unmarshal0(reader,getBeanInfo(expectedType)); } public Object unmarshal0(XMLStreamReader reader, JaxBeanInfo expectedType) throws JAXBException { if (reader == null) { throw new IllegalArgumentException( Messages.format(Messages.NULL_READER)); } int eventType = reader.getEventType(); if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.START_DOCUMENT) { // TODO: convert eventType into event name throw new IllegalStateException( Messages.format(Messages.ILLEGAL_READER_STATE,eventType)); } XmlVisitor h = createUnmarshallerHandler(null,false,expectedType); StAXConnector connector=StAXStreamConnector.create(reader,h); try { connector.bridge(); } catch (XMLStreamException e) { throw handleStreamException(e); } Object retVal = h.getContext().getResult(); h.getContext().clearResult(); return retVal; } @Override public <T> JAXBElement<T> unmarshal(XMLEventReader reader, Class<T> expectedType) throws JAXBException { if(expectedType==null) { throw new IllegalArgumentException(); } return (JAXBElement)unmarshal0(reader,getBeanInfo(expectedType)); } @Override public Object unmarshal(XMLEventReader reader) throws JAXBException { return unmarshal0(reader,null); } private Object unmarshal0(XMLEventReader reader,JaxBeanInfo expectedType) throws JAXBException { if (reader == null) { throw new IllegalArgumentException( Messages.format(Messages.NULL_READER)); } try { XMLEvent event = reader.peek(); if (!event.isStartElement() && !event.isStartDocument()) { // TODO: convert event into event name throw new IllegalStateException( Messages.format( Messages.ILLEGAL_READER_STATE,event.getEventType())); } // Quick hack until SJSXP fixes 6270116 boolean isZephyr = reader.getClass().getName().equals("com.sun.xml.internal.stream.XMLReaderImpl"); XmlVisitor h = createUnmarshallerHandler(null,false,expectedType); if(!isZephyr) { h = new InterningXmlVisitor(h); } new StAXEventConnector(reader,h).bridge(); return h.getContext().getResult(); } catch (XMLStreamException e) { throw handleStreamException(e); } } public Object unmarshal0( InputStream input, JaxBeanInfo expectedType ) throws JAXBException { return unmarshal0(getXMLReader(),new InputSource(input),expectedType); } private static JAXBException handleStreamException(XMLStreamException e) { // StAXStreamConnector wraps SAXException to XMLStreamException. // XMLStreamException doesn't print its nested stack trace when it prints // its stack trace, so if we wrap XMLStreamException in JAXBException, // it becomes harder to find out the real problem. // So we unwrap them here. But we don't want to unwrap too eagerly, because // that could throw away some meaningful exception information. Throwable ne = e.getNestedException(); if(ne instanceof JAXBException) { return (JAXBException)ne; } if(ne instanceof SAXException) { return new UnmarshalException(ne); } return new UnmarshalException(e); } @Override public Object getProperty(String name) throws PropertyException { if(name.equals(IDResolver.class.getName())) { return idResolver; } return super.getProperty(name); } @Override public void setProperty(String name, Object value) throws PropertyException { if(name.equals(FACTORY)) { coordinator.setFactories(value); return; } if(name.equals(IDResolver.class.getName())) { idResolver = (IDResolver)value; return; } if(name.equals(ClassResolver.class.getName())) { coordinator.classResolver = (ClassResolver)value; return; } if(name.equals(ClassLoader.class.getName())) { coordinator.classLoader = (ClassLoader)value; return; } super.setProperty(name, value); } public static final String FACTORY = "com.sun.xml.internal.bind.ObjectFactory"; @Override public void setSchema(Schema schema) { this.schema = schema; } @Override public Schema getSchema() { return schema; } @Override public AttachmentUnmarshaller getAttachmentUnmarshaller() { return attachmentUnmarshaller; } @Override public void setAttachmentUnmarshaller(AttachmentUnmarshaller au) { this.attachmentUnmarshaller = au; }
Deprecated:since 2.0
/** * @deprecated since 2.0 */
@Override public boolean isValidating() { throw new UnsupportedOperationException(); }
Deprecated:since 2.0
/** * @deprecated since 2.0 */
@Override public void setValidating(boolean validating) { throw new UnsupportedOperationException(); } @Override public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) { if (type==null) { throw new IllegalArgumentException(); } coordinator.putAdapter(type,adapter); } @Override public <A extends XmlAdapter> A getAdapter(Class<A> type) { if(type==null) { throw new IllegalArgumentException(); } if(coordinator.containsAdapter(type)) { return coordinator.getAdapter(type); } else { return null; } } // opening up for public use @Override public UnmarshalException createUnmarshalException( SAXException e ) { return super.createUnmarshalException(e); }
Default error handling behavior for Unmarshaller.
/** * Default error handling behavior for {@link Unmarshaller}. */
public boolean handleEvent(ValidationEvent event) { return event.getSeverity()!=ValidationEvent.FATAL_ERROR; } private static InputSource streamSourceToInputSource( StreamSource ss ) { InputSource is = new InputSource(); is.setSystemId( ss.getSystemId() ); is.setByteStream( ss.getInputStream() ); is.setCharacterStream( ss.getReader() ); return is; } public <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz) throws JAXBException { return context.getBeanInfo(clazz,true); } @Override public Listener getListener() { return externalListener; } @Override public void setListener(Listener listener) { externalListener = listener; } public UnmarshallingContext getContext() { return coordinator; } @Override @SuppressWarnings("FinalizeDeclaration") protected void finalize() throws Throwable { try { ClassFactory.cleanCache(); } finally { super.finalize(); } }
Must be called from same thread which created the UnmarshallerImpl instance.
Throws:
  • IOException –
/** * Must be called from same thread which created the UnmarshallerImpl instance. * @throws IOException */
public void close() throws IOException { ClassFactory.cleanCache(); } }