* HBM mappings

* dynamic models
* initial non-aggregated cid support
This commit is contained in:
Steve Ebersole 2020-04-27 15:21:09 -05:00
parent 593eeb0d9f
commit 96f4a350e0
41 changed files with 1289 additions and 271 deletions

View File

@ -94,4 +94,12 @@
|90005500 |90005500
|org.hibernate.sql.ast.tree.SqlAstTreeLogger |org.hibernate.sql.ast.tree.SqlAstTreeLogger
|90005501
|90005600
|org.hibernate.boot.jaxb.JaxbLogger
|90005601
|90005700
|org.hibernate.envers.boot.EnversBootLogger
|=== |===

View File

@ -32,7 +32,9 @@ import org.hibernate.boot.jaxb.SourceType;
import org.hibernate.boot.jaxb.internal.CacheableFileXmlSource; import org.hibernate.boot.jaxb.internal.CacheableFileXmlSource;
import org.hibernate.boot.jaxb.internal.JarFileEntryXmlSource; import org.hibernate.boot.jaxb.internal.JarFileEntryXmlSource;
import org.hibernate.boot.jaxb.internal.JaxpSourceXmlSource; 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.Binding;
import org.hibernate.boot.jaxb.spi.XmlSource;
import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry; 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 static final CoreMessageLogger LOG = CoreLogging.messageLogger( MetadataSources.class );
private final ServiceRegistry serviceRegistry; private final ServiceRegistry serviceRegistry;
private final ClassLoaderService classLoaderService;
private XmlMappingBinderAccess xmlMappingBinderAccess; private XmlMappingBinderAccess xmlMappingBinderAccess;
private List<Binding> xmlBindings; private List<Binding<?>> xmlBindings;
private LinkedHashSet<Class<?>> annotatedClasses; private LinkedHashSet<Class<?>> annotatedClasses;
private LinkedHashSet<String> annotatedClassNames; private LinkedHashSet<String> annotatedClassNames;
private LinkedHashSet<String> annotatedPackages; private LinkedHashSet<String> annotatedPackages;
@ -90,11 +93,12 @@ public class MetadataSources implements Serializable {
} }
} }
this.serviceRegistry = serviceRegistry; this.serviceRegistry = serviceRegistry;
this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
} }
protected static boolean isExpectedServiceRegistryType(ServiceRegistry serviceRegistry) { protected static boolean isExpectedServiceRegistryType(ServiceRegistry serviceRegistry) {
return BootstrapServiceRegistry.class.isInstance( serviceRegistry ) return serviceRegistry instanceof BootstrapServiceRegistry
|| StandardServiceRegistry.class.isInstance( serviceRegistry ); || serviceRegistry instanceof StandardServiceRegistry;
} }
public XmlMappingBinderAccess getXmlMappingBinderAccess() { public XmlMappingBinderAccess getXmlMappingBinderAccess() {
@ -104,7 +108,7 @@ public class MetadataSources implements Serializable {
return xmlMappingBinderAccess; return xmlMappingBinderAccess;
} }
public List<Binding> getXmlBindings() { public List<Binding<?>> getXmlBindings() {
return xmlBindings == null ? Collections.emptyList() : xmlBindings; return xmlBindings == null ? Collections.emptyList() : xmlBindings;
} }
@ -332,7 +336,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addResource(String name) { 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; return this;
} }
@ -358,7 +364,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addFile(File file) { 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; return this;
} }
@ -372,15 +380,10 @@ public class MetadataSources implements Serializable {
* @see #addCacheableFile(java.io.File) * @see #addCacheableFile(java.io.File)
*/ */
public MetadataSources addCacheableFile(String path) { public MetadataSources addCacheableFile(String path) {
final Origin origin = new Origin( SourceType.FILE, path ); addCacheableFile( new File( path ) );
addCacheableFile( origin, new File( path ) );
return this; 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 * 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} * 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) * @return this (for method chaining purposes)
*/ */
public MetadataSources addCacheableFile(File file) { public MetadataSources addCacheableFile(File file) {
final Origin origin = new Origin( SourceType.FILE, file.getName() ); final XmlSource xmlSource = XmlSources.fromCacheableFile( file );
addCacheableFile( origin, file ); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; 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 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. * @throws java.io.FileNotFoundException Indicates that the cached file was not found or was not usable.
*/ */
public MetadataSources addCacheableFileStrictly(File file) throws SerializationException, FileNotFoundException { public MetadataSources addCacheableFileStrictly(File file) throws SerializationException {
final Origin origin = new Origin( SourceType.FILE, file.getAbsolutePath() ); final XmlSource xmlSource = XmlSources.fromCacheableFile( file, true );
getXmlBindingsForWrite().add( new CacheableFileXmlSource( origin, file, true ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) ); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -427,7 +432,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addInputStream(InputStreamAccess xmlInputStreamAccess) { 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; return this;
} }
@ -439,7 +446,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addInputStream(InputStream xmlInputStream) { 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; return this;
} }
@ -451,7 +460,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addURL(URL url) { 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; return this;
} }
@ -466,8 +477,9 @@ public class MetadataSources implements Serializable {
*/ */
@Deprecated @Deprecated
public MetadataSources addDocument(Document document) { public MetadataSources addDocument(Document document) {
final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH ); final XmlSource xmlSource = XmlSources.fromDocument( document );
getXmlBindingsForWrite().add( new JaxpSourceXmlSource( origin, new DOMSource( document ) ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) ); final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this; return this;
} }
@ -481,42 +493,15 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addJar(File jar) { public MetadataSources addJar(File jar) {
if ( LOG.isDebugEnabled() ) { final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
LOG.debugf( "Seeking mapping documents in jar file : %s", jar.getName() ); XmlSources.fromJar(
} jar,
final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() ); xmlSource -> getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) )
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 );
}
return this; return this;
} }
private <Binding> List getXmlBindingsForWrite() { private List<Binding<?>> getXmlBindingsForWrite() {
if ( xmlBindings == null ) { if ( xmlBindings == null ) {
xmlBindings = new ArrayList<>(); xmlBindings = new ArrayList<>();
} }

View File

@ -6,7 +6,9 @@
*/ */
package org.hibernate.boot.archive.spi; package org.hibernate.boot.archive.spi;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.function.Function;
/** /**
* Contract for building InputStreams, especially in on-demand situations * Contract for building InputStreams, especially in on-demand situations
@ -19,12 +21,26 @@ public interface InputStreamAccess {
* *
* @return The backing resource name * @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. * Get access to the stream. Can be called multiple times, a different stream instance should be returned each time.
* *
* @return The stream * @return The stream
*/ */
public InputStream accessInputStream(); InputStream accessInputStream();
default <X> X fromStream(Function<InputStream, X> action) {
final InputStream inputStream = accessInputStream();
try {
return action.apply( inputStream );
}
finally {
try {
inputStream.close();
}
catch (IOException ignore) {
}
}
}
} }

View File

@ -54,18 +54,17 @@ public class BootstrapContextImpl implements BootstrapContext {
private static final Logger log = Logger.getLogger( BootstrapContextImpl.class ); private static final Logger log = Logger.getLogger( BootstrapContextImpl.class );
private final StandardServiceRegistry serviceRegistry; private final StandardServiceRegistry serviceRegistry;
private final MetadataBuildingOptions metadataBuildingOptions;
private final MutableJpaCompliance jpaCompliance;
private final TypeConfiguration typeConfiguration; private final TypeConfiguration typeConfiguration;
private final MutableJpaCompliance jpaCompliance;
private final ClassLoaderAccessImpl classLoaderAccess; private final ClassLoaderAccessImpl classLoaderAccess;
private boolean isJpaBootstrap;
private final JavaReflectionManager hcannReflectionManager; private final JavaReflectionManager hcannReflectionManager;
private final ClassmateContext classmateContext; private final ClassmateContext classmateContext;
private final MetadataBuildingOptions metadataBuildingOptions;
private boolean isJpaBootstrap;
private ScanOptions scanOptions; private ScanOptions scanOptions;
private ScanEnvironment scanEnvironment; private ScanEnvironment scanEnvironment;
@ -76,7 +75,7 @@ public class BootstrapContextImpl implements BootstrapContext {
private HashMap<String,SqmFunctionDescriptor> sqlFunctionMap; private HashMap<String,SqmFunctionDescriptor> sqlFunctionMap;
private ArrayList<AuxiliaryDatabaseObject> auxiliaryDatabaseObjectList; private ArrayList<AuxiliaryDatabaseObject> auxiliaryDatabaseObjectList;
private HashMap<Class, ConverterDescriptor> attributeConverterDescriptorMap; private HashMap<Class<?>, ConverterDescriptor> attributeConverterDescriptorMap;
private ArrayList<CacheRegionDefinition> cacheRegionDefinitions; private ArrayList<CacheRegionDefinition> cacheRegionDefinitions;
private ManagedTypeRepresentationResolver representationStrategySelector; private ManagedTypeRepresentationResolver representationStrategySelector;
@ -87,8 +86,7 @@ public class BootstrapContextImpl implements BootstrapContext {
this.classmateContext = new ClassmateContext(); this.classmateContext = new ClassmateContext();
this.metadataBuildingOptions = metadataBuildingOptions; this.metadataBuildingOptions = metadataBuildingOptions;
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); this.classLoaderAccess = new ClassLoaderAccessImpl( serviceRegistry.getService( ClassLoaderService.class ) );
this.classLoaderAccess = new ClassLoaderAccessImpl( classLoaderService );
this.hcannReflectionManager = generateHcannReflectionManager(); this.hcannReflectionManager = generateHcannReflectionManager();
final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class ); final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class );

View File

@ -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();
}

View File

@ -37,6 +37,7 @@ public abstract class AbstractBinder implements Binder {
private final LocalXmlResourceResolver xmlResourceResolver; private final LocalXmlResourceResolver xmlResourceResolver;
private final boolean validateXml; private final boolean validateXml;
@SuppressWarnings("unused")
protected AbstractBinder(ClassLoaderService classLoaderService) { protected AbstractBinder(ClassLoaderService classLoaderService) {
this( classLoaderService, true ); this( classLoaderService, true );
} }
@ -121,7 +122,6 @@ public abstract class AbstractBinder implements Binder {
return staxFactory; return staxFactory;
} }
@SuppressWarnings( { "UnnecessaryLocalVariable" })
private XMLInputFactory buildStaxFactory() { private XMLInputFactory buildStaxFactory() {
XMLInputFactory staxFactory = XMLInputFactory.newInstance(); XMLInputFactory staxFactory = XMLInputFactory.newInstance();
staxFactory.setXMLResolver( xmlResourceResolver ); staxFactory.setXMLResolver( xmlResourceResolver );
@ -150,6 +150,7 @@ public abstract class AbstractBinder implements Binder {
protected abstract Binding doBind(XMLEventReader staxEventReader, StartElement rootElementStartEvent, Origin origin); protected abstract Binding doBind(XMLEventReader staxEventReader, StartElement rootElementStartEvent, Origin origin);
@SuppressWarnings("unused")
protected static boolean hasNamespace(StartElement startElement) { protected static boolean hasNamespace(StartElement startElement) {
return ! "".equals( startElement.getName().getNamespaceURI() ); return ! "".equals( startElement.getName().getNamespaceURI() );
} }

View File

@ -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 )
);
}
}

View File

@ -41,6 +41,7 @@ public class MappingBinder extends AbstractBinder {
private JAXBContext hbmJaxbContext; private JAXBContext hbmJaxbContext;
@SuppressWarnings("unused")
public MappingBinder(ClassLoaderService classLoaderService) { public MappingBinder(ClassLoaderService classLoaderService) {
this( classLoaderService, true ); this( classLoaderService, true );
} }
@ -50,7 +51,7 @@ public class MappingBinder extends AbstractBinder {
} }
@Override @Override
protected Binding doBind( protected Binding<?> doBind(
XMLEventReader staxEventReader, XMLEventReader staxEventReader,
StartElement rootElementStartEvent, StartElement rootElementStartEvent,
Origin origin) { Origin origin) {
@ -98,7 +99,7 @@ public class MappingBinder extends AbstractBinder {
// are trying to read has comments this process will blow up. So we // are trying to read has comments this process will blow up. So we
// override that to add that support as best we can // override that to add that support as best we can
XMLEvent event = reader.peek(); 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.readComment( reader );
} }
return super.readNode( reader ); return super.readNode( reader );

View File

@ -14,6 +14,7 @@ import java.net.UnknownHostException;
import org.hibernate.boot.MappingException; import org.hibernate.boot.MappingException;
import org.hibernate.boot.MappingNotFoundException; import org.hibernate.boot.MappingNotFoundException;
import org.hibernate.boot.jaxb.Origin; 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.Binder;
import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.jaxb.spi.XmlSource; import org.hibernate.boot.jaxb.spi.XmlSource;
@ -22,6 +23,7 @@ import org.hibernate.boot.jaxb.spi.XmlSource;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class UrlXmlSource extends XmlSource { public class UrlXmlSource extends XmlSource {
private final URL url; private final URL url;
public UrlXmlSource(Origin origin, URL url) { public UrlXmlSource(Origin origin, URL url) {

View File

@ -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<XmlSource> 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<JarEntry> 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 );
}
}
}

View File

@ -91,14 +91,29 @@ public class EntityHierarchySourceImpl implements EntityHierarchySource {
else { else {
// if we get here, we should have a composite identifier. Just need // if we get here, we should have a composite identifier. Just need
// to determine if it is aggregated, or non-aggregated... // to determine if it is aggregated, or non-aggregated...
if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getName() ) ) {
if ( rootEntitySource.jaxbEntityMapping().getCompositeId().isMapped() if ( rootEntitySource.jaxbEntityMapping().getCompositeId().isMapped() ) {
&& StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getClazz() ) ) { if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getClazz() ) ) {
throw new MappingException( throw new MappingException(
"mapped composite identifier must name component class to use.", "mapped composite identifier must name component class to use.",
rootEntitySource.origin() 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 ); return new IdentifierSourceNonAggregatedCompositeImpl( rootEntitySource );
} }
else { else {

View File

@ -9,6 +9,9 @@ package org.hibernate.boot.spi;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.stream.XMLInputFactory;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.CacheRegionDefinition; import org.hibernate.boot.CacheRegionDefinition;
@ -162,6 +165,8 @@ public interface BootstrapContext {
*/ */
Collection<CacheRegionDefinition> getCacheRegionDefinitions(); Collection<CacheRegionDefinition> getCacheRegionDefinitions();
ManagedTypeRepresentationResolver getRepresentationStrategySelector();
/** /**
* Releases the "bootstrap only" resources held by this BootstrapContext. * Releases the "bootstrap only" resources held by this BootstrapContext.
* <p/> * <p/>
@ -172,6 +177,4 @@ public interface BootstrapContext {
* @todo verify this ^^ * @todo verify this ^^
*/ */
void release(); void release();
ManagedTypeRepresentationResolver getRepresentationStrategySelector();
} }

View File

@ -21,16 +21,18 @@ import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type; import javax.persistence.metamodel.Type;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.annotations.common.AssertionFailure; import org.hibernate.annotations.common.AssertionFailure;
import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.EntityManagerMessageLogger;
import org.hibernate.internal.HEMLogging; import org.hibernate.internal.HEMLogging;
import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Component; import org.hibernate.mapping.Component;
import org.hibernate.mapping.KeyValue;
import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.model.domain.AbstractIdentifiableType; import org.hibernate.metamodel.model.domain.AbstractIdentifiableType;
import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType; 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.SingularPersistentAttribute;
import org.hibernate.metamodel.model.domain.internal.AttributeContainer; import org.hibernate.metamodel.model.domain.internal.AttributeContainer;
import org.hibernate.metamodel.model.domain.internal.BasicTypeImpl; 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.EntityTypeImpl;
import org.hibernate.metamodel.model.domain.internal.MappedSuperclassTypeImpl; 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.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -358,7 +359,7 @@ public class MetadataContext {
// 2) register the part (mapping role) // 2) register the part (mapping role)
// 3) somehow get the mapping role "into" the part (setter, ?) // 3) somehow get the mapping role "into" the part (setter, ?)
@SuppressWarnings("unchecked") @SuppressWarnings({"unchecked", "rawtypes"})
private void applyIdMetadata(PersistentClass persistentClass, IdentifiableDomainType<?> identifiableType) { private void applyIdMetadata(PersistentClass persistentClass, IdentifiableDomainType<?> identifiableType) {
if ( persistentClass.hasIdentifierProperty() ) { if ( persistentClass.hasIdentifierProperty() ) {
final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty(); final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty();
@ -371,31 +372,38 @@ public class MetadataContext {
( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdAttribute( idAttribute ); ( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdAttribute( idAttribute );
} }
} }
else if ( persistentClass.hasIdentifierMapper() ) {
@SuppressWarnings("unchecked")
final Iterator<Property> propertyIterator = persistentClass.getIdentifierMapper().getPropertyIterator();
final Set<SingularPersistentAttribute<?, ?>> idClassAttributes = (Set<SingularPersistentAttribute<?, ?>>) buildIdClassAttributes(
identifiableType,
propertyIterator
);
( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdClassAttributes( idClassAttributes );
}
else { else {
final KeyValue value = persistentClass.getIdentifier(); // we have a non-aggregated composite-id
if ( value instanceof Component ) {
final Component component = (Component) value; //noinspection RedundantClassCall
if ( component.getPropertySpan() > 1 ) { if ( ! Component.class.isInstance( persistentClass.getIdentifier() ) ) {
//FIXME we are an Hibernate embedded id (ie not type) throw new MappingException( "Expecting Component for id mapping with no id-attribute" );
} }
else {
//FIXME take care of declared vs non declared property // Handle the actual id-attributes
( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdAttribute( final Component cidValue = (Component) persistentClass.getIdentifier();
attributeFactory.buildIdAttribute( final Iterator<Property> cidPropertyItr = cidValue.getPropertyIterator();
identifiableType, final Set<SingularPersistentAttribute<?,?>> idAttributes = new HashSet<>( cidValue.getPropertySpan() );
(Property) component.getPropertyIterator().next()
) while ( cidPropertyItr.hasNext() ) {
); final Property cidSubProperty = cidPropertyItr.next();
}
final SingularPersistentAttribute<?, Object> 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 propertyIterator
); );
//noinspection unchecked //noinspection unchecked
( ( AttributeContainer) jpaMappingType ).getInFlightAccess().applyIdClassAttributes( attributes ); ( ( AttributeContainer<X>) jpaMappingType ).getInFlightAccess().applyIdClassAttributes( attributes );
} }
} }
@ -427,7 +435,7 @@ public class MetadataContext {
final Property declaredVersion = persistentClass.getDeclaredVersion(); final Property declaredVersion = persistentClass.getDeclaredVersion();
if ( declaredVersion != null ) { if ( declaredVersion != null ) {
//noinspection unchecked //noinspection unchecked
( ( AttributeContainer) jpaEntityType ).getInFlightAccess().applyVersionAttribute( ( ( AttributeContainer<X>) jpaEntityType ).getInFlightAccess().applyVersionAttribute(
attributeFactory.buildVersionAttribute( jpaEntityType, declaredVersion ) attributeFactory.buildVersionAttribute( jpaEntityType, declaredVersion )
); );
} }
@ -437,7 +445,7 @@ public class MetadataContext {
final Property declaredVersion = mappingType.getDeclaredVersion(); final Property declaredVersion = mappingType.getDeclaredVersion();
if ( declaredVersion != null ) { if ( declaredVersion != null ) {
//noinspection unchecked //noinspection unchecked
( ( AttributeContainer) jpaMappingType ).getInFlightAccess().applyVersionAttribute( ( ( AttributeContainer<X>) jpaMappingType ).getInFlightAccess().applyVersionAttribute(
attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion ) attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion )
); );
} }

View File

@ -62,7 +62,7 @@ public class StandardManagedTypeRepresentationResolver implements ManagedTypeRep
// RepresentationMode representation = bootDescriptor.getExplicitRepresentationMode(); // RepresentationMode representation = bootDescriptor.getExplicitRepresentationMode();
RepresentationMode representation = null; RepresentationMode representation = null;
if ( representation == null ) { if ( representation == null ) {
if ( bootDescriptor.getComponentClass() == null ) { if ( bootDescriptor.getComponentClassName() == null ) {
representation = RepresentationMode.MAP; representation = RepresentationMode.MAP;
} }
else { else {

View File

@ -81,6 +81,36 @@ public class EmbeddableMappingType implements ManagedMappingType {
return mappingType; return mappingType;
} }
public static EmbeddableMappingType from(
Component bootDescriptor,
CompositeType compositeType,
NavigableRole embeddedRole,
Function<EmbeddableMappingType,EmbeddableValuedModelPart> 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 JavaTypeDescriptor embeddableJtd;
private final EmbeddableRepresentationStrategy representationStrategy; private final EmbeddableRepresentationStrategy representationStrategy;
@ -90,6 +120,7 @@ public class EmbeddableMappingType implements ManagedMappingType {
private final Map<String,AttributeMapping> attributeMappings = new LinkedHashMap<>(); private final Map<String,AttributeMapping> attributeMappings = new LinkedHashMap<>();
private final EmbeddableValuedModelPart valueMapping; private final EmbeddableValuedModelPart valueMapping;
private NavigableRole embeddedRole;
private final boolean createEmptyCompositesEnabled; private final boolean createEmptyCompositesEnabled;
@ -139,6 +170,7 @@ public class EmbeddableMappingType implements ManagedMappingType {
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
MappingModelCreationHelper.buildBasicAttributeMapping( MappingModelCreationHelper.buildBasicAttributeMapping(
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ),
attributeIndex, attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
this, this,
@ -194,6 +226,7 @@ public class EmbeddableMappingType implements ManagedMappingType {
else if ( subtype instanceof EntityType ) { else if ( subtype instanceof EntityType ) {
final SingularAssociationAttributeMapping singularAssociationAttributeMapping = MappingModelCreationHelper.buildSingularAssociationAttributeMapping( final SingularAssociationAttributeMapping singularAssociationAttributeMapping = MappingModelCreationHelper.buildSingularAssociationAttributeMapping(
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ),
attributeIndex, attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
entityPersister, entityPersister,

View File

@ -59,6 +59,7 @@ public class BasicValuedSingularAttributeMapping
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public BasicValuedSingularAttributeMapping( public BasicValuedSingularAttributeMapping(
String attributeName, String attributeName,
NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
StateArrayContributorMetadataAccess attributeMetadataAccess, StateArrayContributorMetadataAccess attributeMetadataAccess,
FetchStrategy mappedFetchStrategy, FetchStrategy mappedFetchStrategy,
@ -69,7 +70,7 @@ public class BasicValuedSingularAttributeMapping
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess) { PropertyAccess propertyAccess) {
super( attributeName, stateArrayPosition, attributeMetadataAccess, mappedFetchStrategy, declaringType, propertyAccess ); super( attributeName, stateArrayPosition, attributeMetadataAccess, mappedFetchStrategy, declaringType, propertyAccess );
this.navigableRole = declaringType.getNavigableRole().append( attributeName ); this.navigableRole = navigableRole;
this.tableExpression = tableExpression; this.tableExpression = tableExpression;
this.mappedColumnExpression = mappedColumnExpression; this.mappedColumnExpression = mappedColumnExpression;
this.valueConverter = valueConverter; this.valueConverter = valueConverter;

View File

@ -12,8 +12,10 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.function.BiConsumer;
import org.hibernate.FetchMode; import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.collection.internal.StandardArraySemantics; import org.hibernate.collection.internal.StandardArraySemantics;
@ -27,6 +29,7 @@ import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.CascadeStyles;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper; 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.StateArrayContributorMetadata;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.SQLLoadableCollection; import org.hibernate.persister.collection.SQLLoadableCollection;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.walking.internal.FetchStrategyHelper; import org.hibernate.persister.walking.internal.FetchStrategyHelper;
import org.hibernate.property.access.internal.PropertyAccessStrategyMapImpl;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.ast.spi.SqlAliasStemHelper; import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.type.AnyType;
import org.hibernate.type.AssociationType; import org.hibernate.type.AssociationType;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType; import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType; import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection; import org.hibernate.type.ForeignKeyDirection;
@ -116,10 +123,10 @@ public class MappingModelCreationHelper {
final EmbeddableMappingType embeddableMappingType = EmbeddableMappingType.from( final EmbeddableMappingType embeddableMappingType = EmbeddableMappingType.from(
(Component) bootProperty.getValue(), (Component) bootProperty.getValue(),
cidType, cidType,
attributeMappingType -> new EmbeddedIdentifierMappingImpl( embeddable -> new EmbeddedIdentifierMappingImpl(
entityPersister, entityPersister,
attributeName, attributeName,
attributeMappingType, embeddable,
attributeMetadataAccess, attributeMetadataAccess,
propertyAccess, propertyAccess,
rootTableName, rootTableName,
@ -135,20 +142,119 @@ public class MappingModelCreationHelper {
public static CompositeIdentifierMapping buildNonEncapsulatedCompositeIdentifierMapping( public static CompositeIdentifierMapping buildNonEncapsulatedCompositeIdentifierMapping(
EntityPersister entityPersister, EntityPersister entityPersister,
List<SingularAttributeMapping> idAttributeMappings, String rootTableName,
String[] rootTableKeyColumnNames,
CompositeType cidType, CompositeType cidType,
PersistentClass bootEntityDescriptor, PersistentClass bootEntityDescriptor,
BiConsumer<String,SingularAttributeMapping> idSubAttributeConsumer,
MappingModelCreationProcess creationProcess) { MappingModelCreationProcess creationProcess) {
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
final Component bootCompositeDescriptor = (Component) bootEntityDescriptor.getIdentifier(); final Component bootCompositeDescriptor = (Component) bootEntityDescriptor.getIdentifier();
return new NonAggregatedIdentifierMappingImpl( final PropertyAccess propertyAccess = PropertyAccessStrategyMapImpl.INSTANCE.buildPropertyAccess(
entityPersister, null,
idAttributeMappings, EntityIdentifierMapping.ROLE_LOCAL_NAME
);
final StateArrayContributorMetadataAccess attributeMetadataAccess = getStateArrayContributorMetadataAccess(
propertyAccess
);
final EmbeddableMappingType embeddableMappingType = EmbeddableMappingType.from(
bootCompositeDescriptor, bootCompositeDescriptor,
cidType, cidType,
attributeMappingType -> {
final Component bootIdDescriptor = (Component) bootEntityDescriptor.getIdentifier();
final List<SingularAttributeMapping> idAttributeMappings = new ArrayList<>( bootIdDescriptor.getPropertySpan() );
//noinspection unchecked
final Iterator<Property> 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 creationProcess
); );
return (CompositeIdentifierMapping) embeddableMappingType.getEmbeddedValueMapping();
} }
@ -158,6 +264,7 @@ public class MappingModelCreationHelper {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public static BasicValuedSingularAttributeMapping buildBasicAttributeMapping( public static BasicValuedSingularAttributeMapping buildBasicAttributeMapping(
String attrName, String attrName,
NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
Property bootProperty, Property bootProperty,
ManagedMappingType declaringType, ManagedMappingType declaringType,
@ -240,6 +347,7 @@ public class MappingModelCreationHelper {
return new BasicValuedSingularAttributeMapping( return new BasicValuedSingularAttributeMapping(
attrName, attrName,
navigableRole,
stateArrayPosition, stateArrayPosition,
attributeMetadataAccess, attributeMetadataAccess,
fetchStrategy, fetchStrategy,
@ -254,6 +362,7 @@ public class MappingModelCreationHelper {
else { else {
return new BasicValuedSingularAttributeMapping( return new BasicValuedSingularAttributeMapping(
attrName, attrName,
navigableRole,
stateArrayPosition, stateArrayPosition,
attributeMetadataAccess, attributeMetadataAccess,
fetchStrategy, fetchStrategy,
@ -1141,6 +1250,7 @@ public class MappingModelCreationHelper {
public static SingularAssociationAttributeMapping buildSingularAssociationAttributeMapping( public static SingularAssociationAttributeMapping buildSingularAssociationAttributeMapping(
String attrName, String attrName,
NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
Property bootProperty, Property bootProperty,
ManagedMappingType declaringType, ManagedMappingType declaringType,
@ -1183,6 +1293,7 @@ public class MappingModelCreationHelper {
final SingularAssociationAttributeMapping attributeMapping = new SingularAssociationAttributeMapping( final SingularAssociationAttributeMapping attributeMapping = new SingularAssociationAttributeMapping(
attrName, attrName,
navigableRole,
stateArrayPosition, stateArrayPosition,
(ToOne) bootProperty.getValue(), (ToOne) bootProperty.getValue(),
stateArrayContributorMetadataAccess, stateArrayContributorMetadataAccess,

View File

@ -6,21 +6,44 @@
*/ */
package org.hibernate.metamodel.mapping.internal; package org.hibernate.metamodel.mapping.internal;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.Component; import org.hibernate.mapping.Component;
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SingularAttributeMapping; import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.query.NavigablePath; 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.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState; 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.CompositeType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -33,23 +56,37 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMapping { public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMapping, EmbeddableValuedFetchable {
private final EmbeddableMappingType embeddableDescriptor;
private final NavigableRole navigableRole; private final NavigableRole navigableRole;
private final EntityMappingType entityMapping; private final EntityMappingType entityMapping;
private final List<SingularAttributeMapping> idAttributeMappings; private final List<SingularAttributeMapping> idAttributeMappings;
private final StateArrayContributorMetadataAccess attributeMetadataAccess;
private final String rootTableName;
private final List<String> idColumnNames;
public NonAggregatedIdentifierMappingImpl( public NonAggregatedIdentifierMappingImpl(
EmbeddableMappingType embeddableDescriptor,
EntityMappingType entityMapping, EntityMappingType entityMapping,
List<SingularAttributeMapping> idAttributeMappings, List<SingularAttributeMapping> idAttributeMappings,
Component bootIdDescriptor, StateArrayContributorMetadataAccess attributeMetadataAccess,
CompositeType cidType, String rootTableName,
String[] rootTableKeyColumnNames,
Component bootCidDescriptor,
Component bootIdClassDescriptor,
MappingModelCreationProcess creationProcess) { MappingModelCreationProcess creationProcess) {
// todo (6.0) : handle MapsId and IdClass // 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.entityMapping = entityMapping;
this.idAttributeMappings = idAttributeMappings; this.idAttributeMappings = idAttributeMappings;
this.attributeMetadataAccess = attributeMetadataAccess;
this.rootTableName = rootTableName;
this.idColumnNames = Arrays.asList( rootTableKeyColumnNames );
this.navigableRole = entityMapping.getNavigableRole().appendContainer( EntityIdentifierMapping.ROLE_LOCAL_NAME );
} }
@Override @Override
@ -68,8 +105,8 @@ public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMa
} }
@Override @Override
public EntityMappingType getMappedTypeDescriptor() { public EmbeddableMappingType getMappedTypeDescriptor() {
return entityMapping; return embeddableDescriptor;
} }
@Override @Override
@ -103,8 +140,12 @@ public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMa
TableGroup tableGroup, TableGroup tableGroup,
String resultVariable, String resultVariable,
DomainResultCreationState creationState) { DomainResultCreationState creationState) {
// we will need a specialized impl for this return new EmbeddableResultImpl<>(
throw new NotYetImplementedFor6Exception( getClass() ); navigablePath,
this,
resultVariable,
creationState
);
} }
@Override @Override
@ -112,4 +153,109 @@ public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMa
return entityMapping; return entityMapping;
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EmbeddableValuedFetchable
@Override
public EmbeddableMappingType getEmbeddableTypeDescriptor() {
return getMappedTypeDescriptor();
}
@Override
public String getContainingTableExpression() {
return rootTableName;
}
@Override
public List<String> 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<ModelPart> 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();
}
} }

View File

@ -81,6 +81,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
public SingularAssociationAttributeMapping( public SingularAssociationAttributeMapping(
String name, String name,
NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
ToOne bootValue, ToOne bootValue,
StateArrayContributorMetadataAccess attributeMetadataAccess, StateArrayContributorMetadataAccess attributeMetadataAccess,
@ -124,7 +125,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
cardinality = Cardinality.ONE_TO_ONE; cardinality = Cardinality.ONE_TO_ONE;
} }
this.navigableRole = declaringType.getNavigableRole().appendContainer( name ); this.navigableRole = navigableRole;
} }
public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) { public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) {

View File

@ -41,8 +41,10 @@ public abstract class AbstractIdentifiableType<J>
private final boolean hasIdentifierProperty; private final boolean hasIdentifierProperty;
private final boolean hasIdClass; private final boolean hasIdClass;
private SingularPersistentAttribute<J,?> id; private SingularPersistentAttribute<J,?> id;
private Set<SingularPersistentAttribute<? super J,?>> idClassAttributes; private Set<SingularPersistentAttribute<? super J,?>> nonAggregatedIdAttributes;
private SqmPathSource identifierDescriptor; private SqmPathSource identifierDescriptor;
@ -221,8 +223,8 @@ public abstract class AbstractIdentifiableType<J>
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void visitIdClassAttributes(Consumer<SingularPersistentAttribute<? super J, ?>> attributeConsumer) { public void visitIdClassAttributes(Consumer<SingularPersistentAttribute<? super J, ?>> attributeConsumer) {
if ( idClassAttributes != null ) { if ( nonAggregatedIdAttributes != null ) {
idClassAttributes.forEach( attributeConsumer ); nonAggregatedIdAttributes.forEach( attributeConsumer );
} }
else if ( getSuperType() != null ) { else if ( getSuperType() != null ) {
getSuperType().visitIdClassAttributes( (Consumer) attributeConsumer ); getSuperType().visitIdClassAttributes( (Consumer) attributeConsumer );
@ -305,6 +307,7 @@ public abstract class AbstractIdentifiableType<J>
return versionAttribute; return versionAttribute;
} }
@SuppressWarnings({"rawtypes", "unchecked"})
private class InFlightAccessImpl extends AbstractManagedType.InFlightAccessImpl { private class InFlightAccessImpl extends AbstractManagedType.InFlightAccessImpl {
private final AbstractManagedType.InFlightAccess managedTypeAccess; private final AbstractManagedType.InFlightAccess managedTypeAccess;
@ -313,23 +316,28 @@ public abstract class AbstractIdentifiableType<J>
} }
@Override @Override
@SuppressWarnings("unchecked")
public void applyIdAttribute(SingularPersistentAttribute idAttribute) { public void applyIdAttribute(SingularPersistentAttribute idAttribute) {
AbstractIdentifiableType.this.id = idAttribute; AbstractIdentifiableType.this.id = idAttribute;
managedTypeAccess.addAttribute( idAttribute ); managedTypeAccess.addAttribute( idAttribute );
} }
@Override @Override
@SuppressWarnings("unchecked") public void applyNonAggregatedIdAttributes(Set idAttributes) {
public void applyIdClassAttributes(Set idClassAttributes) { if ( AbstractIdentifiableType.this.id != null ) {
for ( SingularAttribute idClassAttribute : ( (Set<SingularPersistentAttribute>) idClassAttributes ) ) { throw new IllegalArgumentException( "`AbstractIdentifiableType#id` already set on call to `#applyNonAggregatedIdAttribute`" );
if ( AbstractIdentifiableType.this == idClassAttribute.getDeclaringType() ) { }
@SuppressWarnings({ "unchecked" })
SingularPersistentAttribute<J,?> declaredAttribute = (SingularPersistentAttribute) idClassAttribute; if ( nonAggregatedIdAttributes != null ) {
addAttribute( declaredAttribute ); throw new IllegalStateException( "Non-aggregated id attributes were already set" );
}
for ( SingularPersistentAttribute idAttribute : (Set<SingularPersistentAttribute>) idAttributes ) {
if ( AbstractIdentifiableType.this == idAttribute.getDeclaringType() ) {
addAttribute( idAttribute );
} }
} }
AbstractIdentifiableType.this.idClassAttributes = idClassAttributes;
AbstractIdentifiableType.this.nonAggregatedIdAttributes = (Set) idAttributes;
} }
@Override @Override
@ -383,7 +391,7 @@ public abstract class AbstractIdentifiableType<J>
); );
} }
} }
else if ( idClassAttributes != null && ! idClassAttributes.isEmpty() ) { else if ( nonAggregatedIdAttributes != null && ! nonAggregatedIdAttributes.isEmpty() ) {
// non-aggregate composite id // non-aggregate composite id
return new NonAggregatedCompositeSqmPathSource( return new NonAggregatedCompositeSqmPathSource(
EntityIdentifierMapping.ROLE_LOCAL_NAME, EntityIdentifierMapping.ROLE_LOCAL_NAME,

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.metamodel.model.domain.internal; package org.hibernate.metamodel.model.domain.internal;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute;
@ -23,12 +24,27 @@ public interface AttributeContainer<J> {
interface InFlightAccess<J> { interface InFlightAccess<J> {
void addAttribute(PersistentAttribute<J,?> attribute); void addAttribute(PersistentAttribute<J,?> 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<J, ?> idAttribute) { default void applyIdAttribute(SingularPersistentAttribute<J, ?> idAttribute) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"AttributeContainer [" + getClass().getName() + "] does not support identifiers" "AttributeContainer [" + getClass().getName() + "] does not support identifiers"
); );
} }
default void applyNonAggregatedIdAttributes(Set<SingularPersistentAttribute<? super J, ?>> 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<SingularPersistentAttribute<? super J, ?>> idClassAttributes) { default void applyIdClassAttributes(Set<SingularPersistentAttribute<? super J, ?>> idClassAttributes) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"AttributeContainer [" + getClass().getName() + "] does not support identifiers" "AttributeContainer [" + getClass().getName() + "] does not support identifiers"

View File

@ -50,6 +50,7 @@ import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor; import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.spi.DynamicModelJtd;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**
@ -515,12 +516,14 @@ public class JpaMetamodelImpl implements JpaMetamodel {
PersistentClass persistentClass, PersistentClass persistentClass,
MetadataContext context, MetadataContext context,
TypeConfiguration typeConfiguration) { TypeConfiguration typeConfiguration) {
final Class javaType = persistentClass.getMappedClass();
context.pushEntityWorkedOn( persistentClass ); context.pushEntityWorkedOn( persistentClass );
final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass(); final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass();
IdentifiableDomainType<?> superType = superMappedSuperclass == null IdentifiableDomainType<?> superType = superMappedSuperclass == null
? null ? null
: locateOrBuildMappedSuperclassType( superMappedSuperclass, context, typeConfiguration ); : locateOrBuildMappedSuperclassType( superMappedSuperclass, context, typeConfiguration );
//no mappedSuperclass, check for a super entity //no mappedSuperclass, check for a super entity
if ( superType == null ) { if ( superType == null ) {
final PersistentClass superPersistentClass = persistentClass.getSuperclass(); final PersistentClass superPersistentClass = persistentClass.getSuperclass();
@ -529,17 +532,28 @@ public class JpaMetamodelImpl implements JpaMetamodel {
: locateOrBuildEntityType( superPersistentClass, context, typeConfiguration ); : locateOrBuildEntityType( superPersistentClass, context, typeConfiguration );
} }
final JavaTypeDescriptor javaTypeDescriptor = context.getTypeConfiguration() final Class<?> javaType = persistentClass.getMappedClass();
.getJavaTypeDescriptorRegistry() final JavaTypeDescriptor<?> javaTypeDescriptor;
.getDescriptor( javaType ); if ( javaType == null || Map.class.isAssignableFrom( javaType ) ) {
final EntityTypeImpl entityType = new EntityTypeImpl( // dynamic map
javaTypeDescriptor = new DynamicModelJtd();
}
else {
javaTypeDescriptor = context.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( javaType );
}
final EntityTypeImpl<?> entityType = new EntityTypeImpl(
javaTypeDescriptor, javaTypeDescriptor,
superType, superType,
persistentClass, persistentClass,
this this
); );
context.registerEntityType( persistentClass, entityType ); context.registerEntityType( persistentClass, entityType );
context.popEntityWorkedOn( persistentClass ); context.popEntityWorkedOn( persistentClass );
return entityType; return entityType;
} }

View File

@ -6039,83 +6039,17 @@ public abstract class AbstractEntityPersister
private EntityIdentifierMapping generateNonEncapsulatedCompositeIdentifierMapping( private EntityIdentifierMapping generateNonEncapsulatedCompositeIdentifierMapping(
MappingModelCreationProcess creationProcess, MappingModelCreationProcess creationProcess,
PersistentClass bootEntityDescriptor, CompositeType cidType) { PersistentClass bootEntityDescriptor,
// process all of the defined "id attributes" because they are declared on the entity CompositeType cidType) {
final Component bootIdDescriptor = (Component) bootEntityDescriptor.getIdentifier(); assert declaredAttributeMappings != null;
final List<SingularAttributeMapping> 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 );
return MappingModelCreationHelper.buildNonEncapsulatedCompositeIdentifierMapping( return MappingModelCreationHelper.buildNonEncapsulatedCompositeIdentifierMapping(
this, this,
idAttributeMappings, getRootTableName(),
getRootTableKeyColumnNames(),
cidType, cidType,
bootEntityDescriptor, bootEntityDescriptor,
declaredAttributeMappings::put,
creationProcess creationProcess
); );
} }
@ -6167,6 +6101,7 @@ public abstract class AbstractEntityPersister
if ( propertyIndex == getVersionProperty() ) { if ( propertyIndex == getVersionProperty() ) {
return MappingModelCreationHelper.buildBasicAttributeMapping( return MappingModelCreationHelper.buildBasicAttributeMapping(
attrName, attrName,
getNavigableRole().append( bootProperty.getName() ),
stateArrayPosition, stateArrayPosition,
bootProperty, bootProperty,
this, this,
@ -6182,6 +6117,7 @@ public abstract class AbstractEntityPersister
if ( attrType instanceof BasicType ) { if ( attrType instanceof BasicType ) {
return MappingModelCreationHelper.buildBasicAttributeMapping( return MappingModelCreationHelper.buildBasicAttributeMapping(
attrName, attrName,
getNavigableRole().append( bootProperty.getName() ),
stateArrayPosition, stateArrayPosition,
bootProperty, bootProperty,
this, this,
@ -6222,6 +6158,7 @@ public abstract class AbstractEntityPersister
else if ( attrType instanceof EntityType ) { else if ( attrType instanceof EntityType ) {
SingularAssociationAttributeMapping attributeMapping = MappingModelCreationHelper.buildSingularAssociationAttributeMapping( SingularAssociationAttributeMapping attributeMapping = MappingModelCreationHelper.buildSingularAssociationAttributeMapping(
attrName, attrName,
getNavigableRole().append( attrName ),
stateArrayPosition, stateArrayPosition,
bootProperty, bootProperty,
this, this,

View File

@ -9,6 +9,7 @@ package org.hibernate.query.hql.internal;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.grammars.hql.HqlLexer; import org.hibernate.grammars.hql.HqlLexer;
import org.hibernate.grammars.hql.HqlParser; import org.hibernate.grammars.hql.HqlParser;
import org.hibernate.query.hql.HqlLogger;
import org.hibernate.query.sqm.InterpretationException; import org.hibernate.query.sqm.InterpretationException;
import org.hibernate.query.hql.HqlTranslator; import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.sqm.internal.SqmTreePrinter; import org.hibernate.query.sqm.internal.SqmTreePrinter;
@ -31,6 +32,7 @@ public class StandardHqlTranslator implements HqlTranslator {
private final SqmCreationContext sqmCreationContext; private final SqmCreationContext sqmCreationContext;
private final SqmCreationOptions sqmCreationOptions; private final SqmCreationOptions sqmCreationOptions;
public StandardHqlTranslator( public StandardHqlTranslator(
SqmCreationContext sqmCreationContext, SqmCreationContext sqmCreationContext,
SqmCreationOptions sqmCreationOptions) { SqmCreationOptions sqmCreationOptions) {
@ -40,6 +42,8 @@ public class StandardHqlTranslator implements HqlTranslator {
@Override @Override
public SqmStatement translate(String query) { public SqmStatement translate(String query) {
HqlLogger.QUERY_LOGGER.debugf( "HQL : " + query );
final HqlParser.StatementContext hqlParseTree = parseHql( query ); final HqlParser.StatementContext hqlParseTree = parseHql( query );
// then we perform semantic analysis and build the semantic representation... // then we perform semantic analysis and build the semantic representation...

View File

@ -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<Map<?,?>> {
@Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) {
throw new UnsupportedOperationException();
}
@Override
public Map<?,?> fromString(String string) {
throw new UnsupportedOperationException();
}
@Override
public <X> X unwrap(Map<?,?> value, Class<X> type, WrapperOptions options) {
throw new UnsupportedOperationException();
}
@Override
public <X> Map<?,?> wrap(X value, WrapperOptions options) {
throw new UnsupportedOperationException();
}
@Override
public Class<Map<?,?>> getJavaTypeClass() {
//noinspection unchecked,rawtypes
return (Class) Map.class;
}
}

View File

@ -7,16 +7,12 @@
package org.hibernate.type.descriptor.java.spi; package org.hibernate.type.descriptor.java.spi;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor; import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.SerializableTypeDescriptor; 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.TypeConfiguration;
import org.hibernate.type.spi.TypeConfigurationAware; import org.hibernate.type.spi.TypeConfigurationAware;
@ -155,34 +151,8 @@ public class JavaTypeDescriptorRegistry implements JavaTypeDescriptorBaseline.Ba
); );
} }
public JavaTypeDescriptor<?> resolveDynamicDescriptor(String typeName) { public JavaTypeDescriptor<?> resolveDynamicEntityDescriptor(String typeName) {
return new DynamicJtd(); return new DynamicModelJtd();
} }
private static class DynamicJtd implements JavaTypeDescriptor<Map> {
@Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) {
throw new UnsupportedOperationException();
}
@Override
public Map fromString(String string) {
throw new UnsupportedOperationException();
}
@Override
public <X> X unwrap(Map value, Class<X> type, WrapperOptions options) {
throw new UnsupportedOperationException();
}
@Override
public <X> Map wrap(X value, WrapperOptions options) {
throw new UnsupportedOperationException();
}
@Override
public Class<Map> getJavaTypeClass() {
return Map.class;
}
}
} }

View File

@ -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;
}
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ 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
-->
<hibernate-mapping auto-import="false" xmlns="http://www.hibernate.org/xsd/orm/hbm">
<class table="hbm_dynamic_cid_basic" entity-name="DynamicCompositeIdBasic" abstract="false">
<composite-id name="id">
<key-property name="key1" type="integer"/>
<key-property name="key2" type="integer"/>
</composite-id>
<property insert="true" name="attr1" type="string"/>
</class>
</hibernate-mapping>

View File

@ -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();
}
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ 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
-->
<hibernate-mapping xmlns="http://www.hibernate.org/xsd/orm/hbm" package="org.hibernate.orm.test.bootstrap.binding.hbm.cid.nonaggregated.dynamic">
<class name="ChangeGroup">
<id name="id"/>
<property name="name" />
</class>
<class entity-name="DynamicCompositeIdManyToOne" table="hbm_dynamic_cid_m2o" >
<composite-id name="id">
<key-property name="key1" type="integer"/>
<key-many-to-one name="key2" class="ChangeGroup"/>
</composite-id>
<property name="attr1" type="string"/>
</class>
</hibernate-mapping>

View File

@ -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();
}
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ 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
-->
<hibernate-mapping xmlns="http://www.hibernate.org/xsd/orm/hbm" >
<class entity-name="SimpleDynamicEntity" table="hbm_simple_entity_dynamic" >
<id name="id" type="integer"/>
<property name="name" type="string"/>
</class>
</hibernate-mapping>

View File

@ -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();
}
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ 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
-->
<hibernate-mapping xmlns="http://www.hibernate.org/xsd/orm/hbm" package="org.hibernate.orm.test.bootstrap.binding.hbm.simple.pojo">
<class name="SimpleEntity" table="hbm_simple_entity_pojo" >
<id name="id"/>
<property name="name"/>
</class>
</hibernate-mapping>

View File

@ -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;
}
}

View File

@ -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() );
}
}

View File

@ -28,7 +28,7 @@ public class SimpleOpsTest extends AbstractOperationTestCase {
} }
public String[] getMappings() { public String[] getMappings() {
return new String[] { "ops/SimpleEntity.hbm.xml" }; return new String[] { "ops/SimpleDynamicEntity.hbm.xml" };
} }
@Test @Test

View File

@ -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);
}

View File

@ -28,6 +28,7 @@ import org.hibernate.boot.model.source.internal.hbm.MappingDocument;
import org.hibernate.boot.spi.AdditionalJaxbMappingProducer; import org.hibernate.boot.spi.AdditionalJaxbMappingProducer;
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.envers.boot.EnversBootLogger;
import org.hibernate.envers.configuration.internal.MappingCollector; import org.hibernate.envers.configuration.internal.MappingCollector;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
@ -63,21 +64,12 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP
// atm we do not have distinct origin info for envers // atm we do not have distinct origin info for envers
final Origin origin = new Origin( SourceType.OTHER, "envers" ); final Origin origin = new Origin( SourceType.OTHER, "envers" );
// final DOMWriter writer = new DOMWriter();
final MappingCollector mappingCollector = new MappingCollector() { final MappingCollector mappingCollector = new MappingCollector() {
@Override @Override
public void addDocument(Document document) throws DocumentException { 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(); final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try { try {
final Writer w = new BufferedWriter( new OutputStreamWriter( baos, "UTF-8" ) ); 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 ); throw new HibernateException( "Unable to bind Envers-generated XML", e );
} }
ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() ); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( baos.toByteArray() );
BufferedInputStream bis = new BufferedInputStream( bais ); BufferedInputStream bufferedInputStream = new BufferedInputStream( byteArrayInputStream );
final Binding jaxbBinding = mappingBinder.bind( bis, origin ); final Binding<JaxbHbmHibernateMapping> jaxbBinding = mappingBinder.bind( bufferedInputStream, origin );
final JaxbHbmHibernateMapping jaxbRoot = (JaxbHbmHibernateMapping) jaxbBinding.getRoot(); final JaxbHbmHibernateMapping jaxbRoot = jaxbBinding.getRoot();
additionalMappingDocuments.add( new MappingDocument( jaxbRoot, origin, buildingContext ) ); additionalMappingDocuments.add( new MappingDocument( jaxbRoot, origin, buildingContext ) );
} }
}; };
@ -103,13 +95,13 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP
return additionalMappingDocuments; return additionalMappingDocuments;
} }
private static void dump(Document document) { private static void logXml(Document document) {
if ( !log.isTraceEnabled() ) { if ( ! EnversBootLogger.DEBUG_ENABLED ) {
return; return;
} }
final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final Writer w = new PrintWriter( baos ); final Writer w = new PrintWriter( outputStream );
try { try {
final XMLWriter xw = new XMLWriter( w, new OutputFormat( " ", true ) ); 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 ); 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( "------------------------------------------------------------" ); log.trace( "------------------------------------------------------------" );
} }
} }

View File

@ -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.BasicBinder=trace
log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace
log4j.logger.org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl=trace 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

View File

@ -9,6 +9,8 @@ package org.hibernate.testing.boot;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import javax.xml.bind.JAXBContext;
import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.CacheRegionDefinition; import org.hibernate.boot.CacheRegionDefinition;
import org.hibernate.boot.archive.scan.spi.ScanEnvironment; import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
@ -141,13 +143,13 @@ public class BootstrapContextImpl implements BootstrapContext {
return delegate.getCacheRegionDefinitions(); return delegate.getCacheRegionDefinitions();
} }
@Override
public void release() {
delegate.release();
}
@Override @Override
public ManagedTypeRepresentationResolver getRepresentationStrategySelector() { public ManagedTypeRepresentationResolver getRepresentationStrategySelector() {
return StandardManagedTypeRepresentationResolver.INSTANCE; return StandardManagedTypeRepresentationResolver.INSTANCE;
} }
@Override
public void release() {
delegate.release();
}
} }