Author: epbernard
Date: 2009-12-18 05:02:26 -0500 (Fri, 18 Dec 2009)
New Revision: 18263
Modified:
core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java
core/trunk/annotations/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm.xml
core/trunk/annotations/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm3.xml
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/PersistenceXmlLoader.java
Log:
HHH-4667 accept orm 2 and orm 1 files. Also improved error reports
Modified:
core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java
===================================================================
---
core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java 2009-12-18
06:23:17 UTC (rev 18262)
+++
core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java 2009-12-18
10:02:26 UTC (rev 18263)
@@ -26,6 +26,7 @@
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.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.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 @@
@Override
public AnnotationConfiguration addInputStream(InputStream xmlInputStream) throws
MappingException {
try {
- List errors = new ArrayList();
- SAXReader saxReader = xmlHelper.createSAXReader( "XML InputStream", errors,
getEntityResolver() );
+ /*
+ * 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 {
- 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"
- );
+ doc = saxReader.read( new InputSource( xmlInputStream ) );
}
- catch ( SAXException e ) {
- saxReader.setValidation( false );
+ 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 );
}
- org.dom4j.Document doc = saxReader
- .read( new InputSource( xmlInputStream ) );
+ 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 @@
}
}
+ 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();
Modified:
core/trunk/annotations/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm.xml
===================================================================
---
core/trunk/annotations/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm.xml 2009-12-18
06:23:17 UTC (rev 18262)
+++
core/trunk/annotations/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm.xml 2009-12-18
10:02:26 UTC (rev 18263)
@@ -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>
Modified:
core/trunk/annotations/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm3.xml
===================================================================
---
core/trunk/annotations/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm3.xml 2009-12-18
06:23:17 UTC (rev 18262)
+++
core/trunk/annotations/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm3.xml 2009-12-18
10:02:26 UTC (rev 18263)
@@ -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>
Modified:
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/PersistenceXmlLoader.java
===================================================================
---
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/PersistenceXmlLoader.java 2009-12-18
06:23:17 UTC (rev 18262)
+++
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/PersistenceXmlLoader.java 2009-12-18
10:02:26 UTC (rev 18263)
@@ -68,6 +68,11 @@
}
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 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;
// }