1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/UnmarshallerImpl.java Tue Mar 06 16:09:35 2012 -0800 1.3 @@ -0,0 +1,568 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.xml.internal.bind.v2.runtime.unmarshaller; 1.30 + 1.31 +import java.io.IOException; 1.32 +import java.io.InputStream; 1.33 + 1.34 +import javax.xml.bind.JAXBContext; 1.35 +import javax.xml.bind.JAXBElement; 1.36 +import javax.xml.bind.JAXBException; 1.37 +import javax.xml.bind.PropertyException; 1.38 +import javax.xml.bind.UnmarshalException; 1.39 +import javax.xml.bind.Unmarshaller; 1.40 +import javax.xml.bind.UnmarshallerHandler; 1.41 +import javax.xml.bind.ValidationEvent; 1.42 +import javax.xml.bind.ValidationEventHandler; 1.43 +import javax.xml.bind.annotation.adapters.XmlAdapter; 1.44 +import javax.xml.bind.attachment.AttachmentUnmarshaller; 1.45 +import javax.xml.bind.helpers.AbstractUnmarshallerImpl; 1.46 +import javax.xml.stream.XMLEventReader; 1.47 +import javax.xml.stream.XMLStreamConstants; 1.48 +import javax.xml.stream.XMLStreamException; 1.49 +import javax.xml.stream.XMLStreamReader; 1.50 +import javax.xml.stream.events.XMLEvent; 1.51 +import javax.xml.transform.Source; 1.52 +import javax.xml.transform.dom.DOMSource; 1.53 +import javax.xml.transform.sax.SAXSource; 1.54 +import javax.xml.transform.stream.StreamSource; 1.55 +import javax.xml.validation.Schema; 1.56 + 1.57 +import com.sun.xml.internal.bind.IDResolver; 1.58 +import com.sun.xml.internal.bind.api.ClassResolver; 1.59 +import com.sun.xml.internal.bind.unmarshaller.DOMScanner; 1.60 +import com.sun.xml.internal.bind.unmarshaller.InfosetScanner; 1.61 +import com.sun.xml.internal.bind.unmarshaller.Messages; 1.62 +import com.sun.xml.internal.bind.v2.ClassFactory; 1.63 +import com.sun.xml.internal.bind.v2.runtime.AssociationMap; 1.64 +import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; 1.65 +import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo; 1.66 + 1.67 +import java.io.Closeable; 1.68 +import org.w3c.dom.Document; 1.69 +import org.w3c.dom.Element; 1.70 +import org.w3c.dom.Node; 1.71 +import org.xml.sax.InputSource; 1.72 +import org.xml.sax.SAXException; 1.73 +import org.xml.sax.XMLReader; 1.74 +import org.xml.sax.helpers.DefaultHandler; 1.75 + 1.76 +/** 1.77 + * Default Unmarshaller implementation. 1.78 + * 1.79 + * <p> 1.80 + * This class can be extended by the generated code to provide 1.81 + * type-safe unmarshall methods. 1.82 + * 1.83 + * @author 1.84 + * <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> 1.85 + */ 1.86 +public final class UnmarshallerImpl extends AbstractUnmarshallerImpl implements ValidationEventHandler, Closeable 1.87 +{ 1.88 + /** Owning {@link JAXBContext} */ 1.89 + protected final JAXBContextImpl context; 1.90 + 1.91 + /** 1.92 + * schema which will be used to validate during calls to unmarshal 1.93 + */ 1.94 + private Schema schema; 1.95 + 1.96 + public final UnmarshallingContext coordinator; 1.97 + 1.98 + /** Unmarshaller.Listener */ 1.99 + private Listener externalListener; 1.100 + 1.101 + /** 1.102 + * The attachment unmarshaller used to support MTOM and swaRef. 1.103 + */ 1.104 + private AttachmentUnmarshaller attachmentUnmarshaller; 1.105 + private IDResolver idResolver = new DefaultIDResolver(); 1.106 + 1.107 + public UnmarshallerImpl( JAXBContextImpl context, AssociationMap assoc ) { 1.108 + this.context = context; 1.109 + this.coordinator = new UnmarshallingContext( this, assoc ); 1.110 + 1.111 + try { 1.112 + setEventHandler(this); 1.113 + } catch (JAXBException e) { 1.114 + throw new AssertionError(e); // impossible 1.115 + } 1.116 + } 1.117 + 1.118 + public UnmarshallerHandler getUnmarshallerHandler() { 1.119 + return getUnmarshallerHandler(true,null); 1.120 + } 1.121 + 1.122 + private SAXConnector getUnmarshallerHandler( boolean intern, JaxBeanInfo expectedType ) { 1.123 + XmlVisitor h = createUnmarshallerHandler(null,false,expectedType); 1.124 + if(intern) 1.125 + h = new InterningXmlVisitor(h); 1.126 + return new SAXConnector(h,null); 1.127 + } 1.128 + 1.129 + /** 1.130 + * Creates and configures a new unmarshalling pipe line. 1.131 + * Depending on the setting, we put a validator as a filter. 1.132 + * 1.133 + * @return 1.134 + * A component that implements both {@link UnmarshallerHandler} 1.135 + * and {@link ValidationEventHandler}. All the parsing errors 1.136 + * should be reported to this error handler for the unmarshalling 1.137 + * process to work correctly. 1.138 + * 1.139 + * Also, returned handler expects all the XML names to be interned. 1.140 + * 1.141 + */ 1.142 + public final XmlVisitor createUnmarshallerHandler(InfosetScanner scanner, boolean inplace, JaxBeanInfo expectedType ) { 1.143 + 1.144 + coordinator.reset(scanner,inplace,expectedType,idResolver); 1.145 + XmlVisitor unmarshaller = coordinator; 1.146 + 1.147 + // delegate to JAXP 1.3 for validation if the client provided a schema 1.148 + if (schema != null) 1.149 + unmarshaller = new ValidatingUnmarshaller(schema,unmarshaller); 1.150 + 1.151 + if(attachmentUnmarshaller!=null && attachmentUnmarshaller.isXOPPackage()) 1.152 + unmarshaller = new MTOMDecorator(this,unmarshaller,attachmentUnmarshaller); 1.153 + 1.154 + return unmarshaller; 1.155 + } 1.156 + 1.157 + private static final DefaultHandler dummyHandler = new DefaultHandler(); 1.158 + 1.159 + public static boolean needsInterning( XMLReader reader ) { 1.160 + // attempt to set it to true, which could fail 1.161 + try { 1.162 + reader.setFeature("http://xml.org/sax/features/string-interning",true); 1.163 + } catch (SAXException e) { 1.164 + // if it fails that's fine. we'll work around on our side 1.165 + } 1.166 + 1.167 + try { 1.168 + if( reader.getFeature("http://xml.org/sax/features/string-interning") ) 1.169 + return false; // no need for intern 1.170 + } catch (SAXException e) { 1.171 + // unrecognized/unsupported 1.172 + } 1.173 + // otherwise we need intern 1.174 + return true; 1.175 + } 1.176 + 1.177 + protected Object unmarshal( XMLReader reader, InputSource source ) throws JAXBException { 1.178 + return unmarshal0(reader,source,null); 1.179 + } 1.180 + 1.181 + protected <T> JAXBElement<T> unmarshal( XMLReader reader, InputSource source, Class<T> expectedType ) throws JAXBException { 1.182 + if(expectedType==null) 1.183 + throw new IllegalArgumentException(); 1.184 + return (JAXBElement)unmarshal0(reader,source,getBeanInfo(expectedType)); 1.185 + } 1.186 + 1.187 + private Object unmarshal0( XMLReader reader, InputSource source, JaxBeanInfo expectedType ) throws JAXBException { 1.188 + 1.189 + SAXConnector connector = getUnmarshallerHandler(needsInterning(reader),expectedType); 1.190 + 1.191 + reader.setContentHandler(connector); 1.192 + // saxErrorHandler will be set by the getUnmarshallerHandler method. 1.193 + // configure XMLReader so that the error will be sent to it. 1.194 + // This is essential for the UnmarshallerHandler to be able to abort 1.195 + // unmarshalling when an error is found. 1.196 + // 1.197 + // Note that when this XMLReader is provided by the client code, 1.198 + // it might be already configured to call a client error handler. 1.199 + // This will clobber such handler, if any. 1.200 + // 1.201 + // Ryan noted that we might want to report errors to such a client 1.202 + // error handler as well. 1.203 + reader.setErrorHandler(coordinator); 1.204 + 1.205 + try { 1.206 + reader.parse(source); 1.207 + } catch( IOException e ) { 1.208 + coordinator.clearStates(); 1.209 + throw new UnmarshalException(e); 1.210 + } catch( SAXException e ) { 1.211 + coordinator.clearStates(); 1.212 + throw createUnmarshalException(e); 1.213 + } 1.214 + 1.215 + Object result = connector.getResult(); 1.216 + 1.217 + // avoid keeping unnecessary references too long to let the GC 1.218 + // reclaim more memory. 1.219 + // setting null upsets some parsers, so use a dummy instance instead. 1.220 + reader.setContentHandler(dummyHandler); 1.221 + reader.setErrorHandler(dummyHandler); 1.222 + 1.223 + return result; 1.224 + } 1.225 + 1.226 + @Override 1.227 + public <T> JAXBElement<T> unmarshal( Source source, Class<T> expectedType ) throws JAXBException { 1.228 + if(source instanceof SAXSource) { 1.229 + SAXSource ss = (SAXSource)source; 1.230 + 1.231 + XMLReader reader = ss.getXMLReader(); 1.232 + if( reader == null ) 1.233 + reader = getXMLReader(); 1.234 + 1.235 + return unmarshal( reader, ss.getInputSource(), expectedType ); 1.236 + } 1.237 + if(source instanceof StreamSource) { 1.238 + return unmarshal( getXMLReader(), streamSourceToInputSource((StreamSource)source), expectedType ); 1.239 + } 1.240 + if(source instanceof DOMSource) 1.241 + return unmarshal( ((DOMSource)source).getNode(), expectedType ); 1.242 + 1.243 + // we don't handle other types of Source 1.244 + throw new IllegalArgumentException(); 1.245 + } 1.246 + 1.247 + public Object unmarshal0( Source source, JaxBeanInfo expectedType ) throws JAXBException { 1.248 + if(source instanceof SAXSource) { 1.249 + SAXSource ss = (SAXSource)source; 1.250 + 1.251 + XMLReader reader = ss.getXMLReader(); 1.252 + if( reader == null ) 1.253 + reader = getXMLReader(); 1.254 + 1.255 + return unmarshal0( reader, ss.getInputSource(), expectedType ); 1.256 + } 1.257 + if(source instanceof StreamSource) { 1.258 + return unmarshal0( getXMLReader(), streamSourceToInputSource((StreamSource)source), expectedType ); 1.259 + } 1.260 + if(source instanceof DOMSource) 1.261 + return unmarshal0( ((DOMSource)source).getNode(), expectedType ); 1.262 + 1.263 + // we don't handle other types of Source 1.264 + throw new IllegalArgumentException(); 1.265 + } 1.266 + 1.267 + 1.268 + @Override 1.269 + public final ValidationEventHandler getEventHandler() { 1.270 + try { 1.271 + return super.getEventHandler(); 1.272 + } catch (JAXBException e) { 1.273 + // impossible 1.274 + throw new AssertionError(); 1.275 + } 1.276 + } 1.277 + 1.278 + /** 1.279 + * Returns true if an event handler is installed. 1.280 + * <p> 1.281 + * The default handler ignores any errors, and for that this method returns false. 1.282 + */ 1.283 + public final boolean hasEventHandler() { 1.284 + return getEventHandler()!=this; 1.285 + } 1.286 + 1.287 + @Override 1.288 + public <T> JAXBElement<T> unmarshal(Node node, Class<T> expectedType) throws JAXBException { 1.289 + if(expectedType==null) 1.290 + throw new IllegalArgumentException(); 1.291 + return (JAXBElement)unmarshal0(node,getBeanInfo(expectedType)); 1.292 + } 1.293 + 1.294 + public final Object unmarshal( Node node ) throws JAXBException { 1.295 + return unmarshal0(node,null); 1.296 + } 1.297 + 1.298 + // just to make the the test harness happy by making this method accessible 1.299 + @Deprecated 1.300 + public final Object unmarshal( SAXSource source ) throws JAXBException { 1.301 + return super.unmarshal(source); 1.302 + } 1.303 + 1.304 + public final Object unmarshal0( Node node, JaxBeanInfo expectedType ) throws JAXBException { 1.305 + try { 1.306 + final DOMScanner scanner = new DOMScanner(); 1.307 + 1.308 + InterningXmlVisitor handler = new InterningXmlVisitor(createUnmarshallerHandler(null,false,expectedType)); 1.309 + scanner.setContentHandler(new SAXConnector(handler,scanner)); 1.310 + 1.311 + if(node.getNodeType() == Node.ELEMENT_NODE) 1.312 + scanner.scan((Element)node); 1.313 + else 1.314 + if(node.getNodeType() == Node.DOCUMENT_NODE) 1.315 + scanner.scan((Document)node); 1.316 + else 1.317 + // no other type of input is supported 1.318 + throw new IllegalArgumentException("Unexpected node type: "+node); 1.319 + 1.320 + Object retVal = handler.getContext().getResult(); 1.321 + handler.getContext().clearResult(); 1.322 + return retVal; 1.323 + } catch( SAXException e ) { 1.324 + throw createUnmarshalException(e); 1.325 + } 1.326 + } 1.327 + 1.328 + @Override 1.329 + public Object unmarshal(XMLStreamReader reader) throws JAXBException { 1.330 + return unmarshal0(reader,null); 1.331 + } 1.332 + 1.333 + @Override 1.334 + public <T> JAXBElement<T> unmarshal(XMLStreamReader reader, Class<T> expectedType) throws JAXBException { 1.335 + if(expectedType==null) 1.336 + throw new IllegalArgumentException(); 1.337 + return (JAXBElement)unmarshal0(reader,getBeanInfo(expectedType)); 1.338 + } 1.339 + 1.340 + public Object unmarshal0(XMLStreamReader reader, JaxBeanInfo expectedType) throws JAXBException { 1.341 + if (reader == null) { 1.342 + throw new IllegalArgumentException( 1.343 + Messages.format(Messages.NULL_READER)); 1.344 + } 1.345 + 1.346 + int eventType = reader.getEventType(); 1.347 + if (eventType != XMLStreamConstants.START_ELEMENT 1.348 + && eventType != XMLStreamConstants.START_DOCUMENT) { 1.349 + // TODO: convert eventType into event name 1.350 + throw new IllegalStateException( 1.351 + Messages.format(Messages.ILLEGAL_READER_STATE,eventType)); 1.352 + } 1.353 + 1.354 + XmlVisitor h = createUnmarshallerHandler(null,false,expectedType); 1.355 + StAXConnector connector=StAXStreamConnector.create(reader,h); 1.356 + 1.357 + try { 1.358 + connector.bridge(); 1.359 + } catch (XMLStreamException e) { 1.360 + throw handleStreamException(e); 1.361 + } 1.362 + 1.363 + Object retVal = h.getContext().getResult(); 1.364 + h.getContext().clearResult(); 1.365 + return retVal; 1.366 + } 1.367 + 1.368 + @Override 1.369 + public <T> JAXBElement<T> unmarshal(XMLEventReader reader, Class<T> expectedType) throws JAXBException { 1.370 + if(expectedType==null) 1.371 + throw new IllegalArgumentException(); 1.372 + return (JAXBElement)unmarshal0(reader,getBeanInfo(expectedType)); 1.373 + } 1.374 + 1.375 + @Override 1.376 + public Object unmarshal(XMLEventReader reader) throws JAXBException { 1.377 + return unmarshal0(reader,null); 1.378 + } 1.379 + 1.380 + private Object unmarshal0(XMLEventReader reader,JaxBeanInfo expectedType) throws JAXBException { 1.381 + if (reader == null) { 1.382 + throw new IllegalArgumentException( 1.383 + Messages.format(Messages.NULL_READER)); 1.384 + } 1.385 + 1.386 + try { 1.387 + XMLEvent event = reader.peek(); 1.388 + 1.389 + if (!event.isStartElement() && !event.isStartDocument()) { 1.390 + // TODO: convert event into event name 1.391 + throw new IllegalStateException( 1.392 + Messages.format( 1.393 + Messages.ILLEGAL_READER_STATE,event.getEventType())); 1.394 + } 1.395 + 1.396 + // Quick hack until SJSXP fixes 6270116 1.397 + boolean isZephyr = reader.getClass().getName().equals("com.sun.xml.internal.stream.XMLReaderImpl"); 1.398 + XmlVisitor h = createUnmarshallerHandler(null,false,expectedType); 1.399 + if(!isZephyr) 1.400 + h = new InterningXmlVisitor(h); 1.401 + new StAXEventConnector(reader,h).bridge(); 1.402 + return h.getContext().getResult(); 1.403 + } catch (XMLStreamException e) { 1.404 + throw handleStreamException(e); 1.405 + } 1.406 + } 1.407 + 1.408 + public Object unmarshal0( InputStream input, JaxBeanInfo expectedType ) throws JAXBException { 1.409 + return unmarshal0(getXMLReader(),new InputSource(input),expectedType); 1.410 + } 1.411 + 1.412 + private static JAXBException handleStreamException(XMLStreamException e) { 1.413 + // StAXStreamConnector wraps SAXException to XMLStreamException. 1.414 + // XMLStreamException doesn't print its nested stack trace when it prints 1.415 + // its stack trace, so if we wrap XMLStreamException in JAXBException, 1.416 + // it becomes harder to find out the real problem. 1.417 + // So we unwrap them here. But we don't want to unwrap too eagerly, because 1.418 + // that could throw away some meaningful exception information. 1.419 + Throwable ne = e.getNestedException(); 1.420 + if(ne instanceof JAXBException) 1.421 + return (JAXBException)ne; 1.422 + if(ne instanceof SAXException) 1.423 + return new UnmarshalException(ne); 1.424 + return new UnmarshalException(e); 1.425 + } 1.426 + 1.427 + @Override 1.428 + public Object getProperty(String name) throws PropertyException { 1.429 + if(name.equals(IDResolver.class.getName())) { 1.430 + return idResolver; 1.431 + } 1.432 + return super.getProperty(name); 1.433 + } 1.434 + 1.435 + @Override 1.436 + public void setProperty(String name, Object value) throws PropertyException { 1.437 + if(name.equals(FACTORY)) { 1.438 + coordinator.setFactories(value); 1.439 + return; 1.440 + } 1.441 + if(name.equals(IDResolver.class.getName())) { 1.442 + idResolver = (IDResolver)value; 1.443 + return; 1.444 + } 1.445 + if(name.equals(ClassResolver.class.getName())) { 1.446 + coordinator.classResolver = (ClassResolver)value; 1.447 + return; 1.448 + } 1.449 + if(name.equals(ClassLoader.class.getName())) { 1.450 + coordinator.classLoader = (ClassLoader)value; 1.451 + return; 1.452 + } 1.453 + super.setProperty(name, value); 1.454 + } 1.455 + 1.456 + public static final String FACTORY = "com.sun.xml.internal.bind.ObjectFactory"; 1.457 + 1.458 + @Override 1.459 + public void setSchema(Schema schema) { 1.460 + this.schema = schema; 1.461 + } 1.462 + 1.463 + @Override 1.464 + public Schema getSchema() { 1.465 + return schema; 1.466 + } 1.467 + 1.468 + @Override 1.469 + public AttachmentUnmarshaller getAttachmentUnmarshaller() { 1.470 + return attachmentUnmarshaller; 1.471 + } 1.472 + 1.473 + @Override 1.474 + public void setAttachmentUnmarshaller(AttachmentUnmarshaller au) { 1.475 + this.attachmentUnmarshaller = au; 1.476 + } 1.477 + 1.478 + /** 1.479 + * @deprecated since 2.0 1.480 + */ 1.481 + @Override 1.482 + public boolean isValidating() { 1.483 + throw new UnsupportedOperationException(); 1.484 + } 1.485 + 1.486 + /** 1.487 + * @deprecated since 2.0 1.488 + */ 1.489 + @Override 1.490 + public void setValidating(boolean validating) { 1.491 + throw new UnsupportedOperationException(); 1.492 + } 1.493 + 1.494 + @Override 1.495 + public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) { 1.496 + if(type==null) 1.497 + throw new IllegalArgumentException(); 1.498 + coordinator.putAdapter(type,adapter); 1.499 + } 1.500 + 1.501 + @Override 1.502 + public <A extends XmlAdapter> A getAdapter(Class<A> type) { 1.503 + if(type==null) 1.504 + throw new IllegalArgumentException(); 1.505 + if(coordinator.containsAdapter(type)) 1.506 + // so as not to create a new instance when this method is called 1.507 + return coordinator.getAdapter(type); 1.508 + else 1.509 + return null; 1.510 + } 1.511 + 1.512 + // opening up for public use 1.513 + @Override 1.514 + public UnmarshalException createUnmarshalException( SAXException e ) { 1.515 + return super.createUnmarshalException(e); 1.516 + } 1.517 + 1.518 + 1.519 + /** 1.520 + * Default error handling behavior for {@link Unmarshaller}. 1.521 + */ 1.522 + public boolean handleEvent(ValidationEvent event) { 1.523 + return event.getSeverity()!=ValidationEvent.FATAL_ERROR; 1.524 + } 1.525 + 1.526 + private static InputSource streamSourceToInputSource( StreamSource ss ) { 1.527 + InputSource is = new InputSource(); 1.528 + is.setSystemId( ss.getSystemId() ); 1.529 + is.setByteStream( ss.getInputStream() ); 1.530 + is.setCharacterStream( ss.getReader() ); 1.531 + 1.532 + return is; 1.533 + } 1.534 + 1.535 + public <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz) throws JAXBException { 1.536 + return context.getBeanInfo(clazz,true); 1.537 + } 1.538 + 1.539 + @Override 1.540 + public Listener getListener() { 1.541 + return externalListener; 1.542 + } 1.543 + 1.544 + @Override 1.545 + public void setListener(Listener listener) { 1.546 + externalListener = listener; 1.547 + } 1.548 + 1.549 + public UnmarshallingContext getContext() { 1.550 + return coordinator; 1.551 + } 1.552 + 1.553 + @Override 1.554 + @SuppressWarnings("FinalizeDeclaration") 1.555 + protected void finalize() throws Throwable { 1.556 + try { 1.557 + ClassFactory.cleanCache(); 1.558 + } finally { 1.559 + super.finalize(); 1.560 + } 1.561 + } 1.562 + 1.563 + /** 1.564 + * Must be called from same thread which created the UnmarshallerImpl instance. 1.565 + * @throws IOException 1.566 + */ 1.567 + public void close() throws IOException { 1.568 + ClassFactory.cleanCache(); 1.569 + } 1.570 + 1.571 +}