From 7fdf40c6939ec162a1818f211f233d9955ea0451 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 5 Feb 2014 09:09:03 -0600 Subject: [PATCH] HHH-8894 - Use an "upgrade" approach to validate and bind (JAXB) mapping XML --- .../hibernate/InvalidMappingException.java | 64 ---- .../java/org/hibernate/cfg/Configuration.java | 1 + .../internal/util/xml/DTDEntityResolver.java | 1 + .../internal/util/xml/ErrorLogger.java | 1 + .../internal/util/xml/MappingReader.java | 321 ------------------ .../hibernate/internal/util/xml/Origin.java | 3 +- .../internal/util/xml/OriginImpl.java | 1 + .../internal/util/xml/XMLHelper.java | 1 + .../internal/util/xml/XmlDocument.java | 1 + .../internal/util/xml/XmlDocumentImpl.java | 4 +- .../xml/internal/jaxb/AbstractXmlBinder.java | 88 +++-- ...ontextProvidingValidationEventHandler.java | 60 ++++ .../xml/internal/jaxb/MappingXmlBinder.java | 17 +- .../internal/stax/SupportedOrmXsdVersion.java | 6 +- .../UnsupportedOrmXsdVersionException.java | 2 +- .../jpa/test/jee/OrmVersionTest.java | 8 +- 16 files changed, 141 insertions(+), 438 deletions(-) delete mode 100644 hibernate-core/src/main/java/org/hibernate/internal/util/xml/MappingReader.java create mode 100644 hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/ContextProvidingValidationEventHandler.java diff --git a/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java b/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java index 08a34f1ca5..2c8b7d7451 100644 --- a/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java +++ b/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java @@ -24,7 +24,6 @@ package org.hibernate; import org.hibernate.xml.spi.Origin; -import org.hibernate.internal.util.xml.XmlDocument; /** * Thrown when a mapping is found to be invalid. @@ -66,27 +65,6 @@ public InvalidMappingException(String customMessage, String type, String path) { this.path=path; } - /** - * Constructs an InvalidMappingException using the given information. - * - * @param customMessage The custom message explaining the exception condition - * @param xmlDocument The document that was invalid - * @param cause The underlying cause - */ - public InvalidMappingException(String customMessage, XmlDocument xmlDocument, Throwable cause) { - this( customMessage, xmlDocument.getOrigin().getType(), xmlDocument.getOrigin().getName(), cause ); - } - - /** - * Constructs an InvalidMappingException using the given information. - * - * @param customMessage The custom message explaining the exception condition - * @param xmlDocument The document that was invalid - */ - public InvalidMappingException(String customMessage, XmlDocument xmlDocument) { - this( customMessage, xmlDocument.getOrigin().getType(), xmlDocument.getOrigin().getName() ); - } - /** * Constructs an InvalidMappingException using the given information. * @@ -97,48 +75,6 @@ public InvalidMappingException(String customMessage, Origin origin) { this( customMessage, origin.getType().toString(), origin.getName() ); } - /** - * Constructs an InvalidMappingException using the given information and a standard message. - * - * @param type The type of invalid mapping document - * @param path The path (type specific) of the invalid mapping document - */ - public InvalidMappingException(String type, String path) { - this( "Could not parse mapping document from " + type + (path==null?"":" " + path), type, path ); - } - - /** - * Constructs an InvalidMappingException using the given information and a standard message. - * - * @param type The type of invalid mapping document - * @param path The path (type specific) of the invalid mapping document - * @param cause The underlying cause - */ - public InvalidMappingException(String type, String path, Throwable cause) { - this( "Could not parse mapping document from " + type + (path==null?"":" " + path), type, path, cause ); - } - - /** - * Constructs an InvalidMappingException using the given information. - * - * @param customMessage The custom message explaining the exception condition - * @param origin The origin of the invalid mapping document - * @param cause The underlying cause - */ - public InvalidMappingException(String customMessage, org.hibernate.internal.util.xml.Origin origin, Exception cause) { - this( customMessage, origin.getType(), origin.getName(), cause ); - } - - /** - * Constructs an InvalidMappingException using the given information. - * - * @param customMessage The custom message explaining the exception condition - * @param origin The origin of the invalid mapping document - */ - public InvalidMappingException(String customMessage, org.hibernate.internal.util.xml.Origin origin) { - this( customMessage, origin, null ); - } - public String getType() { return type; } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java index 4dfa7c3ce1..7ea7bf5e41 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java @@ -381,6 +381,7 @@ public Configuration addFile(File xmlFile) throws MappingException { @Deprecated public void add(XmlDocument metadataXml) { } + /** * Add a cached mapping file. A cached file is a serialized representation * of the DOM structure of a particular mapping. It is saved from a previous diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/DTDEntityResolver.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/DTDEntityResolver.java index 66008b68a2..afd8b6ec77 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/DTDEntityResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/DTDEntityResolver.java @@ -55,6 +55,7 @@ * @author Steve Ebersole * @author Hardy Ferentschik */ +@Deprecated public class DTDEntityResolver implements EntityResolver, Serializable { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, DTDEntityResolver.class.getName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/ErrorLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/ErrorLogger.java index 36ba790691..3f0ee6ea9a 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/ErrorLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/ErrorLogger.java @@ -41,6 +41,7 @@ * @author Steve Ebersole * @author Hardy Ferentschik */ +@Deprecated public class ErrorLogger implements ErrorHandler, Serializable { private static final CoreMessageLogger LOG = Logger.getMessageLogger( diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/MappingReader.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/MappingReader.java deleted file mode 100644 index edd5d6b3e0..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/MappingReader.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as - * indicated by the @author tags or express copyright attribution - * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Inc. - * - * This copyrighted material is made available to anyone wishing to use, modify, - * copy, or redistribute it subject to the terms and conditions of the GNU - * Lesser General Public License, as published by the Free Software Foundation. - * - * This program 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this distribution; if not, write to: - * Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301 USA - */ -package org.hibernate.internal.util.xml; - -import java.io.IOException; -import java.io.StringReader; -import javax.xml.namespace.QName; -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamConstants; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.Attribute; -import javax.xml.stream.events.XMLEvent; -import javax.xml.transform.stax.StAXSource; -import javax.xml.validation.Validator; - -import org.hibernate.InvalidMappingException; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.xml.internal.stax.BufferedXMLEventReader; -import org.hibernate.xml.internal.stax.FilteringXMLEventReader; -import org.hibernate.xml.internal.stax.LocalXmlResourceResolver; -import org.hibernate.xml.internal.stax.SupportedOrmXsdVersion; -import org.hibernate.xml.internal.stax.XmlInfrastructureException; - -import org.jboss.logging.Logger; - -import org.dom4j.Document; -import org.dom4j.io.SAXReader; -import org.dom4j.io.STAXEventReader; -import org.xml.sax.EntityResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * Handles reading mapping documents, both {@code hbm} and {@code orm} varieties. - * - * @author Steve Ebersole - */ -public class MappingReader { - private static final CoreMessageLogger LOG = Logger.getMessageLogger( - CoreMessageLogger.class, - MappingReader.class.getName() - ); - - public static final MappingReader INSTANCE = new MappingReader(); - - /** - * Disallow direct instantiation. - *

- * Eventually we perhaps need to have this configurable by the "configuration" and simply reference it - * from there (registry). This would allow, for example, injection of the entity resolver to use as - * instance state. - */ - private MappingReader() { - } - - public XmlDocument readMappingDocument(InputSource source, Origin origin) { - XMLEventReader staxReader = buildStaxEventReader( source, origin ); - try { - return read( staxReader, origin ); - } - finally { - try { - staxReader.close(); - } - catch ( Exception ignore ) { - } - } - } - - private XMLEventReader buildStaxEventReader(InputSource source, Origin origin) { - XMLEventReader reader = null; - - if ( source.getByteStream() != null ) { - try { - reader = staxFactory().createXMLEventReader( source.getByteStream() ); - } - catch (XMLStreamException e) { - throw new XmlInfrastructureException( - "Unable to create stax reader, origin = " + toLoggableString( origin ), - e - ); - } - } - else if ( source.getCharacterStream() != null ) { - try { - reader = staxFactory().createXMLEventReader( source.getCharacterStream() ); - } - catch (XMLStreamException e) { - throw new XmlInfrastructureException( - "Unable to create stax reader, origin = " + toLoggableString( origin ), - e - ); - } - } - // todo : try to interpret the InputSource SystemId or Origin path? - - if ( reader == null ) { - throw new XmlInfrastructureException( "Unable to convert SAX InputStream into StAX XMLEventReader" ); - } - - // For performance we wrap the reader in a buffered reader - return new BufferedXMLEventReader( reader ); - } - - private XMLInputFactory staxFactory; - - private XMLInputFactory staxFactory() { - if ( staxFactory == null ) { - staxFactory = buildStaxFactory(); - } - return staxFactory; - } - - @SuppressWarnings( { "UnnecessaryLocalVariable" }) - private XMLInputFactory buildStaxFactory() { - XMLInputFactory staxFactory = XMLInputFactory.newInstance(); - staxFactory.setXMLResolver( LocalXmlResourceResolver.INSTANCE ); - return staxFactory; - } - - private String toLoggableString(Origin origin) { - return "[type=" + origin.getType() + ", name=" + origin.getName() + "]"; - } - - private static final QName ORM_VERSION_ATTRIBUTE_QNAME = new QName( "version" ); - - private XmlDocument read(XMLEventReader staxEventReader, Origin origin) { - XMLEvent event; - try { - event = staxEventReader.peek(); - while ( event != null && !event.isStartElement() ) { - staxEventReader.nextEvent(); - event = staxEventReader.peek(); - } - } - catch ( Exception e ) { - throw new InvalidMappingException( "Error accessing stax stream", origin, e ); - } - - if ( event == null ) { - throw new InvalidMappingException( "Could not locate root element", origin ); - } - - final String rootElementName = event.asStartElement().getName().getLocalPart(); - - if ( "entity-mappings".equals( rootElementName ) ) { - final Attribute attribute = event.asStartElement().getAttributeByName( ORM_VERSION_ATTRIBUTE_QNAME ); - final String explicitVersion = attribute == null ? null : attribute.getValue(); - validateMapping( - SupportedOrmXsdVersion.parse( explicitVersion, origin ), - staxEventReader, - origin - ); - } - - return new XmlDocumentImpl( toDom4jDocument( staxEventReader, origin ), origin ); - } - - private Document toDom4jDocument(XMLEventReader staxEventReader, Origin origin) { - STAXEventReader dom4jStaxEventReader = new STAXEventReader(); - try { - // the dom4j converter class is touchy about comments (aka, comments make it implode) - // so wrap the event stream in a filtering stream to filter out comment events - staxEventReader = new FilteringXMLEventReader( staxEventReader ) { - @Override - protected XMLEvent filterEvent(XMLEvent event, boolean peek) { - return event.getEventType() == XMLStreamConstants.COMMENT - ? null - : event; - } - }; - - return dom4jStaxEventReader.readDocument( staxEventReader ); - } - catch (XMLStreamException e) { - throw new InvalidMappingException( "Unable to read StAX source as dom4j Document for processing", origin, e ); - } - } - - private void validateMapping(SupportedOrmXsdVersion xsdVersion, XMLEventReader staxEventReader, Origin origin) { - final Validator validator = xsdVersion.getSchema().newValidator(); - final StAXSource staxSource; - try { - staxSource = new StAXSource( staxEventReader ); - } - catch (XMLStreamException e) { - throw new InvalidMappingException( "Unable to generate StAXSource from mapping", origin, e ); - } - - try { - validator.validate( staxSource ); - } - catch (SAXException e) { - throw new InvalidMappingException( "SAXException performing validation", origin, e ); - } - catch (IOException e) { - throw new InvalidMappingException( "IOException performing validation", origin, e ); - } - } - - - public XmlDocument readMappingDocument(EntityResolver entityResolver, InputSource source, Origin origin) { - return legacyReadMappingDocument( entityResolver, source, origin ); -// return readMappingDocument( source, origin ); - } - - private XmlDocument legacyReadMappingDocument(EntityResolver entityResolver, InputSource source, Origin origin) { - // IMPL NOTE : this is the legacy logic as pulled from the old AnnotationConfiguration code - - Exception failure; - - ErrorLogger errorHandler = new ErrorLogger(); - - SAXReader saxReader = new SAXReader(); - saxReader.setEntityResolver( entityResolver ); - saxReader.setErrorHandler( errorHandler ); - saxReader.setMergeAdjacentText( true ); - saxReader.setValidation( true ); - - Document document = null; - try { - // first try with orm 2.1 xsd validation - setValidationFor( saxReader, "orm_2_1.xsd" ); - document = saxReader.read( source ); - if ( errorHandler.hasErrors() ) { - throw errorHandler.getErrors().get( 0 ); - } - return new XmlDocumentImpl( document, origin ); - } - catch ( Exception e ) { - if ( LOG.isDebugEnabled() ) { - LOG.debugf( "Problem parsing XML using orm 2.1 xsd, trying 2.0 xsd : %s", e.getMessage() ); - } - failure = e; - errorHandler.reset(); - - if ( document != null ) { - // next try with orm 2.0 xsd validation - try { - setValidationFor( saxReader, "orm_2_0.xsd" ); - document = saxReader.read( new StringReader( document.asXML() ) ); - if ( errorHandler.hasErrors() ) { - errorHandler.logErrors(); - throw errorHandler.getErrors().get( 0 ); - } - return new XmlDocumentImpl( document, origin ); - } - catch ( Exception e2 ) { - if ( LOG.isDebugEnabled() ) { - LOG.debugf( "Problem parsing XML using orm 2.0 xsd, trying 1.0 xsd : %s", e2.getMessage() ); - } - errorHandler.reset(); - - if ( document != null ) { - // next try with orm 1.0 xsd validation - try { - setValidationFor( saxReader, "orm_1_0.xsd" ); - document = saxReader.read( new StringReader( document.asXML() ) ); - if ( errorHandler.hasErrors() ) { - errorHandler.logErrors(); - throw errorHandler.getErrors().get( 0 ); - } - return new XmlDocumentImpl( document, origin ); - } - catch ( Exception e3 ) { - if ( LOG.isDebugEnabled() ) { - LOG.debugf( "Problem parsing XML using orm 1.0 xsd : %s", e3.getMessage() ); - } - } - } - } - } - } - throw new InvalidMappingException( "Unable to read XML", origin.getType(), origin.getName(), failure ); - } - - private void setValidationFor(SAXReader saxReader, String xsd) { - try { - saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true ); - // saxReader.setFeature( "http://apache.org/xml/features/validation/dynamic", true ); - if ( "orm_2_1.xsd".equals( xsd ) ) { - saxReader.setProperty( - "http://apache.org/xml/properties/schema/external-schemaLocation", - LocalXmlResourceResolver.SECOND_JPA_ORM_NS + " " + xsd - ); - } - else { - saxReader.setProperty( - "http://apache.org/xml/properties/schema/external-schemaLocation", - LocalXmlResourceResolver.INITIAL_JPA_ORM_NS + " " + xsd - ); - } - } - catch ( SAXException e ) { - saxReader.setValidation( false ); - } - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/Origin.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/Origin.java index 805cdd8168..b2ed1a702d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/Origin.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/Origin.java @@ -30,9 +30,10 @@ * * @author Steve Ebersole */ +@Deprecated public interface Origin extends Serializable { /** - * Retrieve the type of origin. This is not a discrete set, but might be somethign like + * Retrieve the type of origin. This is not a discrete set, but might be something like * {@code file} for file protocol URLs, or {@code resource} for classpath resource lookups. * * @return The origin type. diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/OriginImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/OriginImpl.java index 5bd66025cd..6a6b739f6c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/OriginImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/OriginImpl.java @@ -30,6 +30,7 @@ * * @author Steve Ebersole */ +@Deprecated public class OriginImpl implements Origin, Serializable { private final String type; private final String name; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XMLHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XMLHelper.java index 6708dfd63a..8d2dab7e19 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XMLHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XMLHelper.java @@ -37,6 +37,7 @@ /** * Small helper class that lazy loads DOM and SAX reader and keep them for fast use afterwards. */ +@Deprecated public final class XMLHelper { public static final EntityResolver DEFAULT_DTD_RESOLVER = new DTDEntityResolver(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocument.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocument.java index 0822a9f6aa..6e6f3ee8d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocument.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocument.java @@ -32,6 +32,7 @@ * * @author Steve Ebersole */ +@Deprecated public interface XmlDocument extends Serializable { /** * Retrieve the parsed DOM tree. diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocumentImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocumentImpl.java index aac9763100..33caa55600 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocumentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/xml/XmlDocumentImpl.java @@ -28,10 +28,11 @@ import org.dom4j.Document; /** - * Basic implemementation of {@link XmlDocument} + * Basic implementation of {@link XmlDocument} * * @author Steve Ebersole */ +@Deprecated public class XmlDocumentImpl implements XmlDocument, Serializable { private final Document documentTree; private final Origin origin; @@ -40,6 +41,7 @@ public XmlDocumentImpl(Document documentTree, String originType, String originNa this( documentTree, new OriginImpl( originType, originName ) ); } + public XmlDocumentImpl(Document documentTree, Origin origin) { this.documentTree = documentTree; this.origin = origin; diff --git a/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/AbstractXmlBinder.java b/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/AbstractXmlBinder.java index fe015079bd..e1552c0aba 100644 --- a/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/AbstractXmlBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/AbstractXmlBinder.java @@ -27,9 +27,6 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; -import javax.xml.bind.ValidationEvent; -import javax.xml.bind.ValidationEventHandler; -import javax.xml.bind.ValidationEventLocator; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; @@ -48,6 +45,15 @@ import org.hibernate.xml.spi.XmlBinder; /** + * Base implementation (template) of the XmlBinder contract. + *

+ * Generally implementors should just have to implement:

    + *
  1. {@link #getJaxbContext}
  2. + *
  3. {@link #getSchema}
  4. + *
  5. (optionally) {@link #wrapReader}
  6. + *
+ * + * @author Steve Ebersole * @author Strong Liu */ abstract class AbstractXmlBinder implements XmlBinder { @@ -123,12 +129,14 @@ private BindResult unmarshal(XMLEventReader staxEventReader, final Origin origin final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler(); try { - Schema schema = getSchema(event, origin); + final Schema schema = getSchema( event, origin ); staxEventReader = wrapReader( staxEventReader, event ); - JAXBContext jaxbContext =getJaxbContext(event); - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + + final JAXBContext jaxbContext = getJaxbContext( event ); + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); unmarshaller.setSchema( schema ); unmarshaller.setEventHandler( handler ); + final Object target = unmarshaller.unmarshal( staxEventReader ); return new BindResult( target, origin ); } @@ -136,44 +144,50 @@ private BindResult unmarshal(XMLEventReader staxEventReader, final Origin origin throw new MappingException( "Unable to perform unmarshalling at line number " + handler.getLineNumber() + " and column " + handler.getColumnNumber() - + ". Message: " + handler.getMessage(), e, origin + + ". Message: " + handler.getMessage(), + e, + origin ); } } - protected abstract JAXBContext getJaxbContext(XMLEvent event) throws JAXBException; - protected abstract Schema getSchema(XMLEvent event, Origin origin) throws JAXBException; - protected XMLEventReader wrapReader(XMLEventReader xmlEventReader, XMLEvent event){ + + /** + * Identify the Schema to use to validate the document being processed. + * + * @param rootElementStartEvent The peeked event that represents the start of the root element of the document + * @param origin + * + * @return + * + * @throws JAXBException + */ + protected abstract Schema getSchema(XMLEvent rootElementStartEvent, Origin origin) throws JAXBException; + + /** + * Wrap the given StAX event reader in another if needed. + * + * @param xmlEventReader The "real" reader. + * @param rootElementStartEvent The peeked event that represents the start of the root element of the document + * + * @return The wrapped reader. Simply return the given reader if no wrapping is needed. + */ + protected XMLEventReader wrapReader(XMLEventReader xmlEventReader, XMLEvent rootElementStartEvent) { return xmlEventReader; } + + /** + * Get the JAXB context representing the Java model to bind to. + * + * @param event + * + * @return + * + * @throws JAXBException + */ + protected abstract JAXBContext getJaxbContext(XMLEvent event) throws JAXBException; + protected static boolean isNamespaced(StartElement startElement) { return ! "".equals( startElement.getName().getNamespaceURI() ); } - - static class ContextProvidingValidationEventHandler implements ValidationEventHandler { - private int lineNumber; - private int columnNumber; - private String message; - - @Override - public boolean handleEvent(ValidationEvent validationEvent) { - ValidationEventLocator locator = validationEvent.getLocator(); - lineNumber = locator.getLineNumber(); - columnNumber = locator.getColumnNumber(); - message = validationEvent.getMessage(); - return false; - } - - public int getLineNumber() { - return lineNumber; - } - - public int getColumnNumber() { - return columnNumber; - } - - public String getMessage() { - return message; - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/ContextProvidingValidationEventHandler.java b/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/ContextProvidingValidationEventHandler.java new file mode 100644 index 0000000000..96f5eceb54 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/ContextProvidingValidationEventHandler.java @@ -0,0 +1,60 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2014, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.xml.internal.jaxb; + +import javax.xml.bind.ValidationEvent; +import javax.xml.bind.ValidationEventHandler; +import javax.xml.bind.ValidationEventLocator; + +/** + * ValidationEventHandler implementation providing easier access to where (line/column) an error occurred. + * + * @author Steve Ebersole + */ +class ContextProvidingValidationEventHandler implements ValidationEventHandler { + private int lineNumber; + private int columnNumber; + private String message; + + @Override + public boolean handleEvent(ValidationEvent validationEvent) { + ValidationEventLocator locator = validationEvent.getLocator(); + lineNumber = locator.getLineNumber(); + columnNumber = locator.getColumnNumber(); + message = validationEvent.getMessage(); + return false; + } + + public int getLineNumber() { + return lineNumber; + } + + public int getColumnNumber() { + return columnNumber; + } + + public String getMessage() { + return message; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/MappingXmlBinder.java b/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/MappingXmlBinder.java index 36fce41106..db975a09ba 100644 --- a/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/MappingXmlBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/xml/internal/jaxb/MappingXmlBinder.java @@ -38,7 +38,6 @@ import org.w3c.dom.Element; import org.hibernate.internal.util.StringHelper; import org.hibernate.xml.internal.stax.LocalXmlResourceResolver; -import org.hibernate.internal.util.xml.OriginImpl; import org.hibernate.xml.internal.stax.SupportedOrmXsdVersion; import org.hibernate.xml.spi.BindResult; import org.hibernate.xml.spi.Origin; @@ -65,6 +64,12 @@ public MappingXmlBinder(ServiceRegistry serviceRegistry, boolean validateXml) { super(serviceRegistry, validateXml); } + // todo : DO THIS! + // the goal here ultimately is to: + // 1) use one "combined" XSD for both orm.xml and hbm.xml features (HHH-8893) + // 2) always always always validate against the latest version of that XSD (HHH-8894) + // 3) profit! + @Override protected JAXBContext getJaxbContext(XMLEvent event) throws JAXBException { final String elementName = event.asStartElement().getName().getLocalPart(); @@ -157,7 +162,6 @@ public BindResult unmarshal(Document document, Origin origin) { } private Schema resolveSupportedOrmXsd(String explicitVersion, Origin origin) { - if ( StringHelper.isEmpty( explicitVersion ) ) { return SupportedOrmXsdVersion.ORM_2_1.getSchema(); } @@ -171,13 +175,8 @@ private Schema resolveSupportedOrmXsd(String explicitVersion, Origin origin) { // // However, still check for the validity of the version by calling #parse. If someone explicitly uses a value // that doesn't exist, we still need to throw the exception. - @SuppressWarnings("unused") - SupportedOrmXsdVersion version = - SupportedOrmXsdVersion.parse( - explicitVersion, - new OriginImpl( origin.getType().name(), origin.getName() ) - ); - // return version.getSchema(); + SupportedOrmXsdVersion.parse( explicitVersion, origin ); + return SupportedOrmXsdVersion.ORM_2_1.getSchema(); } diff --git a/hibernate-core/src/main/java/org/hibernate/xml/internal/stax/SupportedOrmXsdVersion.java b/hibernate-core/src/main/java/org/hibernate/xml/internal/stax/SupportedOrmXsdVersion.java index e27697b6c0..3c90f8c104 100644 --- a/hibernate-core/src/main/java/org/hibernate/xml/internal/stax/SupportedOrmXsdVersion.java +++ b/hibernate-core/src/main/java/org/hibernate/xml/internal/stax/SupportedOrmXsdVersion.java @@ -26,11 +26,11 @@ import java.net.URL; import javax.xml.validation.Schema; -import org.hibernate.internal.util.xml.Origin; +import org.hibernate.xml.spi.Origin; /** -* @author Steve Ebersole -*/ + * @author Steve Ebersole + */ public enum SupportedOrmXsdVersion { ORM_1_0( "org/hibernate/jpa/orm_1_0.xsd" ), ORM_2_0( "org/hibernate/jpa/orm_2_0.xsd" ), diff --git a/hibernate-core/src/main/java/org/hibernate/xml/internal/stax/UnsupportedOrmXsdVersionException.java b/hibernate-core/src/main/java/org/hibernate/xml/internal/stax/UnsupportedOrmXsdVersionException.java index ebabeda04e..e3d7e4a33d 100644 --- a/hibernate-core/src/main/java/org/hibernate/xml/internal/stax/UnsupportedOrmXsdVersionException.java +++ b/hibernate-core/src/main/java/org/hibernate/xml/internal/stax/UnsupportedOrmXsdVersionException.java @@ -24,7 +24,7 @@ package org.hibernate.xml.internal.stax; import org.hibernate.HibernateException; -import org.hibernate.internal.util.xml.Origin; +import org.hibernate.xml.spi.Origin; /** * @author Steve Ebersole diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/jee/OrmVersionTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/jee/OrmVersionTest.java index d7314c7a1c..474ed0c762 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/jee/OrmVersionTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/jee/OrmVersionTest.java @@ -45,12 +45,14 @@ import org.hibernate.jpa.test.pack.defaultpar.Lighter; import org.hibernate.jpa.test.pack.defaultpar_1_0.Lighter1; +import org.hibernate.testing.junit4.BaseUnitTestCase; + /** * "smoke" tests for JEE bootstrapping of HEM via a {@link PersistenceUnitInfo} * * @author Steve Ebersole */ -public class OrmVersionTest { +public class OrmVersionTest extends BaseUnitTestCase { @Test public void testOrm1() { PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm1-test", "1.0" ) @@ -58,7 +60,9 @@ public void testOrm1() { HibernatePersistenceProvider hp = new HibernatePersistenceProvider(); EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP ); emf.getMetamodel().entity( Lighter1.class ); // exception if not entity + emf.close(); } + @Test public void testOrm2() { PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm2-test", "2.0" ) @@ -66,7 +70,9 @@ public void testOrm2() { HibernatePersistenceProvider hp = new HibernatePersistenceProvider(); EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP ); emf.getMetamodel().entity( Lighter.class ); // exception if not entity + emf.close(); } + @Test public void testInvalidOrm1() { PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "invalid-orm1-test", "1.0" )