diff --git a/design/logger_id_ranges.adoc b/design/logger_id_ranges.adoc index 8d8e546478..5374b694ff 100644 --- a/design/logger_id_ranges.adoc +++ b/design/logger_id_ranges.adoc @@ -94,4 +94,12 @@ |90005500 |org.hibernate.sql.ast.tree.SqlAstTreeLogger +|90005501 +|90005600 +|org.hibernate.boot.jaxb.JaxbLogger + +|90005601 +|90005700 +|org.hibernate.envers.boot.EnversBootLogger + |=== diff --git a/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java b/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java index 574b710d19..e5210f4f0e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java @@ -32,7 +32,9 @@ import org.hibernate.boot.jaxb.SourceType; import org.hibernate.boot.jaxb.internal.CacheableFileXmlSource; import org.hibernate.boot.jaxb.internal.JarFileEntryXmlSource; import org.hibernate.boot.jaxb.internal.JaxpSourceXmlSource; +import org.hibernate.boot.jaxb.internal.XmlSources; import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlSource; import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistry; @@ -59,10 +61,11 @@ public class MetadataSources implements Serializable { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( MetadataSources.class ); private final ServiceRegistry serviceRegistry; + private final ClassLoaderService classLoaderService; private XmlMappingBinderAccess xmlMappingBinderAccess; - private List xmlBindings; + private List> xmlBindings; private LinkedHashSet> annotatedClasses; private LinkedHashSet annotatedClassNames; private LinkedHashSet annotatedPackages; @@ -90,11 +93,12 @@ public class MetadataSources implements Serializable { } } this.serviceRegistry = serviceRegistry; + this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); } protected static boolean isExpectedServiceRegistryType(ServiceRegistry serviceRegistry) { - return BootstrapServiceRegistry.class.isInstance( serviceRegistry ) - || StandardServiceRegistry.class.isInstance( serviceRegistry ); + return serviceRegistry instanceof BootstrapServiceRegistry + || serviceRegistry instanceof StandardServiceRegistry; } public XmlMappingBinderAccess getXmlMappingBinderAccess() { @@ -104,7 +108,7 @@ public class MetadataSources implements Serializable { return xmlMappingBinderAccess; } - public List getXmlBindings() { + public List> getXmlBindings() { return xmlBindings == null ? Collections.emptyList() : xmlBindings; } @@ -332,7 +336,9 @@ public class MetadataSources implements Serializable { * @return this (for method chaining purposes) */ public MetadataSources addResource(String name) { - getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( name ) ); + final XmlSource xmlSource = XmlSources.fromResource( name, classLoaderService ); + final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); + getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); return this; } @@ -358,7 +364,9 @@ public class MetadataSources implements Serializable { * @return this (for method chaining purposes) */ public MetadataSources addFile(File file) { - getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( file ) ); + final XmlSource xmlSource = XmlSources.fromFile( file ); + final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); + getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); return this; } @@ -372,15 +380,10 @@ public class MetadataSources implements Serializable { * @see #addCacheableFile(java.io.File) */ public MetadataSources addCacheableFile(String path) { - final Origin origin = new Origin( SourceType.FILE, path ); - addCacheableFile( origin, new File( path ) ); + addCacheableFile( new File( path ) ); return this; } - private void addCacheableFile(Origin origin, File file) { - getXmlBindingsForWrite().add( new CacheableFileXmlSource( origin, file, false ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) ); - } - /** * Add a cached mapping file. A cached file is a serialized representation of the DOM structure of a * particular mapping. It is saved from a previous call as a file with the name {@code {xmlFile}.bin} @@ -395,8 +398,9 @@ public class MetadataSources implements Serializable { * @return this (for method chaining purposes) */ public MetadataSources addCacheableFile(File file) { - final Origin origin = new Origin( SourceType.FILE, file.getName() ); - addCacheableFile( origin, file ); + final XmlSource xmlSource = XmlSources.fromCacheableFile( file ); + final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); + getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); return this; } @@ -413,9 +417,10 @@ public class MetadataSources implements Serializable { * @throws org.hibernate.type.SerializationException Indicates a problem deserializing the cached dom tree * @throws java.io.FileNotFoundException Indicates that the cached file was not found or was not usable. */ - public MetadataSources addCacheableFileStrictly(File file) throws SerializationException, FileNotFoundException { - final Origin origin = new Origin( SourceType.FILE, file.getAbsolutePath() ); - getXmlBindingsForWrite().add( new CacheableFileXmlSource( origin, file, true ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) ); + public MetadataSources addCacheableFileStrictly(File file) throws SerializationException { + final XmlSource xmlSource = XmlSources.fromCacheableFile( file, true ); + final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); + getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); return this; } @@ -427,7 +432,9 @@ public class MetadataSources implements Serializable { * @return this (for method chaining purposes) */ public MetadataSources addInputStream(InputStreamAccess xmlInputStreamAccess) { - getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( xmlInputStreamAccess ) ); + final XmlSource xmlSource = XmlSources.fromStream( xmlInputStreamAccess ); + final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); + getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); return this; } @@ -439,7 +446,9 @@ public class MetadataSources implements Serializable { * @return this (for method chaining purposes) */ public MetadataSources addInputStream(InputStream xmlInputStream) { - getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( xmlInputStream ) ); + final XmlSource xmlSource = XmlSources.fromStream( xmlInputStream ); + final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); + getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); return this; } @@ -451,7 +460,9 @@ public class MetadataSources implements Serializable { * @return this (for method chaining purposes) */ public MetadataSources addURL(URL url) { - getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( url ) ); + final XmlSource xmlSource = XmlSources.fromUrl( url ); + final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); + getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); return this; } @@ -466,8 +477,9 @@ public class MetadataSources implements Serializable { */ @Deprecated public MetadataSources addDocument(Document document) { - final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH ); - getXmlBindingsForWrite().add( new JaxpSourceXmlSource( origin, new DOMSource( document ) ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) ); + final XmlSource xmlSource = XmlSources.fromDocument( document ); + final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); + getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ); return this; } @@ -481,42 +493,15 @@ public class MetadataSources implements Serializable { * @return this (for method chaining purposes) */ public MetadataSources addJar(File jar) { - if ( LOG.isDebugEnabled() ) { - LOG.debugf( "Seeking mapping documents in jar file : %s", jar.getName() ); - } - final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() ); - try { - JarFile jarFile = new JarFile( jar ); - final boolean TRACE = LOG.isTraceEnabled(); - try { - Enumeration jarEntries = jarFile.entries(); - while ( jarEntries.hasMoreElements() ) { - final ZipEntry zipEntry = (ZipEntry) jarEntries.nextElement(); - if ( zipEntry.getName().endsWith( ".hbm.xml" ) ) { - if ( TRACE ) { - LOG.tracef( "found mapping document : %s", zipEntry.getName() ); - } - getXmlBindingsForWrite().add( - new JarFileEntryXmlSource( origin, jarFile, zipEntry ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) - ); - } - } - } - finally { - try { - jarFile.close(); - } - catch ( Exception ignore ) { - } - } - } - catch ( IOException e ) { - throw new MappingNotFoundException( e, origin ); - } + final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess(); + XmlSources.fromJar( + jar, + xmlSource -> getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) ) + ); return this; } - private List getXmlBindingsForWrite() { + private List> getXmlBindingsForWrite() { if ( xmlBindings == null ) { xmlBindings = new ArrayList<>(); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/archive/spi/InputStreamAccess.java b/hibernate-core/src/main/java/org/hibernate/boot/archive/spi/InputStreamAccess.java index 0019ea6e20..8e87c72ffa 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/archive/spi/InputStreamAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/archive/spi/InputStreamAccess.java @@ -6,7 +6,9 @@ */ package org.hibernate.boot.archive.spi; +import java.io.IOException; import java.io.InputStream; +import java.util.function.Function; /** * Contract for building InputStreams, especially in on-demand situations @@ -19,12 +21,26 @@ public interface InputStreamAccess { * * @return The backing resource name */ - public String getStreamName(); + String getStreamName(); /** * Get access to the stream. Can be called multiple times, a different stream instance should be returned each time. * * @return The stream */ - public InputStream accessInputStream(); + InputStream accessInputStream(); + + default X fromStream(Function action) { + final InputStream inputStream = accessInputStream(); + try { + return action.apply( inputStream ); + } + finally { + try { + inputStream.close(); + } + catch (IOException ignore) { + } + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java index 7f01bd29f4..669060714e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java @@ -54,18 +54,17 @@ public class BootstrapContextImpl implements BootstrapContext { private static final Logger log = Logger.getLogger( BootstrapContextImpl.class ); private final StandardServiceRegistry serviceRegistry; - - private final MutableJpaCompliance jpaCompliance; + private final MetadataBuildingOptions metadataBuildingOptions; private final TypeConfiguration typeConfiguration; + private final MutableJpaCompliance jpaCompliance; private final ClassLoaderAccessImpl classLoaderAccess; + private boolean isJpaBootstrap; + private final JavaReflectionManager hcannReflectionManager; private final ClassmateContext classmateContext; - private final MetadataBuildingOptions metadataBuildingOptions; - - private boolean isJpaBootstrap; private ScanOptions scanOptions; private ScanEnvironment scanEnvironment; @@ -76,7 +75,7 @@ public class BootstrapContextImpl implements BootstrapContext { private HashMap sqlFunctionMap; private ArrayList auxiliaryDatabaseObjectList; - private HashMap attributeConverterDescriptorMap; + private HashMap, ConverterDescriptor> attributeConverterDescriptorMap; private ArrayList cacheRegionDefinitions; private ManagedTypeRepresentationResolver representationStrategySelector; @@ -87,8 +86,7 @@ public class BootstrapContextImpl implements BootstrapContext { this.classmateContext = new ClassmateContext(); this.metadataBuildingOptions = metadataBuildingOptions; - final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); - this.classLoaderAccess = new ClassLoaderAccessImpl( classLoaderService ); + this.classLoaderAccess = new ClassLoaderAccessImpl( serviceRegistry.getService( ClassLoaderService.class ) ); this.hcannReflectionManager = generateHcannReflectionManager(); final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/JaxbLogger.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/JaxbLogger.java new file mode 100644 index 0000000000..453e307882 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/JaxbLogger.java @@ -0,0 +1,29 @@ +/* + * 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.jaxb; + +import org.jboss.logging.BasicLogger; +import org.jboss.logging.Logger; +import org.jboss.logging.annotations.MessageLogger; +import org.jboss.logging.annotations.ValidIdRange; + +/** + * @author Steve Ebersole + */ +@MessageLogger( projectCode = "HHH" ) +@ValidIdRange( min = 90005501, max = 90005600 ) +public interface JaxbLogger extends BasicLogger { + String LOGGER_NAME = "org.hibernate.orm.boot.jaxb"; + + JaxbLogger JAXB_LOGGER = Logger.getMessageLogger( + JaxbLogger.class, + LOGGER_NAME + ); + + boolean TRACE_ENABLED = JAXB_LOGGER.isTraceEnabled(); + boolean DEBUG_ENABLED = JAXB_LOGGER.isDebugEnabled(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java index e2c98a8ac1..b469a7aefa 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java @@ -37,6 +37,7 @@ public abstract class AbstractBinder implements Binder { private final LocalXmlResourceResolver xmlResourceResolver; private final boolean validateXml; + @SuppressWarnings("unused") protected AbstractBinder(ClassLoaderService classLoaderService) { this( classLoaderService, true ); } @@ -121,7 +122,6 @@ public abstract class AbstractBinder implements Binder { return staxFactory; } - @SuppressWarnings( { "UnnecessaryLocalVariable" }) private XMLInputFactory buildStaxFactory() { XMLInputFactory staxFactory = XMLInputFactory.newInstance(); staxFactory.setXMLResolver( xmlResourceResolver ); @@ -150,6 +150,7 @@ public abstract class AbstractBinder implements Binder { protected abstract Binding doBind(XMLEventReader staxEventReader, StartElement rootElementStartEvent, Origin origin); + @SuppressWarnings("unused") protected static boolean hasNamespace(StartElement startElement) { return ! "".equals( startElement.getName().getNamespaceURI() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/InputStreamAccessXmlSource.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/InputStreamAccessXmlSource.java new file mode 100644 index 0000000000..933ebe444b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/InputStreamAccessXmlSource.java @@ -0,0 +1,36 @@ +/* + * 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.jaxb.internal; + +import org.hibernate.boot.archive.spi.InputStreamAccess; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.spi.Binder; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlSource; + +/** + * @author Steve Ebersole + */ +public class InputStreamAccessXmlSource extends XmlSource { + private final InputStreamAccess inputStreamAccess; + + public InputStreamAccessXmlSource(Origin origin, InputStreamAccess inputStreamAccess) { + super( origin ); + this.inputStreamAccess = inputStreamAccess; + } + + @Override + public Binding doBind(Binder binder) { + return doBind( binder, inputStreamAccess, getOrigin() ); + } + + public static Binding doBind(Binder binder, InputStreamAccess inputStreamAccess, Origin origin) { + return inputStreamAccess.fromStream( + inputStream -> binder.bind( inputStream, origin ) + ); + } +} 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 8dd1e96b1e..0f38e33e2a 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 @@ -41,6 +41,7 @@ public class MappingBinder extends AbstractBinder { private JAXBContext hbmJaxbContext; + @SuppressWarnings("unused") public MappingBinder(ClassLoaderService classLoaderService) { this( classLoaderService, true ); } @@ -50,7 +51,7 @@ public class MappingBinder extends AbstractBinder { } @Override - protected Binding doBind( + protected Binding doBind( XMLEventReader staxEventReader, StartElement rootElementStartEvent, Origin origin) { @@ -98,7 +99,7 @@ public class MappingBinder extends AbstractBinder { // are trying to read has comments this process will blow up. So we // override that to add that support as best we can XMLEvent event = reader.peek(); - if ( javax.xml.stream.events.Comment.class.isInstance( event ) ) { + if ( event instanceof javax.xml.stream.events.Comment ) { return super.readComment( reader ); } return super.readNode( reader ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/UrlXmlSource.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/UrlXmlSource.java index 9724d58250..9005eb193f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/UrlXmlSource.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/UrlXmlSource.java @@ -14,6 +14,7 @@ import java.net.UnknownHostException; import org.hibernate.boot.MappingException; import org.hibernate.boot.MappingNotFoundException; import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.SourceType; import org.hibernate.boot.jaxb.spi.Binder; import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.jaxb.spi.XmlSource; @@ -22,6 +23,7 @@ import org.hibernate.boot.jaxb.spi.XmlSource; * @author Steve Ebersole */ public class UrlXmlSource extends XmlSource { + private final URL url; public UrlXmlSource(Origin origin, URL url) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/XmlSources.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/XmlSources.java new file mode 100644 index 0000000000..1438a0c74b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/XmlSources.java @@ -0,0 +1,137 @@ +/* + * 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.jaxb.internal; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.function.Consumer; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import javax.xml.transform.dom.DOMSource; + +import org.hibernate.boot.MappingNotFoundException; +import org.hibernate.boot.archive.spi.InputStreamAccess; +import org.hibernate.boot.jaxb.JaxbLogger; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.SourceType; +import org.hibernate.boot.jaxb.spi.XmlSource; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; + +import org.w3c.dom.Document; + +/** + * Helper for building and handling {@link org.hibernate.boot.jaxb.spi.XmlSource} references + * + * @author Steve Ebersole + */ +public class XmlSources { + /** + * Create an {@link XmlSource} from a named resource + */ + public static XmlSource fromResource(String resourceName, ClassLoaderService classLoaderService) { + JaxbLogger.JAXB_LOGGER.tracef( "reading mappings from resource : %s", resourceName ); + + final Origin origin = new Origin( SourceType.RESOURCE, resourceName ); + final URL url = classLoaderService.locateResource( resourceName ); + if ( url == null ) { + throw new MappingNotFoundException( origin ); + } + + return new UrlXmlSource( origin, url ); + } + + /** + * Create an {@link XmlSource} from a URL + */ + public static XmlSource fromUrl(URL url) { + final String urlExternalForm = url.toExternalForm(); + JaxbLogger.JAXB_LOGGER.tracef( "Reading mapping document from URL : %s", urlExternalForm ); + + final Origin origin = new Origin( SourceType.URL, urlExternalForm ); + return new UrlXmlSource( origin, url ); + } + + public static XmlSource fromFile(File file) { + final String filePath = file.getPath(); + JaxbLogger.JAXB_LOGGER.tracef( "reading mappings from file : %s", filePath ); + + final Origin origin = new Origin( SourceType.FILE, filePath ); + + if ( !file.exists() ) { + throw new MappingNotFoundException( origin ); + } + + return new FileXmlSource( origin, file ); + } + + public static XmlSource fromCacheableFile(File file) { + return fromCacheableFile( file, false ); + } + + public static XmlSource fromCacheableFile(File file, boolean strict) { + final String filePath = file.getPath(); + JaxbLogger.JAXB_LOGGER.tracef( "reading mappings from cacheable-file : %s", filePath ); + + final Origin origin = new Origin( SourceType.FILE, filePath ); + return new CacheableFileXmlSource( origin, file, true ); + } + + public static XmlSource fromStream(InputStreamAccess inputStreamAccess) { + final String streamName = inputStreamAccess.getStreamName(); + JaxbLogger.JAXB_LOGGER.tracef( "reading mappings from InputStreamAccess : %s", streamName ); + + final Origin origin = new Origin( SourceType.INPUT_STREAM, streamName ); + return new InputStreamAccessXmlSource( origin, inputStreamAccess ); + } + + public static XmlSource fromStream(InputStream inputStream) { + JaxbLogger.JAXB_LOGGER.trace( "reading mappings from InputStream" ); + + final Origin origin = new Origin( SourceType.INPUT_STREAM, null ); + return new InputStreamXmlSource( origin, inputStream, false ); + } + + public static XmlSource fromDocument(Document document) { + JaxbLogger.JAXB_LOGGER.trace( "reading mappings from DOM" ); + final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH ); + return new JaxpSourceXmlSource( origin, new DOMSource( document ) ); + } + + public static void fromJar(File jar, Consumer consumer) { + JaxbLogger.JAXB_LOGGER.tracef( "Seeking mapping documents in jar file : %s", jar.getName() ); + + final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() ); + + try { + final JarFile jarFile = new JarFile( jar ); + + try { + final Enumeration entries = jarFile.entries(); + while ( entries.hasMoreElements() ) { + final JarEntry jarEntry = entries.nextElement(); + if ( jarEntry.getName().endsWith( ".hbm.xml" ) ) { + JaxbLogger.JAXB_LOGGER.tracef( "Found hbm.xml mapping in jar : %s", jarEntry.getName() ); + consumer.accept( new JarFileEntryXmlSource( origin, jarFile, jarEntry ) ); + } + } + } + finally { + try { + jarFile.close(); + } + catch ( Exception ignore ) { + } + } + } + catch ( IOException e ) { + throw new MappingNotFoundException( e, origin ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/EntityHierarchySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/EntityHierarchySourceImpl.java index 813c9fe2ab..3e086db2b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/EntityHierarchySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/EntityHierarchySourceImpl.java @@ -91,14 +91,29 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource { else { // if we get here, we should have a composite identifier. Just need // to determine if it is aggregated, or non-aggregated... - if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getName() ) ) { - if ( rootEntitySource.jaxbEntityMapping().getCompositeId().isMapped() - && StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getClazz() ) ) { + + if ( rootEntitySource.jaxbEntityMapping().getCompositeId().isMapped() ) { + if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getClazz() ) ) { throw new MappingException( "mapped composite identifier must name component class to use.", rootEntitySource.origin() ); } + } + + if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getClazz() ) ) { + if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getName() ) ) { + throw new MappingException( + "dynamic composite-id must specify name", + rootEntitySource.origin() + ); + } + + // we have a non-aggregated id without an IdClass + return new IdentifierSourceNonAggregatedCompositeImpl( rootEntitySource ); + } + else if ( rootEntitySource.jaxbEntityMapping().getCompositeId().isMapped() ) { + // we have a non-aggregated id with an IdClass return new IdentifierSourceNonAggregatedCompositeImpl( rootEntitySource ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/BootstrapContext.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/BootstrapContext.java index 732004bb4e..6aec5582b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/BootstrapContext.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/BootstrapContext.java @@ -9,6 +9,9 @@ package org.hibernate.boot.spi; import java.util.Collection; import java.util.Map; +import javax.xml.bind.JAXBContext; +import javax.xml.stream.XMLInputFactory; + import org.hibernate.Incubating; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.boot.CacheRegionDefinition; @@ -162,6 +165,8 @@ public interface BootstrapContext { */ Collection getCacheRegionDefinitions(); + ManagedTypeRepresentationResolver getRepresentationStrategySelector(); + /** * Releases the "bootstrap only" resources held by this BootstrapContext. *

@@ -172,6 +177,4 @@ public interface BootstrapContext { * @todo verify this ^^ */ void release(); - - ManagedTypeRepresentationResolver getRepresentationStrategySelector(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java index a0f4b37c1f..ca8f097c04 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java @@ -21,16 +21,18 @@ import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.Type; import org.hibernate.Internal; +import org.hibernate.MappingException; +import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.annotations.common.AssertionFailure; import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.HEMLogging; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.mapping.Component; -import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.model.domain.AbstractIdentifiableType; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; @@ -43,10 +45,9 @@ import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; import org.hibernate.metamodel.model.domain.internal.AttributeContainer; import org.hibernate.metamodel.model.domain.internal.BasicTypeImpl; -import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl; import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl; import org.hibernate.metamodel.model.domain.internal.MappedSuperclassTypeImpl; -import org.hibernate.metamodel.MappingMetamodel; +import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; import org.hibernate.type.spi.TypeConfiguration; @@ -358,7 +359,7 @@ public class MetadataContext { // 2) register the part (mapping role) // 3) somehow get the mapping role "into" the part (setter, ?) - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) private void applyIdMetadata(PersistentClass persistentClass, IdentifiableDomainType identifiableType) { if ( persistentClass.hasIdentifierProperty() ) { final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty(); @@ -371,31 +372,38 @@ public class MetadataContext { ( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdAttribute( idAttribute ); } } - else if ( persistentClass.hasIdentifierMapper() ) { - @SuppressWarnings("unchecked") - final Iterator propertyIterator = persistentClass.getIdentifierMapper().getPropertyIterator(); - final Set> idClassAttributes = (Set>) buildIdClassAttributes( - identifiableType, - propertyIterator - ); - ( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdClassAttributes( idClassAttributes ); - } else { - final KeyValue value = persistentClass.getIdentifier(); - if ( value instanceof Component ) { - final Component component = (Component) value; - if ( component.getPropertySpan() > 1 ) { - //FIXME we are an Hibernate embedded id (ie not type) - } - else { - //FIXME take care of declared vs non declared property - ( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdAttribute( - attributeFactory.buildIdAttribute( - identifiableType, - (Property) component.getPropertyIterator().next() - ) - ); - } + // we have a non-aggregated composite-id + + //noinspection RedundantClassCall + if ( ! Component.class.isInstance( persistentClass.getIdentifier() ) ) { + throw new MappingException( "Expecting Component for id mapping with no id-attribute" ); + } + + // Handle the actual id-attributes + final Component cidValue = (Component) persistentClass.getIdentifier(); + final Iterator cidPropertyItr = cidValue.getPropertyIterator(); + final Set> idAttributes = new HashSet<>( cidValue.getPropertySpan() ); + + while ( cidPropertyItr.hasNext() ) { + final Property cidSubProperty = cidPropertyItr.next(); + + final SingularPersistentAttribute cidSubAttr = attributeFactory.buildIdAttribute( + identifiableType, + cidSubProperty + ); + + idAttributes.add( cidSubAttr ); + } + + ( ( AttributeContainer) identifiableType ).getInFlightAccess().applyNonAggregatedIdAttributes( idAttributes ); + + + // see if it also has an IdClass (identifier-mapper) + final Component idClass = persistentClass.getIdentifierMapper(); + if ( idClass != null ) { + // todo (6.0) : handle `@IdClass` + throw new NotYetImplementedFor6Exception( "Support for @IdClass not yet implemented" ); } } } @@ -419,7 +427,7 @@ public class MetadataContext { propertyIterator ); //noinspection unchecked - ( ( AttributeContainer) jpaMappingType ).getInFlightAccess().applyIdClassAttributes( attributes ); + ( ( AttributeContainer) jpaMappingType ).getInFlightAccess().applyIdClassAttributes( attributes ); } } @@ -427,7 +435,7 @@ public class MetadataContext { final Property declaredVersion = persistentClass.getDeclaredVersion(); if ( declaredVersion != null ) { //noinspection unchecked - ( ( AttributeContainer) jpaEntityType ).getInFlightAccess().applyVersionAttribute( + ( ( AttributeContainer) jpaEntityType ).getInFlightAccess().applyVersionAttribute( attributeFactory.buildVersionAttribute( jpaEntityType, declaredVersion ) ); } @@ -437,7 +445,7 @@ public class MetadataContext { final Property declaredVersion = mappingType.getDeclaredVersion(); if ( declaredVersion != null ) { //noinspection unchecked - ( ( AttributeContainer) jpaMappingType ).getInFlightAccess().applyVersionAttribute( + ( ( AttributeContainer) jpaMappingType ).getInFlightAccess().applyVersionAttribute( attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardManagedTypeRepresentationResolver.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardManagedTypeRepresentationResolver.java index 416339dc84..10bdceeac9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardManagedTypeRepresentationResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardManagedTypeRepresentationResolver.java @@ -62,7 +62,7 @@ public class StandardManagedTypeRepresentationResolver implements ManagedTypeRep // RepresentationMode representation = bootDescriptor.getExplicitRepresentationMode(); RepresentationMode representation = null; if ( representation == null ) { - if ( bootDescriptor.getComponentClass() == null ) { + if ( bootDescriptor.getComponentClassName() == null ) { representation = RepresentationMode.MAP; } else { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java index ef627f4a5a..d73f3b493f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java @@ -81,6 +81,36 @@ public class EmbeddableMappingType implements ManagedMappingType { return mappingType; } + public static EmbeddableMappingType from( + Component bootDescriptor, + CompositeType compositeType, + NavigableRole embeddedRole, + Function embeddedPartBuilder, + MappingModelCreationProcess creationProcess) { + final RuntimeModelCreationContext creationContext = creationProcess.getCreationContext(); + + final EmbeddableRepresentationStrategy representationStrategy = creationContext.getBootstrapContext() + .getRepresentationStrategySelector() + .resolveStrategy( bootDescriptor, creationContext ); + + final EmbeddableMappingType mappingType = new EmbeddableMappingType( + bootDescriptor, + representationStrategy, + embeddedPartBuilder, + creationContext.getSessionFactory() + ); + + creationProcess.registerInitializationCallback( + () -> mappingType.finishInitialization( + bootDescriptor, + compositeType, + creationProcess + ) + ); + + return mappingType; + } + private final JavaTypeDescriptor embeddableJtd; private final EmbeddableRepresentationStrategy representationStrategy; @@ -90,6 +120,7 @@ public class EmbeddableMappingType implements ManagedMappingType { private final Map attributeMappings = new LinkedHashMap<>(); private final EmbeddableValuedModelPart valueMapping; + private NavigableRole embeddedRole; private final boolean createEmptyCompositesEnabled; @@ -139,6 +170,7 @@ public class EmbeddableMappingType implements ManagedMappingType { bootPropertyDescriptor.getName(), MappingModelCreationHelper.buildBasicAttributeMapping( bootPropertyDescriptor.getName(), + valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ), attributeIndex, bootPropertyDescriptor, this, @@ -194,6 +226,7 @@ public class EmbeddableMappingType implements ManagedMappingType { else if ( subtype instanceof EntityType ) { final SingularAssociationAttributeMapping singularAssociationAttributeMapping = MappingModelCreationHelper.buildSingularAssociationAttributeMapping( bootPropertyDescriptor.getName(), + valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ), attributeIndex, bootPropertyDescriptor, entityPersister, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedSingularAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedSingularAttributeMapping.java index d687695068..2e1cb85666 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedSingularAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedSingularAttributeMapping.java @@ -59,6 +59,7 @@ public class BasicValuedSingularAttributeMapping @SuppressWarnings("WeakerAccess") public BasicValuedSingularAttributeMapping( String attributeName, + NavigableRole navigableRole, int stateArrayPosition, StateArrayContributorMetadataAccess attributeMetadataAccess, FetchStrategy mappedFetchStrategy, @@ -69,7 +70,7 @@ public class BasicValuedSingularAttributeMapping ManagedMappingType declaringType, PropertyAccess propertyAccess) { super( attributeName, stateArrayPosition, attributeMetadataAccess, mappedFetchStrategy, declaringType, propertyAccess ); - this.navigableRole = declaringType.getNavigableRole().append( attributeName ); + this.navigableRole = navigableRole; this.tableExpression = tableExpression; this.mappedColumnExpression = mappedColumnExpression; this.valueConverter = valueConverter; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java index ea67390d1f..e29081c24b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java @@ -12,8 +12,10 @@ import java.util.Iterator; import java.util.List; import java.util.SortedMap; import java.util.SortedSet; +import java.util.function.BiConsumer; import org.hibernate.FetchMode; +import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.collection.internal.StandardArraySemantics; @@ -27,6 +29,7 @@ import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.CascadeStyle; +import org.hibernate.engine.spi.CascadeStyles; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; @@ -63,16 +66,20 @@ import org.hibernate.metamodel.mapping.SingularAttributeMapping; import org.hibernate.metamodel.mapping.StateArrayContributorMetadata; import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; +import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.SQLLoadableCollection; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.walking.internal.FetchStrategyHelper; +import org.hibernate.property.access.internal.PropertyAccessStrategyMapImpl; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.sql.ast.spi.SqlAliasStemHelper; +import org.hibernate.type.AnyType; import org.hibernate.type.AssociationType; import org.hibernate.type.BasicType; +import org.hibernate.type.CollectionType; import org.hibernate.type.CompositeType; import org.hibernate.type.EntityType; import org.hibernate.type.ForeignKeyDirection; @@ -116,10 +123,10 @@ public class MappingModelCreationHelper { final EmbeddableMappingType embeddableMappingType = EmbeddableMappingType.from( (Component) bootProperty.getValue(), cidType, - attributeMappingType -> new EmbeddedIdentifierMappingImpl( + embeddable -> new EmbeddedIdentifierMappingImpl( entityPersister, attributeName, - attributeMappingType, + embeddable, attributeMetadataAccess, propertyAccess, rootTableName, @@ -135,20 +142,119 @@ public class MappingModelCreationHelper { public static CompositeIdentifierMapping buildNonEncapsulatedCompositeIdentifierMapping( EntityPersister entityPersister, - List idAttributeMappings, + String rootTableName, + String[] rootTableKeyColumnNames, CompositeType cidType, PersistentClass bootEntityDescriptor, + BiConsumer idSubAttributeConsumer, MappingModelCreationProcess creationProcess) { - + final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory(); final Component bootCompositeDescriptor = (Component) bootEntityDescriptor.getIdentifier(); - return new NonAggregatedIdentifierMappingImpl( - entityPersister, - idAttributeMappings, + final PropertyAccess propertyAccess = PropertyAccessStrategyMapImpl.INSTANCE.buildPropertyAccess( + null, + EntityIdentifierMapping.ROLE_LOCAL_NAME + ); + + final StateArrayContributorMetadataAccess attributeMetadataAccess = getStateArrayContributorMetadataAccess( + propertyAccess + ); + + final EmbeddableMappingType embeddableMappingType = EmbeddableMappingType.from( bootCompositeDescriptor, cidType, + attributeMappingType -> { + final Component bootIdDescriptor = (Component) bootEntityDescriptor.getIdentifier(); + + final List idAttributeMappings = new ArrayList<>( bootIdDescriptor.getPropertySpan() ); + + //noinspection unchecked + final Iterator bootIdSubPropertyItr = bootIdDescriptor.getPropertyIterator(); + int columnsConsumedSoFar = 0; + + while ( bootIdSubPropertyItr.hasNext() ) { + final Property bootIdSubProperty = bootIdSubPropertyItr.next(); + final Type idSubPropertyType = bootIdSubProperty.getType(); + + if ( idSubPropertyType instanceof AnyType ) { + throw new HibernateException( + "AnyType property `" + bootEntityDescriptor.getEntityName() + "#" + bootIdSubProperty.getName() + + "` cannot be used as part of entity identifier " + ); + } + + if ( idSubPropertyType instanceof CollectionType ) { + throw new HibernateException( + "Plural property `" + bootEntityDescriptor.getEntityName() + "#" + bootIdSubProperty.getName() + + "` cannot be used as part of entity identifier " + ); + } + + final SingularAttributeMapping idSubAttribute; + + if ( idSubPropertyType instanceof BasicType ) { + //noinspection rawtypes + idSubAttribute = buildBasicAttributeMapping( + bootIdSubProperty.getName(), + entityPersister.getNavigableRole().append( bootIdSubProperty.getName() ), + idAttributeMappings.size(), + bootIdSubProperty, + attributeMappingType, + (BasicType) idSubPropertyType, + rootTableName, + rootTableKeyColumnNames[columnsConsumedSoFar], + entityPersister.getRepresentationStrategy().resolvePropertyAccess( bootIdSubProperty ), + CascadeStyles.ALL, + creationProcess + ); + columnsConsumedSoFar++; + } + else if ( idSubPropertyType instanceof CompositeType ) { + // nested composite + throw new NotYetImplementedFor6Exception(); + } + else if ( idSubPropertyType instanceof EntityType ) { + // key-many-to-one + final EntityType keyManyToOnePropertyType = (EntityType) idSubPropertyType; + + idSubAttribute = buildSingularAssociationAttributeMapping( + bootIdSubProperty.getName(), + entityPersister.getNavigableRole().append( EntityIdentifierMapping.ROLE_LOCAL_NAME ), + idAttributeMappings.size(), + bootIdSubProperty, + attributeMappingType, + keyManyToOnePropertyType, + entityPersister.getRepresentationStrategy().resolvePropertyAccess( bootIdSubProperty ), + CascadeStyles.ALL, + creationProcess + ); + + columnsConsumedSoFar += keyManyToOnePropertyType.getColumnSpan( sessionFactory ); + } + else { + throw new UnsupportedOperationException(); + } + + idAttributeMappings.add( idSubAttribute ); + idSubAttributeConsumer.accept( idSubAttribute.getAttributeName(), idSubAttribute ); + } + + return new NonAggregatedIdentifierMappingImpl( + attributeMappingType, + entityPersister, + idAttributeMappings, + attributeMetadataAccess, + rootTableName, + rootTableKeyColumnNames, + bootCompositeDescriptor, + bootEntityDescriptor.getDeclaredIdentifierMapper(), + creationProcess + ); + }, creationProcess ); + + return (CompositeIdentifierMapping) embeddableMappingType.getEmbeddedValueMapping(); } @@ -158,6 +264,7 @@ public class MappingModelCreationHelper { @SuppressWarnings("rawtypes") public static BasicValuedSingularAttributeMapping buildBasicAttributeMapping( String attrName, + NavigableRole navigableRole, int stateArrayPosition, Property bootProperty, ManagedMappingType declaringType, @@ -240,6 +347,7 @@ public class MappingModelCreationHelper { return new BasicValuedSingularAttributeMapping( attrName, + navigableRole, stateArrayPosition, attributeMetadataAccess, fetchStrategy, @@ -254,6 +362,7 @@ public class MappingModelCreationHelper { else { return new BasicValuedSingularAttributeMapping( attrName, + navigableRole, stateArrayPosition, attributeMetadataAccess, fetchStrategy, @@ -1141,6 +1250,7 @@ public class MappingModelCreationHelper { public static SingularAssociationAttributeMapping buildSingularAssociationAttributeMapping( String attrName, + NavigableRole navigableRole, int stateArrayPosition, Property bootProperty, ManagedMappingType declaringType, @@ -1183,6 +1293,7 @@ public class MappingModelCreationHelper { final SingularAssociationAttributeMapping attributeMapping = new SingularAssociationAttributeMapping( attrName, + navigableRole, stateArrayPosition, (ToOne) bootProperty.getValue(), stateArrayContributorMetadataAccess, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java index 3d14c5cebf..3ea7ad7b5e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java @@ -6,21 +6,44 @@ */ package org.hibernate.metamodel.mapping.internal; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.function.Consumer; +import org.hibernate.LockMode; import org.hibernate.NotYetImplementedFor6Exception; +import org.hibernate.engine.FetchStrategy; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.mapping.Component; import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; +import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.SingularAttributeMapping; +import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.query.NavigablePath; +import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; +import org.hibernate.sql.ast.Clause; +import org.hibernate.sql.ast.SqlAstJoinType; +import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator; +import org.hibernate.sql.ast.spi.SqlAstCreationContext; +import org.hibernate.sql.ast.spi.SqlAstCreationState; +import org.hibernate.sql.ast.spi.SqlExpressionResolver; +import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.sql.ast.tree.from.CompositeTableGroup; import org.hibernate.sql.ast.tree.from.TableGroup; +import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; +import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl; +import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl; import org.hibernate.type.CompositeType; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -33,23 +56,37 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; * * @author Steve Ebersole */ -public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMapping { +public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMapping, EmbeddableValuedFetchable { + private final EmbeddableMappingType embeddableDescriptor; private final NavigableRole navigableRole; private final EntityMappingType entityMapping; private final List idAttributeMappings; + private final StateArrayContributorMetadataAccess attributeMetadataAccess; + private final String rootTableName; + private final List idColumnNames; + public NonAggregatedIdentifierMappingImpl( + EmbeddableMappingType embeddableDescriptor, EntityMappingType entityMapping, List idAttributeMappings, - Component bootIdDescriptor, - CompositeType cidType, + StateArrayContributorMetadataAccess attributeMetadataAccess, + String rootTableName, + String[] rootTableKeyColumnNames, + Component bootCidDescriptor, + Component bootIdClassDescriptor, MappingModelCreationProcess creationProcess) { // todo (6.0) : handle MapsId and IdClass - // todo (6.0) : implement SQL AST apis (DomainResult, e.g.) - this.navigableRole = entityMapping.getNavigableRole().appendContainer( EntityIdentifierMapping.ROLE_LOCAL_NAME ); + + this.embeddableDescriptor = embeddableDescriptor; this.entityMapping = entityMapping; this.idAttributeMappings = idAttributeMappings; + this.attributeMetadataAccess = attributeMetadataAccess; + this.rootTableName = rootTableName; + this.idColumnNames = Arrays.asList( rootTableKeyColumnNames ); + + this.navigableRole = entityMapping.getNavigableRole().appendContainer( EntityIdentifierMapping.ROLE_LOCAL_NAME ); } @Override @@ -68,8 +105,8 @@ public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMa } @Override - public EntityMappingType getMappedTypeDescriptor() { - return entityMapping; + public EmbeddableMappingType getMappedTypeDescriptor() { + return embeddableDescriptor; } @Override @@ -103,8 +140,12 @@ public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMa TableGroup tableGroup, String resultVariable, DomainResultCreationState creationState) { - // we will need a specialized impl for this - throw new NotYetImplementedFor6Exception( getClass() ); + return new EmbeddableResultImpl<>( + navigablePath, + this, + resultVariable, + creationState + ); } @Override @@ -112,4 +153,109 @@ public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMa return entityMapping; } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // EmbeddableValuedFetchable + + + @Override + public EmbeddableMappingType getEmbeddableTypeDescriptor() { + return getMappedTypeDescriptor(); + } + + @Override + public String getContainingTableExpression() { + return rootTableName; + } + + @Override + public List getMappedColumnExpressions() { + return idColumnNames; + } + + @Override + public SingularAttributeMapping getParentInjectionAttributeMapping() { + return null; + } + + @Override + public Expression toSqlExpression( + TableGroup tableGroup, + Clause clause, + SqmToSqlAstConverter walker, + SqlAstCreationState sqlAstCreationState) { + return null; + } + + @Override + public TableGroupJoin createTableGroupJoin( + NavigablePath navigablePath, + TableGroup lhs, + String explicitSourceAlias, + SqlAstJoinType sqlAstJoinType, + LockMode lockMode, + SqlAliasBaseGenerator aliasBaseGenerator, + SqlExpressionResolver sqlExpressionResolver, + SqlAstCreationContext creationContext) { + final CompositeTableGroup compositeTableGroup = new CompositeTableGroup( + navigablePath, + this, + lhs + ); + + final TableGroupJoin join = new TableGroupJoin( navigablePath, SqlAstJoinType.LEFT, compositeTableGroup, null ); + lhs.addTableGroupJoin( join ); + + return join; + } + + @Override + public String getSqlAliasStem() { + return "id"; + } + + @Override + public ModelPart findSubPart(String name, EntityMappingType treatTargetType) { + return getMappedTypeDescriptor().findSubPart( name, treatTargetType ); + } + + @Override + public void visitSubParts(Consumer consumer, EntityMappingType treatTargetType) { + getMappedTypeDescriptor().visitSubParts( consumer, treatTargetType ); + } + + @Override + public String getFetchableName() { + return "id"; + } + + @Override + public FetchStrategy getMappedFetchStrategy() { + return null; + } + + @Override + public Fetch generateFetch( + FetchParent fetchParent, + NavigablePath fetchablePath, + FetchTiming fetchTiming, + boolean selected, + LockMode lockMode, + String resultVariable, + DomainResultCreationState creationState) { + return new EmbeddableFetchImpl( + fetchablePath, + this, + fetchParent, + fetchTiming, + selected, + attributeMetadataAccess.resolveAttributeMetadata( null ).isNullable(), + creationState + ); + } + + @Override + public int getNumberOfFetchables() { + return idAttributeMappings.size(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SingularAssociationAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SingularAssociationAttributeMapping.java index afe29bdef0..09ed9ed030 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SingularAssociationAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SingularAssociationAttributeMapping.java @@ -81,6 +81,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu public SingularAssociationAttributeMapping( String name, + NavigableRole navigableRole, int stateArrayPosition, ToOne bootValue, StateArrayContributorMetadataAccess attributeMetadataAccess, @@ -124,7 +125,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu cardinality = Cardinality.ONE_TO_ONE; } - this.navigableRole = declaringType.getNavigableRole().appendContainer( name ); + this.navigableRole = navigableRole; } public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java index 8e653e9f46..fff0d058c9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java @@ -41,8 +41,10 @@ public abstract class AbstractIdentifiableType private final boolean hasIdentifierProperty; private final boolean hasIdClass; + private SingularPersistentAttribute id; - private Set> idClassAttributes; + private Set> nonAggregatedIdAttributes; + private SqmPathSource identifierDescriptor; @@ -221,8 +223,8 @@ public abstract class AbstractIdentifiableType @Override @SuppressWarnings("unchecked") public void visitIdClassAttributes(Consumer> attributeConsumer) { - if ( idClassAttributes != null ) { - idClassAttributes.forEach( attributeConsumer ); + if ( nonAggregatedIdAttributes != null ) { + nonAggregatedIdAttributes.forEach( attributeConsumer ); } else if ( getSuperType() != null ) { getSuperType().visitIdClassAttributes( (Consumer) attributeConsumer ); @@ -305,6 +307,7 @@ public abstract class AbstractIdentifiableType return versionAttribute; } + @SuppressWarnings({"rawtypes", "unchecked"}) private class InFlightAccessImpl extends AbstractManagedType.InFlightAccessImpl { private final AbstractManagedType.InFlightAccess managedTypeAccess; @@ -313,23 +316,28 @@ public abstract class AbstractIdentifiableType } @Override - @SuppressWarnings("unchecked") public void applyIdAttribute(SingularPersistentAttribute idAttribute) { AbstractIdentifiableType.this.id = idAttribute; managedTypeAccess.addAttribute( idAttribute ); } @Override - @SuppressWarnings("unchecked") - public void applyIdClassAttributes(Set idClassAttributes) { - for ( SingularAttribute idClassAttribute : ( (Set) idClassAttributes ) ) { - if ( AbstractIdentifiableType.this == idClassAttribute.getDeclaringType() ) { - @SuppressWarnings({ "unchecked" }) - SingularPersistentAttribute declaredAttribute = (SingularPersistentAttribute) idClassAttribute; - addAttribute( declaredAttribute ); + public void applyNonAggregatedIdAttributes(Set idAttributes) { + if ( AbstractIdentifiableType.this.id != null ) { + throw new IllegalArgumentException( "`AbstractIdentifiableType#id` already set on call to `#applyNonAggregatedIdAttribute`" ); + } + + if ( nonAggregatedIdAttributes != null ) { + throw new IllegalStateException( "Non-aggregated id attributes were already set" ); + } + + for ( SingularPersistentAttribute idAttribute : (Set) idAttributes ) { + if ( AbstractIdentifiableType.this == idAttribute.getDeclaringType() ) { + addAttribute( idAttribute ); } } - AbstractIdentifiableType.this.idClassAttributes = idClassAttributes; + + AbstractIdentifiableType.this.nonAggregatedIdAttributes = (Set) idAttributes; } @Override @@ -383,7 +391,7 @@ public abstract class AbstractIdentifiableType ); } } - else if ( idClassAttributes != null && ! idClassAttributes.isEmpty() ) { + else if ( nonAggregatedIdAttributes != null && ! nonAggregatedIdAttributes.isEmpty() ) { // non-aggregate composite id return new NonAggregatedCompositeSqmPathSource( EntityIdentifierMapping.ROLE_LOCAL_NAME, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeContainer.java index 8813d0582a..ba4825e777 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeContainer.java @@ -6,6 +6,7 @@ */ package org.hibernate.metamodel.model.domain.internal; +import java.util.List; import java.util.Set; import org.hibernate.metamodel.model.domain.PersistentAttribute; @@ -23,12 +24,27 @@ public interface AttributeContainer { interface InFlightAccess { void addAttribute(PersistentAttribute attribute); + /** + * Callback used when we have a singular id attribute of some form - either a simple id + * or an aggregated composite id ({@link javax.persistence.EmbeddedId + */ default void applyIdAttribute(SingularPersistentAttribute idAttribute) { throw new UnsupportedOperationException( "AttributeContainer [" + getClass().getName() + "] does not support identifiers" ); } + default void applyNonAggregatedIdAttributes(Set> idAttributes) { + throw new UnsupportedOperationException( + "AttributeContainer [" + getClass().getName() + "] does not support identifiers" + ); + } + + /** + * todo (6.0) : we still need to implement this properly and the contract may change + * - specifically I am not certain we will be able to re-use `SingularPersistentAttribute` + * because of its dependence on declaring-type, etc that we may not be able to do + */ default void applyIdClassAttributes(Set> idClassAttributes) { throw new UnsupportedOperationException( "AttributeContainer [" + getClass().getName() + "] does not support identifiers" diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java index f01a19db35..f0848e2b58 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java @@ -50,6 +50,7 @@ import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.java.spi.DynamicModelJtd; import org.hibernate.type.spi.TypeConfiguration; /** @@ -515,12 +516,14 @@ public class JpaMetamodelImpl implements JpaMetamodel { PersistentClass persistentClass, MetadataContext context, TypeConfiguration typeConfiguration) { - final Class javaType = persistentClass.getMappedClass(); context.pushEntityWorkedOn( persistentClass ); + final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass(); + IdentifiableDomainType superType = superMappedSuperclass == null ? null : locateOrBuildMappedSuperclassType( superMappedSuperclass, context, typeConfiguration ); + //no mappedSuperclass, check for a super entity if ( superType == null ) { final PersistentClass superPersistentClass = persistentClass.getSuperclass(); @@ -529,17 +532,28 @@ public class JpaMetamodelImpl implements JpaMetamodel { : locateOrBuildEntityType( superPersistentClass, context, typeConfiguration ); } - final JavaTypeDescriptor javaTypeDescriptor = context.getTypeConfiguration() - .getJavaTypeDescriptorRegistry() - .getDescriptor( javaType ); - final EntityTypeImpl entityType = new EntityTypeImpl( + final Class javaType = persistentClass.getMappedClass(); + final JavaTypeDescriptor javaTypeDescriptor; + if ( javaType == null || Map.class.isAssignableFrom( javaType ) ) { + // dynamic map + javaTypeDescriptor = new DynamicModelJtd(); + } + else { + javaTypeDescriptor = context.getTypeConfiguration() + .getJavaTypeDescriptorRegistry() + .getDescriptor( javaType ); + } + + final EntityTypeImpl entityType = new EntityTypeImpl( javaTypeDescriptor, superType, persistentClass, this ); + context.registerEntityType( persistentClass, entityType ); context.popEntityWorkedOn( persistentClass ); + return entityType; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 20b6e379e8..475b07f8f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -6039,83 +6039,17 @@ public abstract class AbstractEntityPersister private EntityIdentifierMapping generateNonEncapsulatedCompositeIdentifierMapping( MappingModelCreationProcess creationProcess, - PersistentClass bootEntityDescriptor, CompositeType cidType) { - // process all of the defined "id attributes" because they are declared on the entity - final Component bootIdDescriptor = (Component) bootEntityDescriptor.getIdentifier(); - final List idAttributeMappings = new ArrayList<>( bootIdDescriptor.getPropertySpan() ); - int columnsConsumedSoFar = 0; - - if ( attributeMappings == null ) { - attributeMappings = new ArrayList<>( - bootEntityDescriptor.getPropertyClosureSpan() + bootIdDescriptor.getPropertySpan() - ); - - final Iterator bootPropertyIterator = bootIdDescriptor.getPropertyIterator(); - while ( bootPropertyIterator.hasNext() ) { - final Property bootIdProperty = (Property) bootPropertyIterator.next(); - final Type idPropertyType = bootIdProperty.getType(); - - if ( idPropertyType instanceof AnyType ) { - throw new HibernateException( - "AnyType property `" + getEntityName() + "#" + bootIdProperty.getName() + - "` cannot be used as part of entity identifier " - ); - } - - if ( idPropertyType instanceof CollectionType ) { - throw new HibernateException( - "Plural property `" + getEntityName() + "#" + bootIdProperty.getName() + - "` cannot be used as part of entity identifier " - ); - } - - final SingularAttributeMapping idAttributeMapping; - - if ( idPropertyType instanceof BasicType ) { - idAttributeMapping = MappingModelCreationHelper.buildBasicAttributeMapping( - bootIdProperty.getName(), - attributeMappings.size(), - bootIdProperty, - this, - (BasicType) idPropertyType, - getRootTableName(), - rootTableKeyColumnNames[columnsConsumedSoFar], - getRepresentationStrategy().resolvePropertyAccess( bootIdProperty ), - CascadeStyles.ALL, - creationProcess - ); - columnsConsumedSoFar++; - } - else { -// final String[] unconsumedColumnNames = Arrays.copyOfRange( -// rootTableKeyColumnNames, -// columnsConsumedSoFar, -// rootTableKeyColumnNames.length -// ); - - if ( idPropertyType instanceof CompositeType ) { - // nested composite - throw new NotYetImplementedFor6Exception( getClass() ); - } - else if ( idPropertyType instanceof EntityType ) { - // key-many-to-one - throw new NotYetImplementedFor6Exception( getClass() ); - } - else { - throw new UnsupportedOperationException(); - } - } - - idAttributeMappings.add( idAttributeMapping ); - } - } - attributeMappings.addAll( idAttributeMappings ); + PersistentClass bootEntityDescriptor, + CompositeType cidType) { + assert declaredAttributeMappings != null; return MappingModelCreationHelper.buildNonEncapsulatedCompositeIdentifierMapping( this, - idAttributeMappings, + getRootTableName(), + getRootTableKeyColumnNames(), cidType, bootEntityDescriptor, + declaredAttributeMappings::put, creationProcess ); } @@ -6167,6 +6101,7 @@ public abstract class AbstractEntityPersister if ( propertyIndex == getVersionProperty() ) { return MappingModelCreationHelper.buildBasicAttributeMapping( attrName, + getNavigableRole().append( bootProperty.getName() ), stateArrayPosition, bootProperty, this, @@ -6182,6 +6117,7 @@ public abstract class AbstractEntityPersister if ( attrType instanceof BasicType ) { return MappingModelCreationHelper.buildBasicAttributeMapping( attrName, + getNavigableRole().append( bootProperty.getName() ), stateArrayPosition, bootProperty, this, @@ -6222,6 +6158,7 @@ public abstract class AbstractEntityPersister else if ( attrType instanceof EntityType ) { SingularAssociationAttributeMapping attributeMapping = MappingModelCreationHelper.buildSingularAssociationAttributeMapping( attrName, + getNavigableRole().append( attrName ), stateArrayPosition, bootProperty, this, diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/StandardHqlTranslator.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/StandardHqlTranslator.java index 9a111928d6..c57f65c37b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/StandardHqlTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/StandardHqlTranslator.java @@ -9,6 +9,7 @@ package org.hibernate.query.hql.internal; import org.hibernate.QueryException; import org.hibernate.grammars.hql.HqlLexer; import org.hibernate.grammars.hql.HqlParser; +import org.hibernate.query.hql.HqlLogger; import org.hibernate.query.sqm.InterpretationException; import org.hibernate.query.hql.HqlTranslator; import org.hibernate.query.sqm.internal.SqmTreePrinter; @@ -31,6 +32,7 @@ public class StandardHqlTranslator implements HqlTranslator { private final SqmCreationContext sqmCreationContext; private final SqmCreationOptions sqmCreationOptions; + public StandardHqlTranslator( SqmCreationContext sqmCreationContext, SqmCreationOptions sqmCreationOptions) { @@ -40,6 +42,8 @@ public class StandardHqlTranslator implements HqlTranslator { @Override public SqmStatement translate(String query) { + HqlLogger.QUERY_LOGGER.debugf( "HQL : " + query ); + final HqlParser.StatementContext hqlParseTree = parseHql( query ); // then we perform semantic analysis and build the semantic representation... diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/DynamicModelJtd.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/DynamicModelJtd.java new file mode 100644 index 0000000000..72120740e4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/DynamicModelJtd.java @@ -0,0 +1,48 @@ +/* + * 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.type.descriptor.java.spi; + +import java.util.Map; + +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators; + +/** + * JavaTypeDescriptor for dynamic models + * + * @author Steve Ebersole + */ +public class DynamicModelJtd implements JavaTypeDescriptor> { + + @Override + public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) { + throw new UnsupportedOperationException(); + } + + @Override + public Map fromString(String string) { + throw new UnsupportedOperationException(); + } + + @Override + public X unwrap(Map value, Class type, WrapperOptions options) { + throw new UnsupportedOperationException(); + } + + @Override + public Map wrap(X value, WrapperOptions options) { + throw new UnsupportedOperationException(); + } + + @Override + public Class> getJavaTypeClass() { + //noinspection unchecked,rawtypes + return (Class) Map.class; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/JavaTypeDescriptorRegistry.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/JavaTypeDescriptorRegistry.java index 3188bf59e3..0ac89b05e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/JavaTypeDescriptorRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/JavaTypeDescriptorRegistry.java @@ -7,16 +7,12 @@ package org.hibernate.type.descriptor.java.spi; import java.io.Serializable; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; -import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.SerializableTypeDescriptor; -import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; -import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators; import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfigurationAware; @@ -155,34 +151,8 @@ public class JavaTypeDescriptorRegistry implements JavaTypeDescriptorBaseline.Ba ); } - public JavaTypeDescriptor resolveDynamicDescriptor(String typeName) { - return new DynamicJtd(); + public JavaTypeDescriptor resolveDynamicEntityDescriptor(String typeName) { + return new DynamicModelJtd(); } - private static class DynamicJtd implements JavaTypeDescriptor { - @Override - public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) { - throw new UnsupportedOperationException(); - } - - @Override - public Map fromString(String string) { - throw new UnsupportedOperationException(); - } - - @Override - public X unwrap(Map value, Class type, WrapperOptions options) { - throw new UnsupportedOperationException(); - } - - @Override - public Map wrap(X value, WrapperOptions options) { - throw new UnsupportedOperationException(); - } - - @Override - public Class getJavaTypeClass() { - return Map.class; - } - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/ChangeGroup.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/ChangeGroup.java new file mode 100644 index 0000000000..552eeef3c1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/ChangeGroup.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.orm.test.bootstrap.binding.hbm.cid.nonaggregated.dynamic; + +/** + * Entity used as target for a key-many-to-one + * + * @author Steve Ebersole + */ +public class ChangeGroup { + private Integer id; + private String name; + + /** + * For persistence + */ + @SuppressWarnings("unused") + private ChangeGroup() { + } + + public ChangeGroup(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdBasic.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdBasic.hbm.xml new file mode 100644 index 0000000000..3696d99ace --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdBasic.hbm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdBasicTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdBasicTests.java new file mode 100644 index 0000000000..d291c0cca3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdBasicTests.java @@ -0,0 +1,74 @@ +/* + * 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.orm.test.bootstrap.binding.hbm.cid.nonaggregated.dynamic; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; +import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.tool.schema.Action; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Steve Ebersole + */ +@ServiceRegistry( + settings = @ServiceRegistry.Setting( name = AvailableSettings.HBM2DDL_AUTO, value = "create-drop" ) +) +public class DynamicCompositeIdBasicTests { + @Test + public void testBinding(ServiceRegistryScope scope) { + final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( scope.getRegistry() ) + .addResource( "org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdBasic.hbm.xml" ) + .buildMetadata() + .buildSessionFactory(); + + try { + final EntityPersister entityDescriptor = sessionFactory.getRuntimeMetamodels() + .getMappingMetamodel() + .findEntityDescriptor( "DynamicCompositeIdBasic" ); + + assertThat( entityDescriptor.getNumberOfAttributeMappings(), is( 3 ) ); + + final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping(); + assertThat( identifierMapping, instanceOf( NonAggregatedIdentifierMappingImpl.class ) ); + final NonAggregatedIdentifierMappingImpl cid = (NonAggregatedIdentifierMappingImpl) identifierMapping; + assertThat( cid.getEmbeddableTypeDescriptor().getNumberOfAttributeMappings(), is( 2 ) ); + + final AttributeMapping key1 = cid.getEmbeddableTypeDescriptor().findAttributeMapping( "key1" ); + assertThat( key1, notNullValue() ); + + final AttributeMapping key2 = cid.getEmbeddableTypeDescriptor().findAttributeMapping( "key2" ); + assertThat( key2, notNullValue() ); + + final AttributeMapping attr1 = entityDescriptor.findAttributeMapping( "attr1" ); + assertThat( attr1, notNullValue() ); + + sessionFactory.inTransaction( + session -> session.createQuery( "from DynamicCompositeIdBasic e where e.key1 = 1" ).list() + ); + } + finally { + sessionFactory.close(); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdManyToOne.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdManyToOne.hbm.xml new file mode 100644 index 0000000000..3bdb2846e8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdManyToOne.hbm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdManyToOneTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdManyToOneTests.java new file mode 100644 index 0000000000..ae275acc80 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdManyToOneTests.java @@ -0,0 +1,87 @@ +/* + * 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.orm.test.bootstrap.binding.hbm.cid.nonaggregated.dynamic; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.internal.BasicValuedSingularAttributeMapping; +import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl; +import org.hibernate.metamodel.mapping.internal.SingularAssociationAttributeMapping; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.tool.schema.Action; + +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.testing.transaction.TransactionUtil2.inTransaction; + +/** + * Note that this test uses a composite-id with key-many-to-one as part of a + * dynamic model, which is the main construct needed by hibernate-envers + * + * @author Steve Ebersole + */ +@ServiceRegistry( + settings = @ServiceRegistry.Setting( name = AvailableSettings.HBM2DDL_AUTO, value = "create-drop" ) +) +public class DynamicCompositeIdManyToOneTests { + @Test + public void testBinding(ServiceRegistryScope scope) { + final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( scope.getRegistry() ) + .addResource( "org/hibernate/orm/test/bootstrap/binding/hbm/cid/nonaggregated/dynamic/DynamicCompositeIdManyToOne.hbm.xml" ) + .buildMetadata() + .buildSessionFactory(); + + try { + final EntityPersister entityDescriptor = sessionFactory.getRuntimeMetamodels() + .getMappingMetamodel() + .findEntityDescriptor( "DynamicCompositeIdManyToOne" ); + + assertThat( entityDescriptor.getNumberOfAttributeMappings(), is( 3 ) ); + + final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping(); + assertThat( identifierMapping, instanceOf( NonAggregatedIdentifierMappingImpl.class ) ); + final NonAggregatedIdentifierMappingImpl cid = (NonAggregatedIdentifierMappingImpl) identifierMapping; + assertThat( cid.getEmbeddableTypeDescriptor().getNumberOfAttributeMappings(), is( 2 ) ); + + final AttributeMapping key1 = cid.getEmbeddableTypeDescriptor().findAttributeMapping( "key1" ); + assertThat( key1, notNullValue() ); + assertThat( key1, instanceOf( BasicValuedSingularAttributeMapping.class ) ); + + final AttributeMapping key2 = cid.getEmbeddableTypeDescriptor().findAttributeMapping( "key2" ); + assertThat( key2, notNullValue() ); + assertThat( key2, instanceOf( SingularAssociationAttributeMapping.class ) ); + + final AttributeMapping attr1 = entityDescriptor.findAttributeMapping( "attr1" ); + assertThat( attr1, notNullValue() ); + assertThat( attr1, instanceOf( BasicValuedSingularAttributeMapping.class ) ); + + assertThat( entityDescriptor.getNumberOfAttributeMappings(), is( 3 ) ); + + inTransaction( + sessionFactory, + session -> { + session.createQuery( "select e__ from DynamicCompositeIdManyToOne e__" ).list(); + session.createQuery( "select e__ from DynamicCompositeIdManyToOne e__ where e__.key1 = 1" ).list(); + session.createQuery( "select e__ from DynamicCompositeIdManyToOne e__ where e__.key2.name = 'abc'" ).list(); + } + ); + } + finally { + sessionFactory.close(); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/dynamic/SimpleDynamicEntity.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/dynamic/SimpleDynamicEntity.hbm.xml new file mode 100644 index 0000000000..3d8c6460b8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/dynamic/SimpleDynamicEntity.hbm.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/dynamic/SimpleDynamicHbmTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/dynamic/SimpleDynamicHbmTests.java new file mode 100644 index 0000000000..b125fd42a4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/dynamic/SimpleDynamicHbmTests.java @@ -0,0 +1,68 @@ +/* + * 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.orm.test.bootstrap.binding.hbm.simple.dynamic; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Steve Ebersole + */ +@ServiceRegistry( + settings = @ServiceRegistry.Setting( name = AvailableSettings.HBM2DDL_AUTO, value = "create-drop" ) +) +public class SimpleDynamicHbmTests { + @Test + public void testBinding(ServiceRegistryScope scope) { + final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( scope.getRegistry() ) + .addResource( "org/hibernate/orm/test/bootstrap/binding/hbm/simple/dynamic/SimpleDynamicEntity.hbm.xml" ) + .buildMetadata() + .buildSessionFactory(); + + try { + final EntityPersister entityDescriptor = sessionFactory.getRuntimeMetamodels() + .getMappingMetamodel() + .findEntityDescriptor( "SimpleDynamicEntity" ); + + final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping(); + assertThat( identifierMapping, instanceOf( BasicEntityIdentifierMapping.class ) ); + final BasicEntityIdentifierMapping bid = (BasicEntityIdentifierMapping) identifierMapping; + assertThat( bid.getFetchableName(), is( "id" ) ); + assertThat( bid.getPartName(), is( EntityIdentifierMapping.ROLE_LOCAL_NAME ) ); + + assertThat( entityDescriptor.getNumberOfAttributeMappings(), is( 1 ) ); + assertThat( entityDescriptor.getNumberOfDeclaredAttributeMappings(), is( 1 ) ); + final AttributeMapping nameAttr = entityDescriptor.findAttributeMapping( "name" ); + assertThat( nameAttr, notNullValue() ); + + sessionFactory.inTransaction( + session -> { + session.createQuery( "from SimpleDynamicEntity" ).list(); + session.createQuery( "select e from SimpleDynamicEntity e" ).list(); + session.createQuery( "select e from SimpleDynamicEntity e.name = 'abc'" ).list(); + } + ); + } + finally { + sessionFactory.close(); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleEntity.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleEntity.hbm.xml new file mode 100644 index 0000000000..b88e8408ad --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleEntity.hbm.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleEntity.java new file mode 100644 index 0000000000..fb89ed0bc3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleEntity.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.orm.test.bootstrap.binding.hbm.simple.pojo; + +/** + * Entity for testing simply HBM mapping + * + * @author Steve Ebersole + */ +public class SimpleEntity { + private Integer id; + private String name; + + /** + * For Hibernate + */ + @SuppressWarnings("unused") + private SimpleEntity() { + } + + public SimpleEntity(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleHbmTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleHbmTests.java new file mode 100644 index 0000000000..47903a3682 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleHbmTests.java @@ -0,0 +1,52 @@ +/* + * 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.orm.test.bootstrap.binding.hbm.simple.pojo; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Steve Ebersole + */ +@ServiceRegistry +public class SimpleHbmTests { + @Test + public void testBinding(ServiceRegistryScope scope) { + final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( scope.getRegistry() ) + .addResource( "org/hibernate/orm/test/bootstrap/binding/hbm/simple/pojo/SimpleEntity.hbm.xml" ) + .buildMetadata() + .buildSessionFactory(); + + final EntityPersister entityDescriptor = sessionFactory.getRuntimeMetamodels() + .getMappingMetamodel() + .findEntityDescriptor( SimpleEntity.class ); + + final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping(); + assertThat( identifierMapping, instanceOf( BasicEntityIdentifierMapping.class ) ); + final BasicEntityIdentifierMapping bid = (BasicEntityIdentifierMapping) identifierMapping; + assertThat( bid.getFetchableName(), is( "id" ) ); + assertThat( bid.getPartName(), is( EntityIdentifierMapping.ROLE_LOCAL_NAME ) ); + + assertThat( entityDescriptor.getNumberOfAttributeMappings(), is( 1 ) ); + assertThat( entityDescriptor.getNumberOfDeclaredAttributeMappings(), is( 1 ) ); + final AttributeMapping nameAttr = entityDescriptor.findAttributeMapping( "name" ); + assertThat( nameAttr, notNullValue() ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/SimpleOpsTest.java b/hibernate-core/src/test/java/org/hibernate/test/ops/SimpleOpsTest.java index c2e33df480..f4e5853c14 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/ops/SimpleOpsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/ops/SimpleOpsTest.java @@ -28,7 +28,7 @@ public class SimpleOpsTest extends AbstractOperationTestCase { } public String[] getMappings() { - return new String[] { "ops/SimpleEntity.hbm.xml" }; + return new String[] { "ops/SimpleDynamicEntity.hbm.xml" }; } @Test diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/boot/EnversBootLogger.java b/hibernate-envers/src/main/java/org/hibernate/envers/boot/EnversBootLogger.java new file mode 100644 index 0000000000..e7b223f398 --- /dev/null +++ b/hibernate-envers/src/main/java/org/hibernate/envers/boot/EnversBootLogger.java @@ -0,0 +1,51 @@ +/* + * 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.envers.boot; + +import org.jboss.logging.BasicLogger; +import org.jboss.logging.Logger; +import org.jboss.logging.annotations.LogMessage; +import org.jboss.logging.annotations.Message; +import org.jboss.logging.annotations.MessageLogger; +import org.jboss.logging.annotations.ValidIdRange; + +import static org.jboss.logging.Logger.Level.INFO; + +/** + * @author Steve Ebersole + */ +@MessageLogger( projectCode = "HHH" ) +@ValidIdRange( min = 90005601, max = 90005700 ) +public interface EnversBootLogger extends BasicLogger { + String LOGGER_NAME = "org.hibernate.envers.boot"; + + EnversBootLogger BOOT_LOGGER = Logger.getMessageLogger( + EnversBootLogger.class, + LOGGER_NAME + ); + + boolean TRACE_ENABLED = BOOT_LOGGER.isTraceEnabled(); + boolean DEBUG_ENABLED = BOOT_LOGGER.isDebugEnabled(); + + static String subLoggerName(String subName) { + return LOGGER_NAME + '.' + subName; + } + + static Logger subLogger(String subName) { + return Logger.getLogger( subLoggerName( subName ) ); + } + + /** + * Log about usage of deprecated Scanner setting + */ + @LogMessage( level = INFO ) + @Message( + value = "Envers-generated HBM mapping...%n%s", + id = 90000001 + ) + void jaxbContribution(String hbm); +} diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java index 37b0c95c9e..1779b906fe 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java @@ -28,6 +28,7 @@ import org.hibernate.boot.model.source.internal.hbm.MappingDocument; import org.hibernate.boot.spi.AdditionalJaxbMappingProducer; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.envers.boot.EnversBootLogger; import org.hibernate.envers.configuration.internal.MappingCollector; import org.hibernate.service.ServiceRegistry; @@ -63,21 +64,12 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP // atm we do not have distinct origin info for envers final Origin origin = new Origin( SourceType.OTHER, "envers" ); -// final DOMWriter writer = new DOMWriter(); final MappingCollector mappingCollector = new MappingCollector() { @Override public void addDocument(Document document) throws DocumentException { - dump( document ); + logXml( document ); - // while the commented-out code here is more efficient (well, understanding that - // this whole process is un-efficient) it leads to un-decipherable messages when - // we get mapping mapping errors from envers output. -// final DOMSource domSource = new DOMSource( writer.write( document ) ); -// domSource.setSystemId( "envers" ); -// final Binding jaxbBinding = mappingBinder.bind( domSource, origin ); - - // this form at least allows us to get better error messages final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { final Writer w = new BufferedWriter( new OutputStreamWriter( baos, "UTF-8" ) ); @@ -89,11 +81,11 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP throw new HibernateException( "Unable to bind Envers-generated XML", e ); } - ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() ); - BufferedInputStream bis = new BufferedInputStream( bais ); - final Binding jaxbBinding = mappingBinder.bind( bis, origin ); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( baos.toByteArray() ); + BufferedInputStream bufferedInputStream = new BufferedInputStream( byteArrayInputStream ); + final Binding jaxbBinding = mappingBinder.bind( bufferedInputStream, origin ); - final JaxbHbmHibernateMapping jaxbRoot = (JaxbHbmHibernateMapping) jaxbBinding.getRoot(); + final JaxbHbmHibernateMapping jaxbRoot = jaxbBinding.getRoot(); additionalMappingDocuments.add( new MappingDocument( jaxbRoot, origin, buildingContext ) ); } }; @@ -103,13 +95,13 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP return additionalMappingDocuments; } - private static void dump(Document document) { - if ( !log.isTraceEnabled() ) { + private static void logXml(Document document) { + if ( ! EnversBootLogger.DEBUG_ENABLED ) { return; } - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final Writer w = new PrintWriter( baos ); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + final Writer w = new PrintWriter( outputStream ); try { final XMLWriter xw = new XMLWriter( w, new OutputFormat( " ", true ) ); @@ -120,7 +112,9 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP throw new RuntimeException( "Error dumping enhanced class", e1 ); } - log.tracef( "Envers-generate entity mapping -----------------------------\n%s", baos.toString() ); + EnversBootLogger.BOOT_LOGGER.jaxbContribution( outputStream.toString() ); + + log.tracef( "Envers-generate entity mapping -----------------------------\n%s", outputStream.toString() ); log.trace( "------------------------------------------------------------" ); } } diff --git a/hibernate-envers/src/test/resources/log4j.properties b/hibernate-envers/src/test/resources/log4j.properties index e516e460d1..c3a6cd12ce 100644 --- a/hibernate-envers/src/test/resources/log4j.properties +++ b/hibernate-envers/src/test/resources/log4j.properties @@ -20,4 +20,13 @@ log4j.logger.org.hibernate.tool.hbm2ddl=debug log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace -log4j.logger.org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl=trace \ No newline at end of file +log4j.logger.org.hibernate.envers.jaxb=debug + +log4j.logger.org.hibernate.query=debug +log4j.logger.org.hibernate.orm.query=debug + +log4j.logger.org.hibernate.sql.ast=debug +log4j.logger.org.hibernate.orm.sql.ast=debug + +log4j.logger.org.hibernate.sql.exec=debug +log4j.logger.org.hibernate.orm.sql.exec=debug \ No newline at end of file diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/boot/BootstrapContextImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/boot/BootstrapContextImpl.java index b77c174075..9e85f26da4 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/boot/BootstrapContextImpl.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/boot/BootstrapContextImpl.java @@ -9,6 +9,8 @@ package org.hibernate.testing.boot; import java.util.Collection; import java.util.Map; +import javax.xml.bind.JAXBContext; + import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.boot.CacheRegionDefinition; import org.hibernate.boot.archive.scan.spi.ScanEnvironment; @@ -141,13 +143,13 @@ public class BootstrapContextImpl implements BootstrapContext { return delegate.getCacheRegionDefinitions(); } - @Override - public void release() { - delegate.release(); - } - @Override public ManagedTypeRepresentationResolver getRepresentationStrategySelector() { return StandardManagedTypeRepresentationResolver.INSTANCE; } + + @Override + public void release() { + delegate.release(); + } }