From 3af728b42c622266f27bade0805565d7a1b396af Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Sun, 1 Apr 2018 12:50:56 -0500 Subject: [PATCH] HHH-12379 - Add support for persistence_2_2.xsd and orm_2_2.xsd --- .../boot/jaxb/internal/MappingBinder.java | 12 +- .../jaxb/internal/stax/HbmEventReader.java | 8 +- .../internal/stax/JpaOrmXmlEventReader.java | 20 +- .../boot/jaxb/internal/stax/LocalSchema.java | 4 + .../internal/stax/SupportedOrmXsdVersion.java | 69 - .../UnsupportedOrmXsdVersionException.java | 29 - .../hibernate/boot/xsd/ConfigXsdSupport.java | 83 + .../hibernate/boot/xsd/LocalXsdResolver.java | 113 + .../hibernate/boot/xsd/MappingXsdSupport.java | 81 + .../org/hibernate/boot/xsd/XsdDescriptor.java | 44 + .../org/hibernate/boot/xsd/package-info.java | 12 + .../boot/internal/PersistenceXmlParser.java | 108 +- .../resources/org/hibernate/jpa/orm_2_2.xsd | 2301 +++++++++++++++++ .../org/hibernate/jpa/persistence_2_2.xsd | 341 +++ .../ValidatorFactory2PhaseInjectionTest.java | 4 +- .../jpa/test/boot/NewBootProcessTest.java | 4 +- .../jpa/xml/versions/JpaXsdVersionsTest.java} | 46 +- .../jpa/xml/versions/invalid-orm-1_0.xml} | 0 .../jpa/xml/versions/valid-orm-1_0.xml} | 0 .../jpa/xml/versions/valid-orm-2_0.xml} | 0 .../test/jpa/xml/versions/valid-orm-2_1.xml | 40 + .../test/jpa/xml/versions/valid-orm-2_2.xml | 44 + .../xml/versions/valid-persistence-1_0.xml | 0 23 files changed, 3137 insertions(+), 226 deletions(-) delete mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/SupportedOrmXsdVersion.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/UnsupportedOrmXsdVersionException.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/xsd/ConfigXsdSupport.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/xsd/LocalXsdResolver.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/xsd/XsdDescriptor.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/xsd/package-info.java create mode 100644 hibernate-core/src/main/resources/org/hibernate/jpa/orm_2_2.xsd create mode 100644 hibernate-core/src/main/resources/org/hibernate/jpa/persistence_2_2.xsd rename hibernate-core/src/test/java/org/hibernate/{jpa/test/jee/OrmVersionTest.java => test/jpa/xml/versions/JpaXsdVersionsTest.java} (75%) rename hibernate-core/src/test/resources/org/hibernate/{jpa/test/jee/invalid-orm-1.xml => test/jpa/xml/versions/invalid-orm-1_0.xml} (100%) rename hibernate-core/src/test/resources/org/hibernate/{jpa/test/jee/valid-orm-1.xml => test/jpa/xml/versions/valid-orm-1_0.xml} (100%) rename hibernate-core/src/test/resources/org/hibernate/{jpa/test/jee/valid-orm-2.xml => test/jpa/xml/versions/valid-orm-2_0.xml} (100%) create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_1.xml create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_2.xml create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-persistence-1_0.xml diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java index af2051d752..a7a51b905d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java @@ -20,9 +20,9 @@ import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; import org.hibernate.boot.jaxb.internal.stax.HbmEventReader; import org.hibernate.boot.jaxb.internal.stax.JpaOrmXmlEventReader; -import org.hibernate.boot.jaxb.internal.stax.LocalSchema; import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.xsd.MappingXsdSupport; import org.hibernate.internal.util.config.ConfigurationException; import org.jboss.logging.Logger; @@ -38,10 +38,12 @@ public class MappingBinder extends AbstractBinder { private static final Logger log = Logger.getLogger( MappingBinder.class ); private final XMLEventFactory xmlEventFactory = XMLEventFactory.newInstance(); + private final MappingXsdSupport xsdSupport = new MappingXsdSupport(); + private JAXBContext hbmJaxbContext; public MappingBinder(ClassLoaderService classLoaderService) { - super( classLoaderService ); + this( classLoaderService, true ); } public MappingBinder(ClassLoaderService classLoaderService, boolean validateXml) { @@ -58,8 +60,8 @@ public class MappingBinder extends AbstractBinder { log.debugf( "Performing JAXB binding of hbm.xml document : %s", origin.toString() ); XMLEventReader hbmReader = new HbmEventReader( staxEventReader, xmlEventFactory ); - JaxbHbmHibernateMapping hbmBindings = jaxb( hbmReader, LocalSchema.HBM.getSchema(), hbmJaxbContext(), origin ); - return new Binding( hbmBindings, origin ); + JaxbHbmHibernateMapping hbmBindings = jaxb( hbmReader, xsdSupport.hbmXsd().getSchema(), hbmJaxbContext(), origin ); + return new Binding<>( hbmBindings, origin ); } else { // final XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader ); @@ -67,7 +69,7 @@ public class MappingBinder extends AbstractBinder { try { final XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader, xmlEventFactory ); - return new Binding( toDom4jDocument( reader, origin), origin ); + return new Binding<>( toDom4jDocument( reader, origin ), origin ); } catch (JpaOrmXmlEventReader.BadVersionException e) { throw new UnsupportedOrmXsdVersionException( e.getRequestedVersion(), origin ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/HbmEventReader.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/HbmEventReader.java index 98d2d757c9..72e9649cef 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/HbmEventReader.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/HbmEventReader.java @@ -19,6 +19,8 @@ import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import javax.xml.stream.util.EventReaderDelegate; +import org.hibernate.boot.xsd.MappingXsdSupport; + /** * A StAX EventReader for {@code hbm.xml} files to add namespaces in documents * not containing namespaces. @@ -65,7 +67,7 @@ public class HbmEventReader extends EventReaderDelegate { if ( "".equals( startElement.getName().getNamespaceURI() ) ) { // add the default namespace mapping - targetNamespaces.add( xmlEventFactory.createNamespace( LocalSchema.HBM.getNamespaceUri() ) ); + targetNamespaces.add( xmlEventFactory.createNamespace( MappingXsdSupport.INSTANCE.hbmXsd().getNamespaceUri() ) ); } // transfer any namespaces directly, unless it is in the "to map" list in which case @@ -75,7 +77,7 @@ public class HbmEventReader extends EventReaderDelegate { Namespace namespace = originalNamespaces.next(); if ( NAMESPACE_URIS_TO_MAP.contains( namespace.getNamespaceURI() ) ) { // this is a namespace "to map" so map it - namespace = xmlEventFactory.createNamespace( namespace.getPrefix(), LocalSchema.HBM.getNamespaceUri() ); + namespace = xmlEventFactory.createNamespace( namespace.getPrefix(), MappingXsdSupport.INSTANCE.hbmXsd().getNamespaceUri() ); } targetNamespaces.add( namespace ); } @@ -84,7 +86,7 @@ public class HbmEventReader extends EventReaderDelegate { // so that the event we ask it to generate for us has the same location info xmlEventFactory.setLocation( startElement.getLocation() ); return xmlEventFactory.createStartElement( - new QName( LocalSchema.HBM.getNamespaceUri(), startElement.getName().getLocalPart() ), + new QName( MappingXsdSupport.INSTANCE.hbmXsd().getNamespaceUri(), startElement.getName().getLocalPart() ), startElement.getAttributes(), targetNamespaces.iterator() ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/JpaOrmXmlEventReader.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/JpaOrmXmlEventReader.java index 17b0aadb57..b862c4bfac 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/JpaOrmXmlEventReader.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/JpaOrmXmlEventReader.java @@ -21,6 +21,9 @@ import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import javax.xml.stream.util.EventReaderDelegate; +import org.hibernate.boot.xsd.LocalXsdResolver; +import org.hibernate.boot.xsd.MappingXsdSupport; + /** * A JPA {@code orm.xml} specific StAX EVentReader to handle a few oddities. * @@ -44,9 +47,6 @@ public class JpaOrmXmlEventReader extends EventReaderDelegate { private static final String ROOT_ELEMENT_NAME = "entity-mappings"; private static final String VERSION_ATTRIBUTE_NAME = "version"; - private static final String DEFAULT_VERSION = "2.1"; - private static final List VALID_VERSIONS = Arrays.asList( "1.0", "2.0", "2.1" ); - private final XMLEventFactory xmlEventFactory; public JpaOrmXmlEventReader(XMLEventReader reader) { @@ -88,14 +88,14 @@ public class JpaOrmXmlEventReader extends EventReaderDelegate { // so that the event we ask it to generate for us has the same location info xmlEventFactory.setLocation( startElement.getLocation() ); return xmlEventFactory.createStartElement( - new QName( LocalSchema.ORM.getNamespaceUri(), startElement.getName().getLocalPart() ), + new QName( MappingXsdSupport.INSTANCE.latestJpaDescriptor().getNamespaceUri(), startElement.getName().getLocalPart() ), newElementAttributeList.iterator(), newNamespaceList.iterator() ); } private List mapAttributes(StartElement startElement) { - final List mappedAttributes = new ArrayList(); + final List mappedAttributes = new ArrayList<>(); Iterator existingAttributesIterator = existingXmlAttributesIterator( startElement ); while ( existingAttributesIterator.hasNext() ) { @@ -125,11 +125,11 @@ public class JpaOrmXmlEventReader extends EventReaderDelegate { if ( VERSION_ATTRIBUTE_NAME.equals( originalAttribute.getName().getLocalPart() ) ) { final String specifiedVersion = originalAttribute.getValue(); - if ( !VALID_VERSIONS.contains( specifiedVersion ) ) { + if ( !LocalXsdResolver.isValidJpaVersion( specifiedVersion ) ) { throw new BadVersionException( specifiedVersion ); } - return xmlEventFactory.createAttribute( VERSION_ATTRIBUTE_NAME, DEFAULT_VERSION ); + return xmlEventFactory.createAttribute( VERSION_ATTRIBUTE_NAME, LocalXsdResolver.latestJpaVerison() ); } } @@ -156,7 +156,7 @@ public class JpaOrmXmlEventReader extends EventReaderDelegate { } if ( mappedNamespaces.isEmpty() ) { - mappedNamespaces.add( xmlEventFactory.createNamespace( LocalSchema.ORM.getNamespaceUri() ) ); + mappedNamespaces.add( xmlEventFactory.createNamespace( MappingXsdSupport.INSTANCE.latestJpaDescriptor().getNamespaceUri() ) ); } return mappedNamespaces; @@ -170,7 +170,7 @@ public class JpaOrmXmlEventReader extends EventReaderDelegate { private Namespace mapNamespace(Namespace originalNamespace) { if ( NAMESPACE_URIS_TO_MAP.contains( originalNamespace.getNamespaceURI() ) ) { // this is a namespace "to map" so map it - return xmlEventFactory.createNamespace( originalNamespace.getPrefix(), LocalSchema.ORM.getNamespaceUri() ); + return xmlEventFactory.createNamespace( originalNamespace.getPrefix(), MappingXsdSupport.INSTANCE.latestJpaDescriptor().getNamespaceUri() ); } return originalNamespace; @@ -183,7 +183,7 @@ public class JpaOrmXmlEventReader extends EventReaderDelegate { // so that the event we ask it to generate for us has the same location info xmlEventFactory.setLocation( endElement.getLocation() ); return xmlEventFactory.createEndElement( - new QName( LocalSchema.ORM.getNamespaceUri(), endElement.getName().getLocalPart() ), + new QName( MappingXsdSupport.INSTANCE.latestJpaDescriptor().getNamespaceUri(), endElement.getName().getLocalPart() ), targetNamespaces.iterator() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchema.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchema.java index c1067758b7..0897b2bece 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchema.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchema.java @@ -18,7 +18,11 @@ import org.jboss.logging.Logger; /** * @author Steve Ebersole + * + * @deprecated No longer used locally. See {@link org.hibernate.boot.xsd.MappingXsdSupport} + * and {@link org.hibernate.boot.xsd.ConfigXsdSupport} */ +@Deprecated public enum LocalSchema { ORM( "http://www.hibernate.org/xsd/orm/mapping", diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/SupportedOrmXsdVersion.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/SupportedOrmXsdVersion.java deleted file mode 100644 index 2759d34d6a..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/SupportedOrmXsdVersion.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.boot.jaxb.internal.stax; - -import java.net.URL; -import javax.xml.validation.Schema; - -import org.hibernate.boot.jaxb.Origin; - -/** - * @author Steve Ebersole - * - * @deprecated since 5.0; no longer used internally. - */ -@Deprecated -public enum SupportedOrmXsdVersion { - ORM_1_0( "org/hibernate/jpa/orm_1_0.xsd" ), - ORM_2_0( "org/hibernate/jpa/orm_2_0.xsd" ), - ORM_2_1( "org/hibernate/jpa/orm_2_1.xsd" ), - ORM_2_1_0( "org/hibernate/xsd/mapping/mapping-2.1.0.xsd" ), - HBM_4_0( "org/hibernate/xsd/mapping/legacy-mapping-4.0.xsd" ); - - private final String schemaResourceName; - - SupportedOrmXsdVersion(String schemaResourceName) { - this.schemaResourceName = schemaResourceName; - } - - public static SupportedOrmXsdVersion parse(String name, Origin origin) { - if ( "1.0".equals( name ) ) { - return ORM_1_0; - } - else if ( "2.0".equals( name ) ) { - return ORM_2_0; - } - else if ( "2.1".equals( name ) ) { - return ORM_2_1; - } - else if ( "2.1.0".equals( name ) ) { - return ORM_2_1_0; - } - else if ( "4.0".equals( name ) ) { - return HBM_4_0; - } - throw new UnsupportedOrmXsdVersionException( name, origin ); - } - - private URL schemaUrl; - - public URL getSchemaUrl() { - if ( schemaUrl == null ) { - schemaUrl = LocalSchemaLocator.resolveLocalSchemaUrl( schemaResourceName ); - } - return schemaUrl; - } - - private Schema schema; - - public Schema getSchema() { - if ( schema == null ) { - schema = LocalSchemaLocator.resolveLocalSchema( getSchemaUrl() ); - } - return schema; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/UnsupportedOrmXsdVersionException.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/UnsupportedOrmXsdVersionException.java deleted file mode 100644 index 02b3142d80..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/UnsupportedOrmXsdVersionException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.boot.jaxb.internal.stax; - -import org.hibernate.HibernateException; -import org.hibernate.boot.jaxb.Origin; - -/** - * @author Steve Ebersole - * - * @deprecated Use {@link org.hibernate.boot.UnsupportedOrmXsdVersionException} instead - */ -@Deprecated -public class UnsupportedOrmXsdVersionException extends HibernateException { - public UnsupportedOrmXsdVersionException(String requestedVersion, Origin origin) { - super( - String.format( - "Encountered unsupported orm.xml xsd version [%s] in mapping document [type=%s, name=%s]", - requestedVersion, - origin.getType(), - origin.getName() - ) - ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/ConfigXsdSupport.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/ConfigXsdSupport.java new file mode 100644 index 0000000000..4198b6ffe4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/ConfigXsdSupport.java @@ -0,0 +1,83 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.xsd; + +import org.jboss.logging.Logger; + +/** + * Support for XSD handling related to Hibernate's `cfg.xml` and + * JPA's `persistence.xml`. + * + * @author Steve Ebersole + */ +@SuppressWarnings("unused") +public class ConfigXsdSupport { + private static final Logger log = Logger.getLogger( ConfigXsdSupport.class ); + + /** + * Singleton access + */ + public static final ConfigXsdSupport INSTANCE = new ConfigXsdSupport(); + + private final XsdDescriptor jpa10 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/jpa/persistence_1_0.xsd", + "1.0", + "http://java.sun.com/xml/ns/persistence" + ); + + private final XsdDescriptor jpa20 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/jpa/persistence_2_0.xsd", + "2.0" , + "http://java.sun.com/xml/ns/persistence" + ); + + private final XsdDescriptor jpa21 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/jpa/persistence_2_1.xsd", + "2.1", + "http://xmlns.jcp.org/xml/ns/persistence" + ); + + private final XsdDescriptor jpa22 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/jpa/persistence_2_2.xsd", + "2.2" , + "http://xmlns.jcp.org/xml/ns/persistence" + ); + + private final XsdDescriptor cfgXml = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/xsd/cfg/legacy-configuration-4.0.xsd", + "4.0" , + "http://www.hibernate.org/xsd/orm/cfg" + ); + + public XsdDescriptor latestJpaDescriptor() { + return jpa22; + } + + public XsdDescriptor jpaXsd(String version) { + switch ( version ) { + case "1.0": { + return jpa10; + } + case "2.0": { + return jpa20; + } + case "2.1": { + return jpa21; + } + case "2.2": { + return jpa22; + } + default: { + throw new IllegalArgumentException( "Unrecognized JPA persistence.xml XSD version : `" + version + "`" ); + } + } + } + + public XsdDescriptor cfgXsd() { + return cfgXml; + } +} \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/LocalXsdResolver.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/LocalXsdResolver.java new file mode 100644 index 0000000000..31ac6a838e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/LocalXsdResolver.java @@ -0,0 +1,113 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.xsd; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import javax.xml.XMLConstants; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.hibernate.internal.util.xml.XsdException; + +import org.jboss.logging.Logger; + +import org.xml.sax.SAXException; + +/** + * When Hibernate loads an XSD we fully expect that to be resolved from our + * jar file via ClassLoader resource look-up. This class simplifies + * the steps needed to achieve those goals explicitly using its own + * ClassLoader for the look-ups. + * + * @author Steve Ebersole + */ +@SuppressWarnings("WeakerAccess") +public class LocalXsdResolver { + private static final Logger log = Logger.getLogger( LocalXsdResolver.class ); + + private static final List VALID_JPA_VERSIONS = Arrays.asList( "1.0", "2.0", "2.1", "2.2" ); + + public static String latestJpaVerison() { + return "2.2"; + } + + public static boolean isValidJpaVersion(String version) { + return VALID_JPA_VERSIONS.contains( version ); + } + + public static URL resolveLocalXsdUrl(String resourceName) { + // first we try name as a URL + try { + return new URL( resourceName ); + } + catch (Exception ignore) { + } + + try { + final URL url = LocalXsdResolver.class.getClassLoader().getResource( resourceName ); + if ( url != null ) { + return url; + } + } + catch (Exception ignore) { + } + + if ( resourceName.startsWith( "/" ) ) { + resourceName = resourceName.substring( 1 ); + + try { + final URL url = LocalXsdResolver.class.getClassLoader().getResource( resourceName ); + if ( url != null ) { + return url; + } + } + catch (Exception ignore) { + } + } + + return null; + } + + + public static Schema resolveLocalXsdSchema(String schemaResourceName) { + final URL url = resolveLocalXsdUrl( schemaResourceName ); + if ( url == null ) { + throw new XsdException( "Unable to locate schema [" + schemaResourceName + "] via classpath", schemaResourceName ); + } + try { + InputStream schemaStream = url.openStream(); + try { + StreamSource source = new StreamSource( url.openStream() ); + SchemaFactory schemaFactory = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI ); + return schemaFactory.newSchema( source ); + } + catch ( SAXException | IOException e ) { + throw new XsdException( "Unable to load schema [" + schemaResourceName + "]", e, schemaResourceName ); + } + finally { + try { + schemaStream.close(); + } + catch ( IOException e ) { + log.debugf( "Problem closing schema stream [%s]", e.toString() ); + } + } + } + catch ( IOException e ) { + throw new XsdException( "Stream error handling schema url [" + url.toExternalForm() + "]", schemaResourceName ); + } + } + + public static XsdDescriptor buildXsdDescriptor(String resourceName, String version, String namespaceUri) { + return new XsdDescriptor( resourceName, resolveLocalXsdSchema( resourceName ), version, namespaceUri ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java new file mode 100644 index 0000000000..b743cd1fea --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java @@ -0,0 +1,81 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.xsd; + +/** + * Support for XSD handling related to Hibernate's `hbm.xml` and + * JPA's `orm.xml`. + * + * @author Steve Ebersole + */ +@SuppressWarnings("unused") +public class MappingXsdSupport { + + /** + * Singleton access + */ + public static final MappingXsdSupport INSTANCE = new MappingXsdSupport(); + + private final XsdDescriptor jpa10 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/jpa/orm_1_0.xsd", + "1.0", + "http://java.sun.com/xml/ns/persistence/orm" + ); + + private final XsdDescriptor jpa20 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/jpa/orm_2_0.xsd", + "2.0", + "http://java.sun.com/xml/ns/persistence/orm" + ); + + private final XsdDescriptor jpa21 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/jpa/orm_2_1.xsd", + "2.1", + "http://xmlns.jcp.org/xml/ns/persistence" + ); + + private final XsdDescriptor jpa22 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/jpa/orm_2_2.xsd", + "2.2", + "http://xmlns.jcp.org/xml/ns/persistence" + ); + + private final XsdDescriptor hbmXml = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/xsd/mapping/legacy-mapping-4.0.xsd", + "4.0", + "http://www.hibernate.org/xsd/orm/hbm" + ); + + public XsdDescriptor latestJpaDescriptor() { + return jpa22; + } + + public XsdDescriptor jpaXsd(String version) { + switch ( version ) { + case "1.0": { + return jpa10; + } + case "2.0": { + return jpa20; + } + case "2.1": { + return jpa21; + } + case "2.2": { + return jpa22; + } + default: { + throw new IllegalArgumentException( "Unrecognized JPA orm.xml XSD version : `" + version + "`" ); + } + } + } + + public XsdDescriptor hbmXsd() { + return hbmXml; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/XsdDescriptor.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/XsdDescriptor.java new file mode 100644 index 0000000000..f17d550dba --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/XsdDescriptor.java @@ -0,0 +1,44 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.xsd; + +import javax.xml.validation.Schema; + +/** + * Representation of a locally resolved XSD + * + * @author Steve Ebersole + */ +public class XsdDescriptor { + private final String localResourceName; + private final String namespaceUri; + private final String version; + private final Schema schema; + + public XsdDescriptor(String localResourceName, Schema schema, String version, String namespaceUri) { + this.localResourceName = localResourceName; + this.schema = schema; + this.version = version; + this.namespaceUri = namespaceUri; + } + + public String getLocalResourceName() { + return localResourceName; + } + + public String getNamespaceUri() { + return namespaceUri; + } + + public String getVersion() { + return version; + } + + public Schema getSchema() { + return schema; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/package-info.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/package-info.java new file mode 100644 index 0000000000..b6be8bfa11 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/package-info.java @@ -0,0 +1,12 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ + +/** + * Support for XSD handling, specifically for ORM mappings (Hibernate's `hbm.xml` and + * JPA's `orm.xml`) and config files (Hibernate's `cfg.xml` and JPA's `persistence.xml`) + */ +package org.hibernate.boot.xsd; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java index 81c31ad51e..99f76fe5a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java @@ -18,23 +18,19 @@ import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import javax.persistence.PersistenceException; import javax.persistence.spi.PersistenceUnitTransactionType; -import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import org.hibernate.boot.archive.internal.ArchiveHelper; import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.xsd.ConfigXsdSupport; import org.hibernate.cfg.AvailableSettings; import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.util.StringHelper; -import org.hibernate.internal.util.xml.XsdException; import org.hibernate.jpa.internal.util.ConfigurationHelper; import org.w3c.dom.Document; @@ -204,8 +200,7 @@ public class PersistenceXmlParser { public static Map parse( URL persistenceXmlUrl, PersistenceUnitTransactionType transactionType, - Map integration - ) { + Map integration) { PersistenceXmlParser parser = new PersistenceXmlParser( ClassLoaderServiceImpl.fromConfigSettings( integration ), transactionType @@ -215,6 +210,7 @@ public class PersistenceXmlParser { return parser.persistenceUnits; } + private final ConfigXsdSupport xsdSupport = new ConfigXsdSupport(); private final ClassLoaderService classLoaderService; private final PersistenceUnitTransactionType defaultTransactionType; private final Map persistenceUnits; @@ -435,8 +431,7 @@ public class PersistenceXmlParser { URLConnection conn = xmlUrl.openConnection(); conn.setUseCaches( false ); //avoid JAR locking on Windows and Tomcat try { - InputStream inputStream = conn.getInputStream(); - try { + try (InputStream inputStream = conn.getInputStream()) { final InputSource inputSource = new InputSource( inputStream ); try { DocumentBuilder documentBuilder = documentBuilderFactory().newDocumentBuilder(); @@ -445,22 +440,15 @@ public class PersistenceXmlParser { validate( document ); return document; } - catch (SAXException e) { - throw new PersistenceException( "Unexpected error parsing [" + resourceName + "]", e ); - } - catch (IOException e) { + catch (SAXException | IOException e) { throw new PersistenceException( "Unexpected error parsing [" + resourceName + "]", e ); } } catch (ParserConfigurationException e) { - throw new PersistenceException( "Unable to generate javax.xml.parsers.DocumentBuilder instance", e ); - } - } - finally { - try { - inputStream.close(); - } - catch (Exception ignored) { + throw new PersistenceException( + "Unable to generate javax.xml.parsers.DocumentBuilder instance", + e + ); } } } @@ -476,22 +464,10 @@ public class PersistenceXmlParser { private void validate(Document document) { // todo : add ability to disable validation... - final Validator validator; final String version = document.getDocumentElement().getAttribute( "version" ); - if ( "2.1".equals( version ) ) { - validator = v21Schema().newValidator(); - } - else if ( "2.0".equals( version ) ) { - validator = v2Schema().newValidator(); - } - else if ( "1.0".equals( version ) ) { - validator = v1Schema().newValidator(); - } - else { - throw new PersistenceException( "Unrecognized persistence.xml version [" + version + "]" ); - } + final Validator validator = xsdSupport.jpaXsd( version ).getSchema().newValidator(); - List errors = new ArrayList(); + List errors = new ArrayList<>(); validator.setErrorHandler( new ErrorHandlerImpl( errors ) ); try { validator.validate( new DOMSource( document ) ); @@ -528,68 +504,6 @@ public class PersistenceXmlParser { return documentBuilderFactory; } - private Schema v21Schema; - - private Schema v21Schema() { - if ( v21Schema == null ) { - v21Schema = resolveLocalSchema( "org/hibernate/jpa/persistence_2_1.xsd" ); - } - return v21Schema; - } - - private Schema v2Schema; - - private Schema v2Schema() { - if ( v2Schema == null ) { - v2Schema = resolveLocalSchema( "org/hibernate/jpa/persistence_2_0.xsd" ); - } - return v2Schema; - } - - private Schema v1Schema; - - private Schema v1Schema() { - if ( v1Schema == null ) { - v1Schema = resolveLocalSchema( "org/hibernate/jpa/persistence_1_0.xsd" ); - } - return v1Schema; - } - - - private Schema resolveLocalSchema(String schemaName) { - // These XSD resources should be available on the Hibernate ClassLoader - final URL url = classLoaderService.locateResource( schemaName ); - if ( url == null ) { - throw new XsdException( "Unable to locate schema [" + schemaName + "] via classpath", schemaName ); - } - try { - InputStream schemaStream = url.openStream(); - try { - StreamSource source = new StreamSource( url.openStream() ); - SchemaFactory schemaFactory = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI ); - return schemaFactory.newSchema( source ); - } - catch ( SAXException e ) { - throw new XsdException( "Unable to load schema [" + schemaName + "]", e, schemaName ); - } - catch ( IOException e ) { - throw new XsdException( "Unable to load schema [" + schemaName + "]", e, schemaName ); - } - finally { - try { - schemaStream.close(); - } - catch ( IOException e ) { - LOG.debugf( "Problem closing schema stream [%s]", e.toString() ); - } - } - } - catch ( IOException e ) { - throw new XsdException( "Stream error handling schema url [" + url.toExternalForm() + "]", schemaName ); - } - } - - public static class ErrorHandlerImpl implements ErrorHandler { private List errors; diff --git a/hibernate-core/src/main/resources/org/hibernate/jpa/orm_2_2.xsd b/hibernate-core/src/main/resources/org/hibernate/jpa/orm_2_2.xsd new file mode 100644 index 0000000000..3334780af2 --- /dev/null +++ b/hibernate-core/src/main/resources/org/hibernate/jpa/orm_2_2.xsd @@ -0,0 +1,2301 @@ + + + + + + + + @(#)orm_2_1.xsd 2.1 February 4 2013 + + + + + + ... + + + + ]]> + + + + + + + + + + + + + + + + + + The entity-mappings element is the root element of a mapping + file. It contains the following four types of elements: + + 1. The persistence-unit-metadata element contains metadata + for the entire persistence unit. It is undefined if this element + occurs in multiple mapping files within the same persistence unit. + + 2. The package, schema, catalog and access elements apply to all of + the entity, mapped-superclass and embeddable elements defined in + the same file in which they occur. + + 3. The sequence-generator, table-generator, converter, named-query, + named-native-query, named-stored-procedure-query, and + sql-result-set-mapping elements are global to the persistence + unit. It is undefined to have more than one sequence-generator + or table-generator of the same name in the same or different + mapping files in a persistence unit. It is undefined to have + more than one named-query, named-native-query, sql-result-set-mapping, + or named-stored-procedure-query of the same name in the same + or different mapping files in a persistence unit. It is also + undefined to have more than one converter for the same target + type in the same or different mapping files in a persistence unit. + + 4. The entity, mapped-superclass and embeddable elements each define + the mapping information for a managed persistent class. The mapping + information contained in these elements may be complete or it may + be partial. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Metadata that applies to the persistence unit and not just to + the mapping file in which it is contained. + + If the xml-mapping-metadata-complete element is specified, + the complete set of mapping metadata for the persistence unit + is contained in the XML mapping files for the persistence unit. + + + + + + + + + + + + + + + + + These defaults are applied to the persistence unit as a whole + unless they are overridden by local annotation or XML + element settings. + + schema - Used as the schema for all tables, secondary tables, join + tables, collection tables, sequence generators, and table + generators that apply to the persistence unit + catalog - Used as the catalog for all tables, secondary tables, join + tables, collection tables, sequence generators, and table + generators that apply to the persistence unit + delimited-identifiers - Used to treat database identifiers as + delimited identifiers. + access - Used as the access type for all managed classes in + the persistence unit + cascade-persist - Adds cascade-persist to the set of cascade options + in all entity relationships of the persistence unit + entity-listeners - List of default entity listeners to be invoked + on each entity in the persistence unit. + + + + + + + + + + + + + + + + + + + + Defines the settings and mappings for an entity. Is allowed to be + sparsely populated and used in conjunction with the annotations. + Alternatively, the metadata-complete attribute can be used to + indicate that no annotations on the entity class (and its fields + or properties) are to be processed. If this is the case then + the defaulting rules for the entity and its subelements will + be recursively applied. + + @Target(TYPE) @Retention(RUNTIME) + public @interface Entity { + String name() default ""; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This element determines how the persistence provider accesses the + state of an entity or embedded object. + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface AssociationOverride { + String name(); + JoinColumn[] joinColumns() default{}; + JoinTable joinTable() default @JoinTable; + } + + + + + + + + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface AttributeOverride { + String name(); + Column column(); + } + + + + + + + + + + + + + + + + + This element contains the entity field or property mappings. + It may be sparsely populated to include only a subset of the + fields or properties. If metadata-complete for the entity is true + then the remainder of the attributes will be defaulted according + to the default rules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Basic { + FetchType fetch() default EAGER; + boolean optional() default true; + } + + + + + + + + + + + + + + + + + + + + + + + + + public enum CascadeType { ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH}; + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface CollectionTable { + String name() default ""; + String catalog() default ""; + String schema() default ""; + JoinColumn[] joinColumns() default {}; + UniqueConstraint[] uniqueConstraints() default {}; + Index[] indexes() default {}; + } + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Column { + String name() default ""; + boolean unique() default false; + boolean nullable() default true; + boolean insertable() default true; + boolean updatable() default true; + String columnDefinition() default ""; + String table() default ""; + int length() default 255; + int precision() default 0; // decimal precision + int scale() default 0; // decimal scale + } + + + + + + + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface ColumnResult { + String name(); + Class type() default void.class; + } + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface ConstructorResult { + Class targetClass(); + ColumnResult[] columns(); + } + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface Convert { + Class converter() default void.class; + String attributeName() default ""; + boolean disableConversion() default false; + } + + + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface Converter { + boolean autoApply() default false; + } + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface DiscriminatorColumn { + String name() default "DTYPE"; + DiscriminatorType discriminatorType() default STRING; + String columnDefinition() default ""; + int length() default 31; + } + + + + + + + + + + + + + + + + public enum DiscriminatorType { STRING, CHAR, INTEGER }; + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface DiscriminatorValue { + String value(); + } + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface ElementCollection { + Class targetClass() default void.class; + FetchType fetch() default LAZY; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the settings and mappings for embeddable objects. Is + allowed to be sparsely populated and used in conjunction with + the annotations. Alternatively, the metadata-complete attribute + can be used to indicate that no annotations are to be processed + in the class. If this is the case then the defaulting rules will + be recursively applied. + + @Target({TYPE}) @Retention(RUNTIME) + public @interface Embeddable {} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Embedded {} + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface EmbeddedId {} + + + + + + + + + + + + + + + + + Defines an entity listener to be invoked at lifecycle events + for the entities that list this listener. + + + + + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface EntityListeners { + Class[] value(); + } + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface EntityResult { + Class entityClass(); + FieldResult[] fields() default {}; + String discriminatorColumn() default ""; + } + + + + + + + + + + + + + + + + + public enum EnumType { + ORDINAL, + STRING + } + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Enumerated { + EnumType value() default ORDINAL; + } + + + + + + + + + + + + + public enum FetchType { LAZY, EAGER }; + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface FieldResult { + String name(); + String column(); + } + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface ForeignKey { + String name() default ""; + String foreign-key-definition() default ""; + boolean disable-foreign-key() default false; + } + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface GeneratedValue { + GenerationType strategy() default AUTO; + String generator() default ""; + } + + + + + + + + + + + + + + public enum GenerationType { TABLE, SEQUENCE, IDENTITY, AUTO }; + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Id {} + + + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface IdClass { + Class value(); + } + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface Index { + String name() default ""; + String columnList(); + boolean unique() default false; + } + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface Inheritance { + InheritanceType strategy() default SINGLE_TABLE; + } + + + + + + + + + + + + + public enum InheritanceType + { SINGLE_TABLE, JOINED, TABLE_PER_CLASS}; + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface JoinColumn { + String name() default ""; + String referencedColumnName() default ""; + boolean unique() default false; + boolean nullable() default true; + boolean insertable() default true; + boolean updatable() default true; + String columnDefinition() default ""; + String table() default ""; + ForeignKey foreignKey() default @ForeignKey(); + } + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface JoinTable { + String name() default ""; + String catalog() default ""; + String schema() default ""; + JoinColumn[] joinColumns() default {}; + JoinColumn[] inverseJoinColumns() default {}; + UniqueConstraint[] uniqueConstraints() default {}; + Index[] indexes() default {}; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Lob {} + + + + + + + + + + + + public enum LockModeType { READ, WRITE, OPTIMISTIC, OPTIMISTIC_FORCE_INCREMENT, PESSIMISTIC_READ, PESSIMISTIC_WRITE, PESSIMISTIC_FORCE_INCREMENT, NONE}; + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface ManyToMany { + Class targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default LAZY; + String mappedBy() default ""; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface ManyToOne { + Class targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default EAGER; + boolean optional() default true; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface MapKey { + String name() default ""; + } + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface MapKeyClass { + Class value(); + } + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface MapKeyColumn { + String name() default ""; + boolean unique() default false; + boolean nullable() default false; + boolean insertable() default true; + boolean updatable() default true; + String columnDefinition() default ""; + String table() default ""; + int length() default 255; + int precision() default 0; // decimal precision + int scale() default 0; // decimal scale + } + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface MapKeyJoinColumn { + String name() default ""; + String referencedColumnName() default ""; + boolean unique() default false; + boolean nullable() default false; + boolean insertable() default true; + boolean updatable() default true; + String columnDefinition() default ""; + String table() default ""; + } + + + + + + + + + + + + + + + + + + + + + Defines the settings and mappings for a mapped superclass. Is + allowed to be sparsely populated and used in conjunction with + the annotations. Alternatively, the metadata-complete attribute + can be used to indicate that no annotations are to be processed + If this is the case then the defaulting rules will be recursively + applied. + + @Target(TYPE) @Retention(RUNTIME) + public @interface MappedSuperclass{} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface NamedAttributeNode { + String value(); + String subgraph() default ""; + String keySubgraph() default ""; + } + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedEntityGraph { + String name() default ""; + NamedAttributeNode[] attributeNodes() default {}; + boolean includeAllAttributes() default false; + NamedSubgraph[] subgraphs() default {}; + NamedSubGraph[] subclassSubgraphs() default {}; + } + + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedNativeQuery { + String name(); + String query(); + QueryHint[] hints() default {}; + Class resultClass() default void.class; + String resultSetMapping() default ""; //named SqlResultSetMapping + } + + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedQuery { + String name(); + String query(); + LockModeType lockMode() default NONE; + QueryHint[] hints() default {}; + } + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedStoredProcedureQuery { + String name(); + String procedureName(); + StoredProcedureParameter[] parameters() default {}; + Class[] resultClasses() default {}; + String[] resultSetMappings() default{}; + QueryHint[] hints() default {}; + } + + + + + + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface NamedSubgraph { + String name(); + Class type() default void.class; + NamedAttributeNode[] attributeNodes(); + } + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OneToMany { + Class targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default LAZY; + String mappedBy() default ""; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OneToOne { + Class targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default EAGER; + boolean optional() default true; + String mappedBy() default ""; + boolean orphanRemoval() default false; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OrderBy { + String value() default ""; + } + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OrderColumn { + String name() default ""; + boolean nullable() default true; + boolean insertable() default true; + boolean updatable() default true; + String columnDefinition() default ""; + } + + + + + + + + + + + + + + + + + public enum ParameterMode { IN, INOUT, OUT, REF_CURSOR}; + + + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostLoad {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostPersist {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostRemove {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostUpdate {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PrePersist {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PreRemove {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PreUpdate {} + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface PrimaryKeyJoinColumn { + String name() default ""; + String referencedColumnName() default ""; + String columnDefinition() default ""; + } + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface QueryHint { + String name(); + String value(); + } + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface SecondaryTable { + String name(); + String catalog() default ""; + String schema() default ""; + PrimaryKeyJoinColumn[] pkJoinColumns() default {}; + UniqueConstraint[] uniqueConstraints() default {}; + Index[] indexes() default {}; + } + + + + + + + + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface SequenceGenerator { + String name(); + String sequenceName() default ""; + String catalog() default ""; + String schema() default ""; + int initialValue() default 1; + int allocationSize() default 50; + } + + + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface SqlResultSetMapping { + String name(); + EntityResult[] entities() default {}; + ConstructorResult[] classes() default{}; + ColumnResult[] columns() default {}; + } + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface StoredProcedureParameter { + String name() default ""; + ParameterMode mode() default ParameterMode.IN; + Class type(); + } + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface Table { + String name() default ""; + String catalog() default ""; + String schema() default ""; + UniqueConstraint[] uniqueConstraints() default {}; + Index[] indexes() default {}; + } + + + + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface TableGenerator { + String name(); + String table() default ""; + String catalog() default ""; + String schema() default ""; + String pkColumnName() default ""; + String valueColumnName() default ""; + String pkColumnValue() default ""; + int initialValue() default 0; + int allocationSize() default 50; + UniqueConstraint[] uniqueConstraints() default {}; + Indexes[] indexes() default {}; + } + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Temporal { + TemporalType value(); + } + + + + + + + + + + + + + public enum TemporalType { + DATE, // java.sql.Date + TIME, // java.sql.Time + TIMESTAMP // java.sql.Timestamp + } + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Transient {} + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface UniqueConstraint { + String name() default ""; + String[] columnNames(); + } + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Version {} + + + + + + + + + + + + diff --git a/hibernate-core/src/main/resources/org/hibernate/jpa/persistence_2_2.xsd b/hibernate-core/src/main/resources/org/hibernate/jpa/persistence_2_2.xsd new file mode 100644 index 0000000000..6b6a6c32ce --- /dev/null +++ b/hibernate-core/src/main/resources/org/hibernate/jpa/persistence_2_2.xsd @@ -0,0 +1,341 @@ + + + + + + + + @(#)persistence_2_1.xsd 2.1 February 8, 2013 + + + + + + ... + + + ]]> + + + + + + + + + + + + + + + + + + + + + + Configuration of a persistence unit. + + + + + + + + + + + + Description of this persistence unit. + + + + + + + + + + + + Provider class that supplies EntityManagers for this + persistence unit. + + + + + + + + + + + + The container-specific name of the JTA datasource to use. + + + + + + + + + + + + The container-specific name of a non-JTA datasource to use. + + + + + + + + + + + + File containing mapping information. Loaded as a resource + by the persistence provider. + + + + + + + + + + + + Jar file that is to be scanned for managed classes. + + + + + + + + + + + + Managed class to be included in the persistence unit and + to scan for annotations. It should be annotated + with either @Entity, @Embeddable or @MappedSuperclass. + + + + + + + + + + + + When set to true then only listed classes and jars will + be scanned for persistent classes, otherwise the + enclosing jar or directory will also be scanned. + Not applicable to Java SE persistence units. + + + + + + + + + + + + Defines whether caching is enabled for the + persistence unit if caching is supported by the + persistence provider. When set to ALL, all entities + will be cached. When set to NONE, no entities will + be cached. When set to ENABLE_SELECTIVE, only entities + specified as cacheable will be cached. When set to + DISABLE_SELECTIVE, entities specified as not cacheable + will not be cached. When not specified or when set to + UNSPECIFIED, provider defaults may apply. + + + + + + + + + + + + The validation mode to be used for the persistence unit. + + + + + + + + + + + + + A list of standard and vendor-specific properties + and hints. + + + + + + + + + A name-value pair. + + + + + + + + + + + + + + + + + + + + Name used in code to reference this persistence unit. + + + + + + + + + + + + Type of transactions used by EntityManagers from this + persistence unit. + + + + + + + + + + + + + + + + + + + public enum PersistenceUnitTransactionType {JTA, RESOURCE_LOCAL}; + + + + + + + + + + + + + + + + public enum SharedCacheMode { ALL, NONE, ENABLE_SELECTIVE, DISABLE_SELECTIVE, UNSPECIFIED}; + + + + + + + + + + + + + + + + + + + public enum ValidationMode { AUTO, CALLBACK, NONE}; + + + + + + + + + + + diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/beanvalidation/ValidatorFactory2PhaseInjectionTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/beanvalidation/ValidatorFactory2PhaseInjectionTest.java index 98430fa81d..d567c9c22f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/beanvalidation/ValidatorFactory2PhaseInjectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/beanvalidation/ValidatorFactory2PhaseInjectionTest.java @@ -17,7 +17,7 @@ import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.HibernatePersistenceProvider; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; -import org.hibernate.jpa.test.jee.OrmVersionTest; +import org.hibernate.test.jpa.xml.versions.JpaXsdVersionsTest; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.After; @@ -49,7 +49,7 @@ public class ValidatorFactory2PhaseInjectionTest extends BaseUnitTestCase { @Test public void testInjectionAvailabilityFromEmf() { EntityManagerFactoryBuilder emfb = Bootstrap.getEntityManagerFactoryBuilder( - new OrmVersionTest.PersistenceUnitInfoImpl( "my-test" ) { + new JpaXsdVersionsTest.PersistenceUnitInfoImpl( "my-test" ) { @Override public URL getPersistenceUnitRootUrl() { // just get any known url... diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/boot/NewBootProcessTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/boot/NewBootProcessTest.java index 2daba86012..47916e966c 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/boot/NewBootProcessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/boot/NewBootProcessTest.java @@ -11,7 +11,7 @@ import java.net.URL; import java.util.HashMap; import java.util.Map; -import org.hibernate.jpa.test.jee.OrmVersionTest; +import org.hibernate.test.jpa.xml.versions.JpaXsdVersionsTest; import org.hibernate.jpa.HibernatePersistenceProvider; import org.junit.Test; @@ -26,7 +26,7 @@ public class NewBootProcessTest { HibernatePersistenceProvider persistenceProvider = new HibernatePersistenceProvider(); final EntityManagerFactory emf = persistenceProvider.createContainerEntityManagerFactory( - new OrmVersionTest.PersistenceUnitInfoImpl( "my-test" ) { + new JpaXsdVersionsTest.PersistenceUnitInfoImpl( "my-test" ) { @Override public URL getPersistenceUnitRootUrl() { // just get any known url... diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/jee/OrmVersionTest.java b/hibernate-core/src/test/java/org/hibernate/test/jpa/xml/versions/JpaXsdVersionsTest.java similarity index 75% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/jee/OrmVersionTest.java rename to hibernate-core/src/test/java/org/hibernate/test/jpa/xml/versions/JpaXsdVersionsTest.java index de42aae490..a541e8a331 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/jee/OrmVersionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jpa/xml/versions/JpaXsdVersionsTest.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.jpa.test.jee; +package org.hibernate.test.jpa.xml.versions; import java.net.URL; import java.util.ArrayList; @@ -34,11 +34,11 @@ import org.junit.Test; * * @author Steve Ebersole */ -public class OrmVersionTest { +public class JpaXsdVersionsTest { @Test public void testOrm1() { PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm1-test", "1.0" ) - .addMappingFileName( "org/hibernate/jpa/test/jee/valid-orm-1.xml" ); + .addMappingFileName( "org/hibernate/test/jpa/xml/versions/valid-orm-1_0.xml" ); HibernatePersistenceProvider hp = new HibernatePersistenceProvider(); EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP ); try { @@ -50,9 +50,37 @@ public class OrmVersionTest { } @Test - public void testOrm2() { + public void testOrm20() { PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm2-test", "2.0" ) - .addMappingFileName( "org/hibernate/jpa/test/jee/valid-orm-2.xml" ); + .addMappingFileName( "org/hibernate/test/jpa/xml/versions/valid-orm-2_0.xml" ); + HibernatePersistenceProvider hp = new HibernatePersistenceProvider(); + EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP ); + try { + emf.getMetamodel().entity( Lighter.class ); // exception if not entity + } + finally { + emf.close(); + } + } + + @Test + public void testOrm21() { + PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm2-test", "2.1" ) + .addMappingFileName( "org/hibernate/test/jpa/xml/versions/valid-orm-2_1.xml" ); + HibernatePersistenceProvider hp = new HibernatePersistenceProvider(); + EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP ); + try { + emf.getMetamodel().entity( Lighter.class ); // exception if not entity + } + finally { + emf.close(); + } + } + + @Test + public void testOrm22() { + PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "orm2-test", "2.2") + .addMappingFileName( "org/hibernate/test/jpa/xml/versions/valid-orm-2_2.xml" ); HibernatePersistenceProvider hp = new HibernatePersistenceProvider(); EntityManagerFactory emf = hp.createContainerEntityManagerFactory( pui, Collections.EMPTY_MAP ); try { @@ -66,7 +94,7 @@ public class OrmVersionTest { @Test public void testInvalidOrm1() { PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( "invalid-orm1-test", "1.0" ) - .addMappingFileName( "org/hibernate/jpa/test/jee/invalid-orm-1.xml" ); + .addMappingFileName( "org/hibernate/test/jpa/xml/versions/invalid-orm-1_0.xml" ); HibernatePersistenceProvider hp = new HibernatePersistenceProvider(); EntityManagerFactory emf = null; try { @@ -94,7 +122,7 @@ public class OrmVersionTest { private final String persistenceSchemaVersion; public PersistenceUnitInfoImpl(String name) { - this( name, "2.0" ); + this( name, "2.2" ); } public PersistenceUnitInfoImpl(String name, String persistenceSchemaVersion) { diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/jee/invalid-orm-1.xml b/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/invalid-orm-1_0.xml similarity index 100% rename from hibernate-core/src/test/resources/org/hibernate/jpa/test/jee/invalid-orm-1.xml rename to hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/invalid-orm-1_0.xml diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/jee/valid-orm-1.xml b/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-1_0.xml similarity index 100% rename from hibernate-core/src/test/resources/org/hibernate/jpa/test/jee/valid-orm-1.xml rename to hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-1_0.xml diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/jee/valid-orm-2.xml b/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_0.xml similarity index 100% rename from hibernate-core/src/test/resources/org/hibernate/jpa/test/jee/valid-orm-2.xml rename to hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_0.xml diff --git a/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_1.xml b/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_1.xml new file mode 100644 index 0000000000..09b5c1010c --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_1.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + org.hibernate.jpa.test.pack.defaultpar + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_2.xml b/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_2.xml new file mode 100644 index 0000000000..b0872c6852 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-orm-2_2.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + org.hibernate.jpa.test.pack.defaultpar + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-persistence-1_0.xml b/hibernate-core/src/test/resources/org/hibernate/test/jpa/xml/versions/valid-persistence-1_0.xml new file mode 100644 index 0000000000..e69de29bb2