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.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.StringReader;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -54,6 +55,8 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.SAXParseException;
|
||||||
|
import org.xml.sax.ErrorHandler;
|
||||||
|
|
||||||
import org.hibernate.AnnotationException;
|
import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.DuplicateMappingException;
|
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.ReflectionManager;
|
||||||
import org.hibernate.annotations.common.reflection.XClass;
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
|
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.Version;
|
||||||
import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider;
|
import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider;
|
||||||
import org.hibernate.cfg.beanvalidation.BeanValidationActivator;
|
import org.hibernate.cfg.beanvalidation.BeanValidationActivator;
|
||||||
|
@ -839,32 +843,76 @@ public class AnnotationConfiguration extends Configuration {
|
||||||
@Override
|
@Override
|
||||||
public AnnotationConfiguration addInputStream(InputStream xmlInputStream) throws MappingException {
|
public AnnotationConfiguration addInputStream(InputStream xmlInputStream) throws MappingException {
|
||||||
try {
|
try {
|
||||||
List errors = new ArrayList();
|
/*
|
||||||
SAXReader saxReader = xmlHelper.createSAXReader( "XML InputStream", errors, getEntityResolver() );
|
* try and parse the document:
|
||||||
try {
|
* - try and validate the document with orm_2_0.xsd
|
||||||
saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true );
|
* - if it fails because of the version attribute mismatch, try and validate the document with orm_1_0.xsd
|
||||||
//saxReader.setFeature( "http://apache.org/xml/features/validation/dynamic", true );
|
*/
|
||||||
//set the default schema locators
|
List<SAXParseException> errors = new ArrayList<SAXParseException>();
|
||||||
saxReader.setProperty(
|
SAXReader saxReader = new SAXReader( );
|
||||||
"http://apache.org/xml/properties/schema/external-schemaLocation",
|
saxReader.setEntityResolver( getEntityResolver() );
|
||||||
"http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
|
saxReader.setErrorHandler( new ErrorLogger(errors) );
|
||||||
);
|
saxReader.setMergeAdjacentText(true);
|
||||||
}
|
saxReader.setValidation(true);
|
||||||
catch ( SAXException e ) {
|
|
||||||
saxReader.setValidation( false );
|
|
||||||
}
|
|
||||||
org.dom4j.Document doc = saxReader
|
|
||||||
.read( new InputSource( xmlInputStream ) );
|
|
||||||
|
|
||||||
|
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 ) {
|
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 );
|
add( doc );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
catch ( DocumentException e ) {
|
|
||||||
throw new MappingException( "Could not parse mapping document in input stream", e );
|
|
||||||
}
|
|
||||||
finally {
|
finally {
|
||||||
try {
|
try {
|
||||||
xmlInputStream.close();
|
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 {
|
public SessionFactory buildSessionFactory() throws HibernateException {
|
||||||
enableLegacyHibernateValidator();
|
enableLegacyHibernateValidator();
|
||||||
enableBeanValidation();
|
enableBeanValidation();
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
version="1.0"
|
version="2.0">
|
||||||
>
|
|
||||||
<!-- no grammar specified should pass -->
|
<!-- no grammar specified should pass -->
|
||||||
<persistence-unit-metadata>
|
<persistence-unit-metadata>
|
||||||
<persistence-unit-defaults>
|
<persistence-unit-defaults>
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
|
|
||||||
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm/orm_2_0.xsd"
|
||||||
version="1.0"
|
version="2.0">
|
||||||
>
|
|
||||||
<package>org.hibernate.test.annotations.xml.ejb3</package>
|
<package>org.hibernate.test.annotations.xml.ejb3</package>
|
||||||
<entity class="Lighter" access="FIELD" metadata-complete="true">
|
<entity class="Lighter" access="FIELD" metadata-complete="true">
|
||||||
<attributes>
|
<attributes>
|
||||||
|
|
|
@ -68,6 +68,11 @@ public final class PersistenceXmlLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Document loadURL(URL configURL, EntityResolver resolver) throws Exception {
|
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;
|
InputStream is = null;
|
||||||
if (configURL != null) {
|
if (configURL != null) {
|
||||||
URLConnection conn = configURL.openConnection();
|
URLConnection conn = configURL.openConnection();
|
||||||
|
@ -75,8 +80,9 @@ public final class PersistenceXmlLoader {
|
||||||
is = conn.getInputStream();
|
is = conn.getInputStream();
|
||||||
}
|
}
|
||||||
if ( is == null ) {
|
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();
|
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||||
docBuilderFactory.setNamespaceAware( true );
|
docBuilderFactory.setNamespaceAware( true );
|
||||||
final Schema v2Schema = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI )
|
final Schema v2Schema = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI )
|
||||||
|
@ -91,6 +97,8 @@ public final class PersistenceXmlLoader {
|
||||||
docBuilder.setEntityResolver( resolver );
|
docBuilder.setEntityResolver( resolver );
|
||||||
List<SAXParseException> errors = new ArrayList<SAXParseException>();
|
List<SAXParseException> errors = new ArrayList<SAXParseException>();
|
||||||
Document doc = null;
|
Document doc = null;
|
||||||
|
|
||||||
|
//first sparse document and collect syntaxic errors
|
||||||
try {
|
try {
|
||||||
doc = docBuilder.parse( source );
|
doc = docBuilder.parse( source );
|
||||||
}
|
}
|
||||||
|
@ -99,7 +107,7 @@ public final class PersistenceXmlLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors.size() == 0) {
|
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);
|
log.trace("Validate with persistence_2_0.xsd schema on file {}", configURL);
|
||||||
v2Validator.validate( new DOMSource( doc ) );
|
v2Validator.validate( new DOMSource( doc ) );
|
||||||
boolean isV1Schema = false;
|
boolean isV1Schema = false;
|
||||||
|
@ -108,6 +116,7 @@ public final class PersistenceXmlLoader {
|
||||||
log.trace("Found error with persistence_2_0.xsd schema on file {}", configURL);
|
log.trace("Found error with persistence_2_0.xsd schema on file {}", configURL);
|
||||||
SAXParseException exception = errors.get( 0 );
|
SAXParseException exception = errors.get( 0 );
|
||||||
final String errorMessage = exception.getMessage();
|
final String errorMessage = exception.getMessage();
|
||||||
|
//is it a validation error due to a v1 schema validated by a v2
|
||||||
isV1Schema = errorMessage.contains("1.0")
|
isV1Schema = errorMessage.contains("1.0")
|
||||||
&& errorMessage.contains("2.0")
|
&& errorMessage.contains("2.0")
|
||||||
&& errorMessage.contains("version");
|
&& errorMessage.contains("version");
|
||||||
|
@ -116,11 +125,12 @@ public final class PersistenceXmlLoader {
|
||||||
if (isV1Schema) {
|
if (isV1Schema) {
|
||||||
log.trace("Validate with persistence_1_0.xsd schema on file {}", configURL);
|
log.trace("Validate with persistence_1_0.xsd schema on file {}", configURL);
|
||||||
errors.clear();
|
errors.clear();
|
||||||
v1Validator.setErrorHandler( new ErrorLogger( "XML InputStream", errors, resolver ) );
|
v1Validator.setErrorHandler( new ErrorLogger( errors ) );
|
||||||
v1Validator.validate( new DOMSource( doc ) );
|
v1Validator.validate( new DOMSource( doc ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( errors.size() != 0 ) {
|
if ( errors.size() != 0 ) {
|
||||||
|
//report all errors in the exception
|
||||||
StringBuilder errorMessage = new StringBuilder( );
|
StringBuilder errorMessage = new StringBuilder( );
|
||||||
for (SAXParseException error : errors) {
|
for (SAXParseException error : errors) {
|
||||||
errorMessage.append("Error parsing XML (line")
|
errorMessage.append("Error parsing XML (line")
|
||||||
|
@ -310,17 +320,14 @@ public final class PersistenceXmlLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ErrorLogger implements ErrorHandler {
|
public static class ErrorLogger implements ErrorHandler {
|
||||||
private String file;
|
private List<SAXParseException> errors;
|
||||||
private List errors;
|
|
||||||
private EntityResolver resolver;
|
|
||||||
|
|
||||||
ErrorLogger(String file, List errors, EntityResolver resolver) {
|
ErrorLogger(List<SAXParseException> errors) {
|
||||||
this.file = file;
|
|
||||||
this.errors = errors;
|
this.errors = errors;
|
||||||
this.resolver = resolver;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void error(SAXParseException error) {
|
public void error(SAXParseException error) {
|
||||||
|
//what was this commented code about?
|
||||||
// if ( resolver instanceof EJB3DTDEntityResolver ) {
|
// if ( resolver instanceof EJB3DTDEntityResolver ) {
|
||||||
// if ( ( (EJB3DTDEntityResolver) resolver ).isResolved() == false ) return;
|
// if ( ( (EJB3DTDEntityResolver) resolver ).isResolved() == false ) return;
|
||||||
// }
|
// }
|
||||||
|
|
Loading…
Reference in New Issue