HHH-4667 accept orm 2 and orm 1 files. Also improved error reports
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18263 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
cab9873205
commit
a87e031bd5
|
@ -26,6 +26,7 @@ package org.hibernate.cfg;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -54,6 +55,8 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.DuplicateMappingException;
|
||||
|
@ -67,6 +70,7 @@ import org.hibernate.annotations.common.reflection.MetadataProviderInjector;
|
|||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
import org.hibernate.cfg.annotations.Version;
|
||||
import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider;
|
||||
import org.hibernate.cfg.beanvalidation.BeanValidationActivator;
|
||||
|
@ -839,32 +843,76 @@ public class AnnotationConfiguration extends Configuration {
|
|||
@Override
|
||||
public AnnotationConfiguration addInputStream(InputStream xmlInputStream) throws MappingException {
|
||||
try {
|
||||
List errors = new ArrayList();
|
||||
SAXReader saxReader = xmlHelper.createSAXReader( "XML InputStream", errors, getEntityResolver() );
|
||||
try {
|
||||
saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true );
|
||||
//saxReader.setFeature( "http://apache.org/xml/features/validation/dynamic", true );
|
||||
//set the default schema locators
|
||||
saxReader.setProperty(
|
||||
"http://apache.org/xml/properties/schema/external-schemaLocation",
|
||||
"http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
|
||||
);
|
||||
}
|
||||
catch ( SAXException e ) {
|
||||
saxReader.setValidation( false );
|
||||
}
|
||||
org.dom4j.Document doc = saxReader
|
||||
.read( new InputSource( xmlInputStream ) );
|
||||
/*
|
||||
* try and parse the document:
|
||||
* - try and validate the document with orm_2_0.xsd
|
||||
* - if it fails because of the version attribute mismatch, try and validate the document with orm_1_0.xsd
|
||||
*/
|
||||
List<SAXParseException> errors = new ArrayList<SAXParseException>();
|
||||
SAXReader saxReader = new SAXReader( );
|
||||
saxReader.setEntityResolver( getEntityResolver() );
|
||||
saxReader.setErrorHandler( new ErrorLogger(errors) );
|
||||
saxReader.setMergeAdjacentText(true);
|
||||
saxReader.setValidation(true);
|
||||
|
||||
setValidationFor( saxReader, "orm_2_0.xsd" );
|
||||
|
||||
org.dom4j.Document doc = null;
|
||||
try {
|
||||
doc = saxReader.read( new InputSource( xmlInputStream ) );
|
||||
}
|
||||
catch ( DocumentException e ) {
|
||||
//the document is syntactically incorrect
|
||||
|
||||
//DOM4J sometimes wraps the SAXParseException wo much interest
|
||||
final Throwable throwable = e.getCause();
|
||||
if ( e.getCause() == null || !( throwable instanceof SAXParseException ) ) {
|
||||
throw new MappingException( "Could not parse JPA mapping document", e );
|
||||
}
|
||||
errors.add( (SAXParseException) throwable );
|
||||
}
|
||||
|
||||
boolean isV1Schema = false;
|
||||
if ( errors.size() != 0 ) {
|
||||
throw new MappingException( "invalid mapping", ( Throwable ) errors.get( 0 ) );
|
||||
SAXParseException exception = errors.get( 0 );
|
||||
final String errorMessage = exception.getMessage();
|
||||
//does the error look like a schema mismatch?
|
||||
isV1Schema = doc != null
|
||||
&& errorMessage.contains("1.0")
|
||||
&& errorMessage.contains("2.0")
|
||||
&& errorMessage.contains("version");
|
||||
}
|
||||
if (isV1Schema) {
|
||||
//reparse with v1
|
||||
errors.clear();
|
||||
setValidationFor( saxReader, "orm_1_0.xsd" );
|
||||
try {
|
||||
//too bad we have to reparse to validate again :(
|
||||
saxReader.read( new StringReader( doc.asXML() ) );
|
||||
}
|
||||
catch ( DocumentException e ) {
|
||||
//oops asXML fails even if the core doc parses initially
|
||||
new AssertionFailure("Error in DOM4J leads to a bug in Hibernate", e);
|
||||
}
|
||||
|
||||
}
|
||||
if ( errors.size() != 0 ) {
|
||||
//report errors in exception
|
||||
StringBuilder errorMessage = new StringBuilder( );
|
||||
for (SAXParseException error : errors) {
|
||||
errorMessage.append("Error parsing XML (line")
|
||||
.append(error.getLineNumber())
|
||||
.append(" : column ")
|
||||
.append(error.getColumnNumber())
|
||||
.append("): ")
|
||||
.append(error.getMessage())
|
||||
.append("\n");
|
||||
}
|
||||
throw new MappingException( "Invalid ORM mapping file.\n" + errorMessage.toString() );
|
||||
}
|
||||
add( doc );
|
||||
return this;
|
||||
}
|
||||
catch ( DocumentException e ) {
|
||||
throw new MappingException( "Could not parse mapping document in input stream", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
xmlInputStream.close();
|
||||
|
@ -875,6 +923,40 @@ public class AnnotationConfiguration extends Configuration {
|
|||
}
|
||||
}
|
||||
|
||||
private static class ErrorLogger implements ErrorHandler {
|
||||
private List<SAXParseException> errors;
|
||||
|
||||
public ErrorLogger(List<SAXParseException> errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public void warning(SAXParseException exception) throws SAXException {
|
||||
errors.add( exception );
|
||||
}
|
||||
|
||||
public void error(SAXParseException exception) throws SAXException {
|
||||
errors.add( exception );
|
||||
}
|
||||
|
||||
public void fatalError(SAXParseException exception) throws SAXException {
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
//set the default schema locators
|
||||
saxReader.setProperty(
|
||||
"http://apache.org/xml/properties/schema/external-schemaLocation",
|
||||
"http://java.sun.com/xml/ns/persistence/orm " + xsd
|
||||
);
|
||||
}
|
||||
catch ( SAXException e ) {
|
||||
saxReader.setValidation( false );
|
||||
}
|
||||
}
|
||||
|
||||
public SessionFactory buildSessionFactory() throws HibernateException {
|
||||
enableLegacyHibernateValidator();
|
||||
enableBeanValidation();
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
version="1.0"
|
||||
>
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
version="2.0">
|
||||
<!-- no grammar specified should pass -->
|
||||
<persistence-unit-metadata>
|
||||
<persistence-unit-defaults>
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
|
||||
version="1.0"
|
||||
>
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm/orm_2_0.xsd"
|
||||
version="2.0">
|
||||
<package>org.hibernate.test.annotations.xml.ejb3</package>
|
||||
<entity class="Lighter" access="FIELD" metadata-complete="true">
|
||||
<attributes>
|
||||
|
|
|
@ -68,6 +68,11 @@ public final class PersistenceXmlLoader {
|
|||
}
|
||||
|
||||
private static Document loadURL(URL configURL, EntityResolver resolver) throws Exception {
|
||||
/*
|
||||
* try and parse the document:
|
||||
* - try and validate the document with persistence_2_0.xsd
|
||||
* - if it fails because of the version attribute mismatch, try and validate the document with persistence_1_0.xsd
|
||||
*/
|
||||
InputStream is = null;
|
||||
if (configURL != null) {
|
||||
URLConnection conn = configURL.openConnection();
|
||||
|
@ -75,8 +80,9 @@ public final class PersistenceXmlLoader {
|
|||
is = conn.getInputStream();
|
||||
}
|
||||
if ( is == null ) {
|
||||
throw new IOException( "Failed to obtain InputStream from url: " + configURL );
|
||||
throw new IOException( "Failed to obtain InputStream while reading persistence.xml file: " + configURL );
|
||||
}
|
||||
|
||||
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
docBuilderFactory.setNamespaceAware( true );
|
||||
final Schema v2Schema = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI )
|
||||
|
@ -91,6 +97,8 @@ public final class PersistenceXmlLoader {
|
|||
docBuilder.setEntityResolver( resolver );
|
||||
List<SAXParseException> errors = new ArrayList<SAXParseException>();
|
||||
Document doc = null;
|
||||
|
||||
//first sparse document and collect syntaxic errors
|
||||
try {
|
||||
doc = docBuilder.parse( source );
|
||||
}
|
||||
|
@ -99,7 +107,7 @@ public final class PersistenceXmlLoader {
|
|||
}
|
||||
|
||||
if (errors.size() == 0) {
|
||||
v2Validator.setErrorHandler( new ErrorLogger( "XML InputStream", errors, resolver ) );
|
||||
v2Validator.setErrorHandler( new ErrorLogger( errors ) );
|
||||
log.trace("Validate with persistence_2_0.xsd schema on file {}", configURL);
|
||||
v2Validator.validate( new DOMSource( doc ) );
|
||||
boolean isV1Schema = false;
|
||||
|
@ -108,6 +116,7 @@ public final class PersistenceXmlLoader {
|
|||
log.trace("Found error with persistence_2_0.xsd schema on file {}", configURL);
|
||||
SAXParseException exception = errors.get( 0 );
|
||||
final String errorMessage = exception.getMessage();
|
||||
//is it a validation error due to a v1 schema validated by a v2
|
||||
isV1Schema = errorMessage.contains("1.0")
|
||||
&& errorMessage.contains("2.0")
|
||||
&& errorMessage.contains("version");
|
||||
|
@ -116,11 +125,12 @@ public final class PersistenceXmlLoader {
|
|||
if (isV1Schema) {
|
||||
log.trace("Validate with persistence_1_0.xsd schema on file {}", configURL);
|
||||
errors.clear();
|
||||
v1Validator.setErrorHandler( new ErrorLogger( "XML InputStream", errors, resolver ) );
|
||||
v1Validator.setErrorHandler( new ErrorLogger( errors ) );
|
||||
v1Validator.validate( new DOMSource( doc ) );
|
||||
}
|
||||
}
|
||||
if ( errors.size() != 0 ) {
|
||||
//report all errors in the exception
|
||||
StringBuilder errorMessage = new StringBuilder( );
|
||||
for (SAXParseException error : errors) {
|
||||
errorMessage.append("Error parsing XML (line")
|
||||
|
@ -310,17 +320,14 @@ public final class PersistenceXmlLoader {
|
|||
}
|
||||
|
||||
public static class ErrorLogger implements ErrorHandler {
|
||||
private String file;
|
||||
private List errors;
|
||||
private EntityResolver resolver;
|
||||
private List<SAXParseException> errors;
|
||||
|
||||
ErrorLogger(String file, List errors, EntityResolver resolver) {
|
||||
this.file = file;
|
||||
ErrorLogger(List<SAXParseException> errors) {
|
||||
this.errors = errors;
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
public void error(SAXParseException error) {
|
||||
//what was this commented code about?
|
||||
// if ( resolver instanceof EJB3DTDEntityResolver ) {
|
||||
// if ( ( (EJB3DTDEntityResolver) resolver ).isResolved() == false ) return;
|
||||
// }
|
||||
|
|
Loading…
Reference in New Issue