* 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
|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.JarFileEntryXmlSource;
import org.hibernate.boot.jaxb.internal.JaxpSourceXmlSource;
import org.hibernate.boot.jaxb.internal.XmlSources;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.jaxb.spi.XmlSource;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
@ -59,10 +61,11 @@ public class MetadataSources implements Serializable {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( MetadataSources.class );
private final ServiceRegistry serviceRegistry;
private final ClassLoaderService classLoaderService;
private XmlMappingBinderAccess xmlMappingBinderAccess;
private List<Binding> xmlBindings;
private List<Binding<?>> xmlBindings;
private LinkedHashSet<Class<?>> annotatedClasses;
private LinkedHashSet<String> annotatedClassNames;
private LinkedHashSet<String> annotatedPackages;
@ -90,11 +93,12 @@ public class MetadataSources implements Serializable {
}
}
this.serviceRegistry = serviceRegistry;
this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
}
protected static boolean isExpectedServiceRegistryType(ServiceRegistry serviceRegistry) {
return BootstrapServiceRegistry.class.isInstance( serviceRegistry )
|| StandardServiceRegistry.class.isInstance( serviceRegistry );
return serviceRegistry instanceof BootstrapServiceRegistry
|| serviceRegistry instanceof StandardServiceRegistry;
}
public XmlMappingBinderAccess getXmlMappingBinderAccess() {
@ -104,7 +108,7 @@ public class MetadataSources implements Serializable {
return xmlMappingBinderAccess;
}
public List<Binding> getXmlBindings() {
public List<Binding<?>> getXmlBindings() {
return xmlBindings == null ? Collections.emptyList() : xmlBindings;
}
@ -332,7 +336,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes)
*/
public MetadataSources addResource(String name) {
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( name ) );
final XmlSource xmlSource = XmlSources.fromResource( name, classLoaderService );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this;
}
@ -358,7 +364,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes)
*/
public MetadataSources addFile(File file) {
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( file ) );
final XmlSource xmlSource = XmlSources.fromFile( file );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this;
}
@ -372,15 +380,10 @@ public class MetadataSources implements Serializable {
* @see #addCacheableFile(java.io.File)
*/
public MetadataSources addCacheableFile(String path) {
final Origin origin = new Origin( SourceType.FILE, path );
addCacheableFile( origin, new File( path ) );
addCacheableFile( new File( path ) );
return this;
}
private void addCacheableFile(Origin origin, File file) {
getXmlBindingsForWrite().add( new CacheableFileXmlSource( origin, file, false ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
}
/**
* Add a cached mapping file. A cached file is a serialized representation of the DOM structure of a
* particular mapping. It is saved from a previous call as a file with the name {@code {xmlFile}.bin}
@ -395,8 +398,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes)
*/
public MetadataSources addCacheableFile(File file) {
final Origin origin = new Origin( SourceType.FILE, file.getName() );
addCacheableFile( origin, file );
final XmlSource xmlSource = XmlSources.fromCacheableFile( file );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this;
}
@ -413,9 +417,10 @@ public class MetadataSources implements Serializable {
* @throws org.hibernate.type.SerializationException Indicates a problem deserializing the cached dom tree
* @throws java.io.FileNotFoundException Indicates that the cached file was not found or was not usable.
*/
public MetadataSources addCacheableFileStrictly(File file) throws SerializationException, FileNotFoundException {
final Origin origin = new Origin( SourceType.FILE, file.getAbsolutePath() );
getXmlBindingsForWrite().add( new CacheableFileXmlSource( origin, file, true ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
public MetadataSources addCacheableFileStrictly(File file) throws SerializationException {
final XmlSource xmlSource = XmlSources.fromCacheableFile( file, true );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this;
}
@ -427,7 +432,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes)
*/
public MetadataSources addInputStream(InputStreamAccess xmlInputStreamAccess) {
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( xmlInputStreamAccess ) );
final XmlSource xmlSource = XmlSources.fromStream( xmlInputStreamAccess );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this;
}
@ -439,7 +446,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes)
*/
public MetadataSources addInputStream(InputStream xmlInputStream) {
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( xmlInputStream ) );
final XmlSource xmlSource = XmlSources.fromStream( xmlInputStream );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this;
}
@ -451,7 +460,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes)
*/
public MetadataSources addURL(URL url) {
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( url ) );
final XmlSource xmlSource = XmlSources.fromUrl( url );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this;
}
@ -466,8 +477,9 @@ public class MetadataSources implements Serializable {
*/
@Deprecated
public MetadataSources addDocument(Document document) {
final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH );
getXmlBindingsForWrite().add( new JaxpSourceXmlSource( origin, new DOMSource( document ) ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
final XmlSource xmlSource = XmlSources.fromDocument( document );
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) );
return this;
}
@ -481,42 +493,15 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes)
*/
public MetadataSources addJar(File jar) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Seeking mapping documents in jar file : %s", jar.getName() );
}
final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() );
try {
JarFile jarFile = new JarFile( jar );
final boolean TRACE = LOG.isTraceEnabled();
try {
Enumeration jarEntries = jarFile.entries();
while ( jarEntries.hasMoreElements() ) {
final ZipEntry zipEntry = (ZipEntry) jarEntries.nextElement();
if ( zipEntry.getName().endsWith( ".hbm.xml" ) ) {
if ( TRACE ) {
LOG.tracef( "found mapping document : %s", zipEntry.getName() );
}
getXmlBindingsForWrite().add(
new JarFileEntryXmlSource( origin, jarFile, zipEntry ).doBind( getXmlMappingBinderAccess().getMappingBinder() )
);
}
}
}
finally {
try {
jarFile.close();
}
catch ( Exception ignore ) {
}
}
}
catch ( IOException e ) {
throw new MappingNotFoundException( e, origin );
}
final XmlMappingBinderAccess binderAccess = getXmlMappingBinderAccess();
XmlSources.fromJar(
jar,
xmlSource -> getXmlBindingsForWrite().add( xmlSource.doBind( binderAccess.getMappingBinder() ) )
);
return this;
}
private <Binding> List getXmlBindingsForWrite() {
private List<Binding<?>> getXmlBindingsForWrite() {
if ( xmlBindings == null ) {
xmlBindings = new ArrayList<>();
}

View File

@ -6,7 +6,9 @@
*/
package org.hibernate.boot.archive.spi;
import java.io.IOException;
import java.io.InputStream;
import java.util.function.Function;
/**
* Contract for building InputStreams, especially in on-demand situations
@ -19,12 +21,26 @@ public interface InputStreamAccess {
*
* @return The backing resource name
*/
public String getStreamName();
String getStreamName();
/**
* Get access to the stream. Can be called multiple times, a different stream instance should be returned each time.
*
* @return The stream
*/
public InputStream accessInputStream();
InputStream accessInputStream();
default <X> 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 final StandardServiceRegistry serviceRegistry;
private final MutableJpaCompliance jpaCompliance;
private final MetadataBuildingOptions metadataBuildingOptions;
private final TypeConfiguration typeConfiguration;
private final MutableJpaCompliance jpaCompliance;
private final ClassLoaderAccessImpl classLoaderAccess;
private boolean isJpaBootstrap;
private final JavaReflectionManager hcannReflectionManager;
private final ClassmateContext classmateContext;
private final MetadataBuildingOptions metadataBuildingOptions;
private boolean isJpaBootstrap;
private ScanOptions scanOptions;
private ScanEnvironment scanEnvironment;
@ -76,7 +75,7 @@ public class BootstrapContextImpl implements BootstrapContext {
private HashMap<String,SqmFunctionDescriptor> sqlFunctionMap;
private ArrayList<AuxiliaryDatabaseObject> auxiliaryDatabaseObjectList;
private HashMap<Class, ConverterDescriptor> attributeConverterDescriptorMap;
private HashMap<Class<?>, ConverterDescriptor> attributeConverterDescriptorMap;
private ArrayList<CacheRegionDefinition> cacheRegionDefinitions;
private ManagedTypeRepresentationResolver representationStrategySelector;
@ -87,8 +86,7 @@ public class BootstrapContextImpl implements BootstrapContext {
this.classmateContext = new ClassmateContext();
this.metadataBuildingOptions = metadataBuildingOptions;
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
this.classLoaderAccess = new ClassLoaderAccessImpl( classLoaderService );
this.classLoaderAccess = new ClassLoaderAccessImpl( serviceRegistry.getService( ClassLoaderService.class ) );
this.hcannReflectionManager = generateHcannReflectionManager();
final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class );

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

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

View File

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

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 {
// if we get here, we should have a composite identifier. Just need
// to determine if it is aggregated, or non-aggregated...
if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getName() ) ) {
if ( rootEntitySource.jaxbEntityMapping().getCompositeId().isMapped()
&& StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getClazz() ) ) {
if ( rootEntitySource.jaxbEntityMapping().getCompositeId().isMapped() ) {
if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getClazz() ) ) {
throw new MappingException(
"mapped composite identifier must name component class to use.",
rootEntitySource.origin()
);
}
}
if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getClazz() ) ) {
if ( StringHelper.isEmpty( rootEntitySource.jaxbEntityMapping().getCompositeId().getName() ) ) {
throw new MappingException(
"dynamic composite-id must specify name",
rootEntitySource.origin()
);
}
// we have a non-aggregated id without an IdClass
return new IdentifierSourceNonAggregatedCompositeImpl( rootEntitySource );
}
else if ( rootEntitySource.jaxbEntityMapping().getCompositeId().isMapped() ) {
// we have a non-aggregated id with an IdClass
return new IdentifierSourceNonAggregatedCompositeImpl( rootEntitySource );
}
else {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,21 +6,44 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.Component;
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl;
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl;
import org.hibernate.type.CompositeType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -33,23 +56,37 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
*
* @author Steve Ebersole
*/
public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMapping {
public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMapping, EmbeddableValuedFetchable {
private final EmbeddableMappingType embeddableDescriptor;
private final NavigableRole navigableRole;
private final EntityMappingType entityMapping;
private final List<SingularAttributeMapping> idAttributeMappings;
private final StateArrayContributorMetadataAccess attributeMetadataAccess;
private final String rootTableName;
private final List<String> idColumnNames;
public NonAggregatedIdentifierMappingImpl(
EmbeddableMappingType embeddableDescriptor,
EntityMappingType entityMapping,
List<SingularAttributeMapping> idAttributeMappings,
Component bootIdDescriptor,
CompositeType cidType,
StateArrayContributorMetadataAccess attributeMetadataAccess,
String rootTableName,
String[] rootTableKeyColumnNames,
Component bootCidDescriptor,
Component bootIdClassDescriptor,
MappingModelCreationProcess creationProcess) {
// todo (6.0) : handle MapsId and IdClass
// todo (6.0) : implement SQL AST apis (DomainResult, e.g.)
this.navigableRole = entityMapping.getNavigableRole().appendContainer( EntityIdentifierMapping.ROLE_LOCAL_NAME );
this.embeddableDescriptor = embeddableDescriptor;
this.entityMapping = entityMapping;
this.idAttributeMappings = idAttributeMappings;
this.attributeMetadataAccess = attributeMetadataAccess;
this.rootTableName = rootTableName;
this.idColumnNames = Arrays.asList( rootTableKeyColumnNames );
this.navigableRole = entityMapping.getNavigableRole().appendContainer( EntityIdentifierMapping.ROLE_LOCAL_NAME );
}
@Override
@ -68,8 +105,8 @@ public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMa
}
@Override
public EntityMappingType getMappedTypeDescriptor() {
return entityMapping;
public EmbeddableMappingType getMappedTypeDescriptor() {
return embeddableDescriptor;
}
@Override
@ -103,8 +140,12 @@ public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMa
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
// we will need a specialized impl for this
throw new NotYetImplementedFor6Exception( getClass() );
return new EmbeddableResultImpl<>(
navigablePath,
this,
resultVariable,
creationState
);
}
@Override
@ -112,4 +153,109 @@ public class NonAggregatedIdentifierMappingImpl implements CompositeIdentifierMa
return entityMapping;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EmbeddableValuedFetchable
@Override
public EmbeddableMappingType getEmbeddableTypeDescriptor() {
return getMappedTypeDescriptor();
}
@Override
public String getContainingTableExpression() {
return rootTableName;
}
@Override
public List<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(
String name,
NavigableRole navigableRole,
int stateArrayPosition,
ToOne bootValue,
StateArrayContributorMetadataAccess attributeMetadataAccess,
@ -124,7 +125,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
cardinality = Cardinality.ONE_TO_ONE;
}
this.navigableRole = declaringType.getNavigableRole().appendContainer( name );
this.navigableRole = navigableRole;
}
public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) {

View File

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

View File

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

View File

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

View File

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

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;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.SerializableTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.type.spi.TypeConfigurationAware;
@ -155,34 +151,8 @@ public class JavaTypeDescriptorRegistry implements JavaTypeDescriptorBaseline.Ba
);
}
public JavaTypeDescriptor<?> resolveDynamicDescriptor(String typeName) {
return new DynamicJtd();
public JavaTypeDescriptor<?> resolveDynamicEntityDescriptor(String typeName) {
return new DynamicModelJtd();
}
private static class DynamicJtd implements JavaTypeDescriptor<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() {
return new String[] { "ops/SimpleEntity.hbm.xml" };
return new String[] { "ops/SimpleDynamicEntity.hbm.xml" };
}
@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.MetadataBuildingContext;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.envers.boot.EnversBootLogger;
import org.hibernate.envers.configuration.internal.MappingCollector;
import org.hibernate.service.ServiceRegistry;
@ -63,21 +64,12 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP
// atm we do not have distinct origin info for envers
final Origin origin = new Origin( SourceType.OTHER, "envers" );
// final DOMWriter writer = new DOMWriter();
final MappingCollector mappingCollector = new MappingCollector() {
@Override
public void addDocument(Document document) throws DocumentException {
dump( document );
logXml( document );
// while the commented-out code here is more efficient (well, understanding that
// this whole process is un-efficient) it leads to un-decipherable messages when
// we get mapping mapping errors from envers output.
// final DOMSource domSource = new DOMSource( writer.write( document ) );
// domSource.setSystemId( "envers" );
// final Binding jaxbBinding = mappingBinder.bind( domSource, origin );
// this form at least allows us to get better error messages
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
final Writer w = new BufferedWriter( new OutputStreamWriter( baos, "UTF-8" ) );
@ -89,11 +81,11 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP
throw new HibernateException( "Unable to bind Envers-generated XML", e );
}
ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() );
BufferedInputStream bis = new BufferedInputStream( bais );
final Binding jaxbBinding = mappingBinder.bind( bis, origin );
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( baos.toByteArray() );
BufferedInputStream bufferedInputStream = new BufferedInputStream( byteArrayInputStream );
final Binding<JaxbHbmHibernateMapping> jaxbBinding = mappingBinder.bind( bufferedInputStream, origin );
final JaxbHbmHibernateMapping jaxbRoot = (JaxbHbmHibernateMapping) jaxbBinding.getRoot();
final JaxbHbmHibernateMapping jaxbRoot = jaxbBinding.getRoot();
additionalMappingDocuments.add( new MappingDocument( jaxbRoot, origin, buildingContext ) );
}
};
@ -103,13 +95,13 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP
return additionalMappingDocuments;
}
private static void dump(Document document) {
if ( !log.isTraceEnabled() ) {
private static void logXml(Document document) {
if ( ! EnversBootLogger.DEBUG_ENABLED ) {
return;
}
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Writer w = new PrintWriter( baos );
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final Writer w = new PrintWriter( outputStream );
try {
final XMLWriter xw = new XMLWriter( w, new OutputFormat( " ", true ) );
@ -120,7 +112,9 @@ public class AdditionalJaxbMappingProducerImpl implements AdditionalJaxbMappingP
throw new RuntimeException( "Error dumping enhanced class", e1 );
}
log.tracef( "Envers-generate entity mapping -----------------------------\n%s", baos.toString() );
EnversBootLogger.BOOT_LOGGER.jaxbContribution( outputStream.toString() );
log.tracef( "Envers-generate entity mapping -----------------------------\n%s", outputStream.toString() );
log.trace( "------------------------------------------------------------" );
}
}

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.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.Map;
import javax.xml.bind.JAXBContext;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.CacheRegionDefinition;
import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
@ -141,13 +143,13 @@ public class BootstrapContextImpl implements BootstrapContext {
return delegate.getCacheRegionDefinitions();
}
@Override
public void release() {
delegate.release();
}
@Override
public ManagedTypeRepresentationResolver getRepresentationStrategySelector() {
return StandardManagedTypeRepresentationResolver.INSTANCE;
}
@Override
public void release() {
delegate.release();
}
}