HHH-8894 - Use an "upgrade" approach to validate and bind (JAXB) mapping XML

This commit is contained in:
Steve Ebersole 2014-02-05 09:09:03 -06:00
parent 599c843eed
commit 7fdf40c693
16 changed files with 141 additions and 438 deletions

View File

@ -24,7 +24,6 @@
package org.hibernate; package org.hibernate;
import org.hibernate.xml.spi.Origin; import org.hibernate.xml.spi.Origin;
import org.hibernate.internal.util.xml.XmlDocument;
/** /**
* Thrown when a mapping is found to be invalid. * Thrown when a mapping is found to be invalid.
@ -66,27 +65,6 @@ public InvalidMappingException(String customMessage, String type, String path) {
this.path=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. * Constructs an InvalidMappingException using the given information.
* *
@ -97,48 +75,6 @@ public InvalidMappingException(String customMessage, Origin origin) {
this( customMessage, origin.getType().toString(), origin.getName() ); 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() { public String getType() {
return type; return type;
} }

View File

@ -381,6 +381,7 @@ public Configuration addFile(File xmlFile) throws MappingException {
@Deprecated @Deprecated
public void add(XmlDocument metadataXml) { public void add(XmlDocument metadataXml) {
} }
/** /**
* Add a cached mapping file. A cached file is a serialized representation * 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 * of the DOM structure of a particular mapping. It is saved from a previous

View File

@ -55,6 +55,7 @@
* @author Steve Ebersole * @author Steve Ebersole
* @author Hardy Ferentschik * @author Hardy Ferentschik
*/ */
@Deprecated
public class DTDEntityResolver implements EntityResolver, Serializable { public class DTDEntityResolver implements EntityResolver, Serializable {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, DTDEntityResolver.class.getName() ); private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, DTDEntityResolver.class.getName() );

View File

@ -41,6 +41,7 @@
* @author Steve Ebersole * @author Steve Ebersole
* @author Hardy Ferentschik * @author Hardy Ferentschik
*/ */
@Deprecated
public class ErrorLogger implements ErrorHandler, Serializable { public class ErrorLogger implements ErrorHandler, Serializable {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( private static final CoreMessageLogger LOG = Logger.getMessageLogger(

View File

@ -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.
* <p/>
* 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 );
}
}
}

View File

@ -30,9 +30,10 @@
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@Deprecated
public interface Origin extends Serializable { 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. * {@code file} for file protocol URLs, or {@code resource} for classpath resource lookups.
* *
* @return The origin type. * @return The origin type.

View File

@ -30,6 +30,7 @@
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@Deprecated
public class OriginImpl implements Origin, Serializable { public class OriginImpl implements Origin, Serializable {
private final String type; private final String type;
private final String name; private final String name;

View File

@ -37,6 +37,7 @@
/** /**
* Small helper class that lazy loads DOM and SAX reader and keep them for fast use afterwards. * Small helper class that lazy loads DOM and SAX reader and keep them for fast use afterwards.
*/ */
@Deprecated
public final class XMLHelper { public final class XMLHelper {
public static final EntityResolver DEFAULT_DTD_RESOLVER = new DTDEntityResolver(); public static final EntityResolver DEFAULT_DTD_RESOLVER = new DTDEntityResolver();

View File

@ -32,6 +32,7 @@
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@Deprecated
public interface XmlDocument extends Serializable { public interface XmlDocument extends Serializable {
/** /**
* Retrieve the parsed DOM tree. * Retrieve the parsed DOM tree.

View File

@ -28,10 +28,11 @@
import org.dom4j.Document; import org.dom4j.Document;
/** /**
* Basic implemementation of {@link XmlDocument} * Basic implementation of {@link XmlDocument}
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@Deprecated
public class XmlDocumentImpl implements XmlDocument, Serializable { public class XmlDocumentImpl implements XmlDocument, Serializable {
private final Document documentTree; private final Document documentTree;
private final Origin origin; private final Origin origin;
@ -40,6 +41,7 @@ public XmlDocumentImpl(Document documentTree, String originType, String originNa
this( documentTree, new OriginImpl( originType, originName ) ); this( documentTree, new OriginImpl( originType, originName ) );
} }
public XmlDocumentImpl(Document documentTree, Origin origin) { public XmlDocumentImpl(Document documentTree, Origin origin) {
this.documentTree = documentTree; this.documentTree = documentTree;
this.origin = origin; this.origin = origin;

View File

@ -27,9 +27,6 @@
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException; import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller; 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.XMLEventReader;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
@ -48,6 +45,15 @@
import org.hibernate.xml.spi.XmlBinder; import org.hibernate.xml.spi.XmlBinder;
/** /**
* Base implementation (template) of the XmlBinder contract.
* <p/>
* Generally implementors should just have to implement:<ol>
* <li>{@link #getJaxbContext}</li>
* <li>{@link #getSchema}</li>
* <li>(optionally) {@link #wrapReader}</li>
* </ol>
*
* @author Steve Ebersole
* @author Strong Liu <stliu@hibernate.org> * @author Strong Liu <stliu@hibernate.org>
*/ */
abstract class AbstractXmlBinder implements XmlBinder { abstract class AbstractXmlBinder implements XmlBinder {
@ -123,12 +129,14 @@ private BindResult unmarshal(XMLEventReader staxEventReader, final Origin origin
final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler(); final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler();
try { try {
Schema schema = getSchema(event, origin); final Schema schema = getSchema( event, origin );
staxEventReader = wrapReader( staxEventReader, event ); 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.setSchema( schema );
unmarshaller.setEventHandler( handler ); unmarshaller.setEventHandler( handler );
final Object target = unmarshaller.unmarshal( staxEventReader ); final Object target = unmarshaller.unmarshal( staxEventReader );
return new BindResult( target, origin ); return new BindResult( target, origin );
} }
@ -136,44 +144,50 @@ private BindResult unmarshal(XMLEventReader staxEventReader, final Origin origin
throw new MappingException( throw new MappingException(
"Unable to perform unmarshalling at line number " + handler.getLineNumber() "Unable to perform unmarshalling at line number " + handler.getLineNumber()
+ " and column " + handler.getColumnNumber() + " 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; 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) { protected static boolean isNamespaced(StartElement startElement) {
return ! "".equals( startElement.getName().getNamespaceURI() ); 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;
}
}
} }

View File

@ -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;
}
}

View File

@ -38,7 +38,6 @@
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.xml.internal.stax.LocalXmlResourceResolver; 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.internal.stax.SupportedOrmXsdVersion;
import org.hibernate.xml.spi.BindResult; import org.hibernate.xml.spi.BindResult;
import org.hibernate.xml.spi.Origin; import org.hibernate.xml.spi.Origin;
@ -65,6 +64,12 @@ public MappingXmlBinder(ServiceRegistry serviceRegistry, boolean validateXml) {
super(serviceRegistry, 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 @Override
protected JAXBContext getJaxbContext(XMLEvent event) throws JAXBException { protected JAXBContext getJaxbContext(XMLEvent event) throws JAXBException {
final String elementName = event.asStartElement().getName().getLocalPart(); 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) { private Schema resolveSupportedOrmXsd(String explicitVersion, Origin origin) {
if ( StringHelper.isEmpty( explicitVersion ) ) { if ( StringHelper.isEmpty( explicitVersion ) ) {
return SupportedOrmXsdVersion.ORM_2_1.getSchema(); 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 // 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. // that doesn't exist, we still need to throw the exception.
@SuppressWarnings("unused") SupportedOrmXsdVersion.parse( explicitVersion, origin );
SupportedOrmXsdVersion version =
SupportedOrmXsdVersion.parse(
explicitVersion,
new OriginImpl( origin.getType().name(), origin.getName() )
);
// return version.getSchema();
return SupportedOrmXsdVersion.ORM_2_1.getSchema(); return SupportedOrmXsdVersion.ORM_2_1.getSchema();
} }

View File

@ -26,11 +26,11 @@
import java.net.URL; import java.net.URL;
import javax.xml.validation.Schema; 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 { public enum SupportedOrmXsdVersion {
ORM_1_0( "org/hibernate/jpa/orm_1_0.xsd" ), ORM_1_0( "org/hibernate/jpa/orm_1_0.xsd" ),
ORM_2_0( "org/hibernate/jpa/orm_2_0.xsd" ), ORM_2_0( "org/hibernate/jpa/orm_2_0.xsd" ),

View File

@ -24,7 +24,7 @@
package org.hibernate.xml.internal.stax; package org.hibernate.xml.internal.stax;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.internal.util.xml.Origin; import org.hibernate.xml.spi.Origin;
/** /**
* @author Steve Ebersole * @author Steve Ebersole

View File

@ -45,12 +45,14 @@
import org.hibernate.jpa.test.pack.defaultpar.Lighter; import org.hibernate.jpa.test.pack.defaultpar.Lighter;
import org.hibernate.jpa.test.pack.defaultpar_1_0.Lighter1; 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} * "smoke" tests for JEE bootstrapping of HEM via a {@link PersistenceUnitInfo}
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class OrmVersionTest { public class OrmVersionTest extends BaseUnitTestCase {
@Test @Test
public void testOrm1() { public void testOrm1() {
PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm1-test", "1.0" ) PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm1-test", "1.0" )
@ -58,7 +60,9 @@ public void testOrm1() {
HibernatePersistenceProvider hp = new HibernatePersistenceProvider(); HibernatePersistenceProvider hp = new HibernatePersistenceProvider();
EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP ); EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP );
emf.getMetamodel().entity( Lighter1.class ); // exception if not entity emf.getMetamodel().entity( Lighter1.class ); // exception if not entity
emf.close();
} }
@Test @Test
public void testOrm2() { public void testOrm2() {
PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm2-test", "2.0" ) PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm2-test", "2.0" )
@ -66,7 +70,9 @@ public void testOrm2() {
HibernatePersistenceProvider hp = new HibernatePersistenceProvider(); HibernatePersistenceProvider hp = new HibernatePersistenceProvider();
EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP ); EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP );
emf.getMetamodel().entity( Lighter.class ); // exception if not entity emf.getMetamodel().entity( Lighter.class ); // exception if not entity
emf.close();
} }
@Test @Test
public void testInvalidOrm1() { public void testInvalidOrm1() {
PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "invalid-orm1-test", "1.0" ) PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "invalid-orm1-test", "1.0" )