HHH-8894 - Use an "upgrade" approach to validate and bind (JAXB) mapping XML
This commit is contained in:
parent
599c843eed
commit
7fdf40c693
|
@ -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 class InvalidMappingException extends MappingException {
|
|||
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 class InvalidMappingException extends MappingException {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -381,6 +381,7 @@ public class Configuration {
|
|||
@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
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.xml.sax.InputSource;
|
|||
* @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() );
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.xml.sax.SAXParseException;
|
|||
* @author Steve Ebersole
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
@Deprecated
|
||||
public class ErrorLogger implements ErrorHandler, Serializable {
|
||||
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -30,9 +30,10 @@ import java.io.Serializable;
|
|||
*
|
||||
* @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.
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.io.Serializable;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Deprecated
|
||||
public class OriginImpl implements Origin, Serializable {
|
||||
private final String type;
|
||||
private final String name;
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.xml.sax.ErrorHandler;
|
|||
/**
|
||||
* 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();
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.dom4j.Document;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Deprecated
|
||||
public interface XmlDocument extends Serializable {
|
||||
/**
|
||||
* Retrieve the parsed DOM tree.
|
||||
|
|
|
@ -28,10 +28,11 @@ import java.io.Serializable;
|
|||
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 class XmlDocumentImpl implements XmlDocument, Serializable {
|
|||
this( documentTree, new OriginImpl( originType, originName ) );
|
||||
}
|
||||
|
||||
|
||||
public XmlDocumentImpl(Document documentTree, Origin origin) {
|
||||
this.documentTree = documentTree;
|
||||
this.origin = origin;
|
||||
|
|
|
@ -27,9 +27,6 @@ import java.io.InputStream;
|
|||
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.service.ServiceRegistry;
|
|||
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>
|
||||
*/
|
||||
abstract class AbstractXmlBinder implements XmlBinder {
|
||||
|
@ -123,12 +129,14 @@ abstract class AbstractXmlBinder implements XmlBinder {
|
|||
|
||||
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 @@ abstract class AbstractXmlBinder implements XmlBinder {
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -38,7 +38,6 @@ import org.w3c.dom.Document;
|
|||
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 class MappingXmlBinder extends AbstractXmlBinder {
|
|||
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 class MappingXmlBinder extends AbstractXmlBinder {
|
|||
}
|
||||
|
||||
private Schema resolveSupportedOrmXsd(String explicitVersion, Origin origin) {
|
||||
|
||||
if ( StringHelper.isEmpty( explicitVersion ) ) {
|
||||
return SupportedOrmXsdVersion.ORM_2_1.getSchema();
|
||||
}
|
||||
|
@ -171,13 +175,8 @@ public class MappingXmlBinder extends AbstractXmlBinder {
|
|||
//
|
||||
// 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();
|
||||
|
||||
}
|
||||
|
|
|
@ -26,11 +26,11 @@ package org.hibernate.xml.internal.stax;
|
|||
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" ),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -45,12 +45,14 @@ import org.hibernate.jpa.HibernatePersistenceProvider;
|
|||
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 class OrmVersionTest {
|
|||
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 class OrmVersionTest {
|
|||
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" )
|
||||
|
|
Loading…
Reference in New Issue