clean up CollectionBinder and friends
This commit is contained in:
parent
38b4e8e01b
commit
3cd90d7615
|
@ -26,6 +26,7 @@ import jakarta.persistence.MappedSuperclass;
|
|||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.TimeZoneStorageStrategy;
|
||||
import org.hibernate.annotations.ColumnTransformer;
|
||||
import org.hibernate.annotations.ColumnTransformers;
|
||||
|
@ -47,8 +48,6 @@ import org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType;
|
|||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* No idea.
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public abstract class AbstractPropertyHolder implements PropertyHolder {
|
||||
|
|
|
@ -35,7 +35,6 @@ import java.util.Map;
|
|||
import static org.hibernate.cfg.BinderHelper.findReferencedColumnOwner;
|
||||
import static org.hibernate.cfg.BinderHelper.getRelativePath;
|
||||
import static org.hibernate.cfg.BinderHelper.isEmptyOrNullAnnotationValue;
|
||||
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
|
||||
import static org.hibernate.internal.util.StringHelper.isQuoted;
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
|
||||
|
|
|
@ -1982,12 +1982,10 @@ public final class AnnotationBinder {
|
|||
Class<? extends CompositeUserType<?>> compositeUserTypeClass,
|
||||
MetadataBuildingContext buildingContext,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
/*
|
||||
* inSecondPass can only be used to apply right away the second pass of a composite-element
|
||||
* Because it's a value type, there is no bidirectional association, hence second pass
|
||||
* ordering does not matter
|
||||
*/
|
||||
Component comp = createComponent(
|
||||
// inSecondPass can only be used to apply right away the second pass of a composite-element
|
||||
// Because it's a value type, there is no bidirectional association, hence second pass
|
||||
// ordering does not matter
|
||||
final Component component = createComponent(
|
||||
propertyHolder,
|
||||
inferredData,
|
||||
isComponentEmbedded,
|
||||
|
@ -1996,17 +1994,16 @@ public final class AnnotationBinder {
|
|||
buildingContext
|
||||
);
|
||||
|
||||
String subpath = getPath( propertyHolder, inferredData );
|
||||
final String subpath = getPath( propertyHolder, inferredData );
|
||||
LOG.tracev( "Binding component with path: {0}", subpath );
|
||||
PropertyHolder subHolder = buildPropertyHolder(
|
||||
comp,
|
||||
final PropertyHolder subHolder = buildPropertyHolder(
|
||||
component,
|
||||
subpath,
|
||||
inferredData,
|
||||
propertyHolder,
|
||||
buildingContext
|
||||
);
|
||||
|
||||
|
||||
// propertyHolder here is the owner of the component property. Tell it we are about to start the component...
|
||||
|
||||
propertyHolder.startingProperty( inferredData.getProperty() );
|
||||
|
@ -2026,7 +2023,7 @@ public final class AnnotationBinder {
|
|||
.getService( ManagedBeanRegistry.class )
|
||||
.getBean( compositeUserTypeClass )
|
||||
.getBeanInstance();
|
||||
comp.setTypeName( compositeUserTypeClass.getName() );
|
||||
component.setTypeName( compositeUserTypeClass.getName() );
|
||||
returnedClassOrElement = buildingContext.getBootstrapContext().getReflectionManager().toXClass( compositeUserType.embeddable() );
|
||||
}
|
||||
|
||||
|
@ -2124,7 +2121,7 @@ public final class AnnotationBinder {
|
|||
if ( isGlobalGeneratorNameGlobal( buildingContext ) ) {
|
||||
buildGenerators( property, buildingContext );
|
||||
SecondPass secondPass = new IdGeneratorResolverSecondPass(
|
||||
(SimpleValue) comp.getProperty( property.getName() ).getValue(),
|
||||
(SimpleValue) component.getProperty( property.getName() ).getValue(),
|
||||
property,
|
||||
generatorType,
|
||||
generator,
|
||||
|
@ -2141,7 +2138,7 @@ public final class AnnotationBinder {
|
|||
Map<String, IdentifierGeneratorDefinition> localGenerators =
|
||||
new HashMap<>( buildGenerators( property, buildingContext ) );
|
||||
makeIdGenerator(
|
||||
(SimpleValue) comp.getProperty( property.getName() ).getValue(),
|
||||
(SimpleValue) component.getProperty( property.getName() ).getValue(),
|
||||
property,
|
||||
generatorType,
|
||||
generator,
|
||||
|
@ -2153,11 +2150,11 @@ public final class AnnotationBinder {
|
|||
}
|
||||
|
||||
if ( compositeUserType != null ) {
|
||||
comp.sortProperties();
|
||||
final List<String> sortedPropertyNames = new ArrayList<>( comp.getPropertySpan() );
|
||||
final List<Type> sortedPropertyTypes = new ArrayList<>( comp.getPropertySpan() );
|
||||
component.sortProperties();
|
||||
final List<String> sortedPropertyNames = new ArrayList<>( component.getPropertySpan() );
|
||||
final List<Type> sortedPropertyTypes = new ArrayList<>( component.getPropertySpan() );
|
||||
final PropertyAccessStrategy strategy = new PropertyAccessStrategyCompositeUserTypeImpl( compositeUserType, sortedPropertyNames, sortedPropertyTypes );
|
||||
for ( Property property : comp.getProperties() ) {
|
||||
for ( Property property : component.getProperties() ) {
|
||||
sortedPropertyNames.add( property.getName() );
|
||||
sortedPropertyTypes.add(
|
||||
PropertyAccessStrategyMixedImpl.INSTANCE.buildPropertyAccess(
|
||||
|
@ -2169,7 +2166,7 @@ public final class AnnotationBinder {
|
|||
property.setPropertyAccessStrategy( strategy );
|
||||
}
|
||||
}
|
||||
return comp;
|
||||
return component;
|
||||
}
|
||||
|
||||
public static Component createComponent(
|
||||
|
|
|
@ -107,6 +107,10 @@ public class BinderHelper {
|
|||
boolean.class.getName()
|
||||
);
|
||||
|
||||
public static boolean isPrimitive(String elementTypeName) {
|
||||
return PRIMITIVE_NAMES.contains( elementTypeName );
|
||||
}
|
||||
|
||||
/**
|
||||
* Here we address a fundamental problem: the {@code @JoinColumn}
|
||||
* annotation specifies the referenced column in the target table
|
||||
|
|
|
@ -17,7 +17,8 @@ import org.hibernate.resource.beans.spi.ManagedBean;
|
|||
import org.hibernate.usertype.UserCollectionType;
|
||||
|
||||
/**
|
||||
* Bind an Array
|
||||
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentArrayHolder primitive arrays},
|
||||
* whose mapping model type is {@link org.hibernate.mapping.Array}.
|
||||
*
|
||||
* @author Anthony Patricio
|
||||
*/
|
||||
|
|
|
@ -11,12 +11,12 @@ import java.util.function.Supplier;
|
|||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SemanticsResolver;
|
||||
import org.hibernate.resource.beans.spi.ManagedBean;
|
||||
import org.hibernate.usertype.UserCollectionType;
|
||||
|
||||
/**
|
||||
* Bind a bag.
|
||||
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentBag bags},
|
||||
* whose mapping model type is {@link org.hibernate.mapping.Bag}.
|
||||
*
|
||||
* @author Matthew Inger
|
||||
*/
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -89,7 +89,6 @@ import org.hibernate.boot.spi.InFlightMetadataCollector;
|
|||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.AccessType;
|
||||
import org.hibernate.cfg.AnnotatedClassType;
|
||||
import org.hibernate.cfg.AnnotatedColumn;
|
||||
import org.hibernate.cfg.AnnotatedColumns;
|
||||
import org.hibernate.cfg.AnnotatedDiscriminatorColumn;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumns;
|
||||
|
@ -1307,23 +1306,12 @@ public class EntityBinder {
|
|||
|
||||
private void bindhandleFilters() {
|
||||
for ( Filter filter : filters ) {
|
||||
final String filterName = filter.name();
|
||||
String condition = filter.condition();
|
||||
if ( isEmptyAnnotationValue( condition ) ) {
|
||||
final FilterDefinition definition = context.getMetadataCollector().getFilterDefinition( filterName );
|
||||
if ( definition == null ) {
|
||||
throw new AnnotationException( "Entity '" + name
|
||||
+ "' has a '@Filter' for an undefined filter named '" + filterName + "'" );
|
||||
}
|
||||
condition = definition.getDefaultFilterCondition();
|
||||
if ( isEmpty( condition ) ) {
|
||||
throw new AnnotationException( "Entity '" + name +
|
||||
"' has a '@Filter' with no 'condition' and no default condition was given by the '@FilterDef' named '"
|
||||
+ filterName + "'" );
|
||||
}
|
||||
condition = getDefaultFilterCondition(filter.name());
|
||||
}
|
||||
persistentClass.addFilter(
|
||||
filterName,
|
||||
filter.name(),
|
||||
condition,
|
||||
filter.deduceAliasInjectionPoints(),
|
||||
toAliasTableMap( filter.aliases() ),
|
||||
|
@ -1332,6 +1320,21 @@ public class EntityBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private String getDefaultFilterCondition(String filterName) {
|
||||
final FilterDefinition definition = context.getMetadataCollector().getFilterDefinition(filterName);
|
||||
if ( definition == null ) {
|
||||
throw new AnnotationException( "Entity '" + name
|
||||
+ "' has a '@Filter' for an undefined filter named '" + filterName + "'" );
|
||||
}
|
||||
final String condition = definition.getDefaultFilterCondition();
|
||||
if ( isEmpty( condition ) ) {
|
||||
throw new AnnotationException( "Entity '" + name +
|
||||
"' has a '@Filter' with no 'condition' and no default condition was given by the '@FilterDef' named '"
|
||||
+ filterName + "'" );
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
private void bindSynchronize() {
|
||||
if ( annotatedClass.isAnnotationPresent( Synchronize.class ) ) {
|
||||
final JdbcEnvironment jdbcEnvironment = context.getMetadataCollector().getDatabase().getJdbcEnvironment();
|
||||
|
|
|
@ -34,6 +34,9 @@ import jakarta.persistence.Column;
|
|||
import static org.hibernate.cfg.BinderHelper.makeIdGenerator;
|
||||
|
||||
/**
|
||||
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentIdentifierBag id bags}
|
||||
* whose mapping model type is {@link org.hibernate.mapping.IdentifierBag}.
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class IdBagBinder extends BagBinder {
|
||||
|
@ -54,7 +57,8 @@ public class IdBagBinder extends BagBinder {
|
|||
|
||||
final CollectionId collectionIdAnn = property.getAnnotation( CollectionId.class );
|
||||
if ( collectionIdAnn == null ) {
|
||||
throw new MappingException( "idbag mapping missing @CollectionId" );
|
||||
//TODO shouldn't this be an assertion?
|
||||
throw new MappingException( "idbag mapping missing '@CollectionId' annotation" );
|
||||
}
|
||||
|
||||
final PropertyData propertyData = new WrappedInferredData(
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.cfg.annotations;
|
|||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.OrderBy;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
|
@ -31,14 +32,13 @@ import org.jboss.logging.Logger;
|
|||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
|
||||
/**
|
||||
* Bind a list to the underlying Hibernate configuration
|
||||
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentList lists},
|
||||
* whose mapping model type is {@link org.hibernate.mapping.List}.
|
||||
*
|
||||
* @author Matthew Inger
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class ListBinder extends CollectionBinder {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, ListBinder.class.getName() );
|
||||
|
||||
public ListBinder(
|
||||
Supplier<ManagedBean<? extends UserCollectionType>> customTypeBeanResolver,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
|
@ -53,7 +53,7 @@ public class ListBinder extends CollectionBinder {
|
|||
@Override
|
||||
public void setSqlOrderBy(OrderBy orderByAnn) {
|
||||
if ( orderByAnn != null ) {
|
||||
LOG.orderByAnnotationIndexedCollection();
|
||||
throw new AnnotationException( "A collection of type 'List' is annotated '@OrderBy'" );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.hibernate.cfg.CollectionPropertyHolder;
|
|||
import org.hibernate.cfg.CollectionSecondPass;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumn;
|
||||
import org.hibernate.cfg.InheritanceState;
|
||||
import org.hibernate.cfg.PropertyData;
|
||||
import org.hibernate.cfg.PropertyPreloadedData;
|
||||
import org.hibernate.cfg.SecondPass;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
|
@ -59,14 +58,15 @@ import jakarta.persistence.MapKeyColumn;
|
|||
import jakarta.persistence.MapKeyJoinColumn;
|
||||
import jakarta.persistence.MapKeyJoinColumns;
|
||||
|
||||
import static org.hibernate.cfg.BinderHelper.PRIMITIVE_NAMES;
|
||||
import static org.hibernate.cfg.BinderHelper.findPropertyByName;
|
||||
import static org.hibernate.cfg.BinderHelper.isPrimitive;
|
||||
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
|
||||
import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
|
||||
/**
|
||||
* Implementation to bind a Map
|
||||
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentMap maps},
|
||||
* whose mapping model type is {@link org.hibernate.mapping.Map}.
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
|
@ -157,69 +157,79 @@ public class MapBinder extends CollectionBinder {
|
|||
boolean isEmbedded,
|
||||
AnnotatedColumns mapKeyColumns,
|
||||
AnnotatedJoinColumns mapKeyManyToManyColumns) {
|
||||
org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
|
||||
if ( mapKeyPropertyName != null ) {
|
||||
//this is an EJB3 @MapKey
|
||||
handleExplicitMapKey( elementType, persistentClasses, mapKeyPropertyName );
|
||||
handleMapKeyProperty( elementType, persistentClasses, mapKeyPropertyName, map );
|
||||
}
|
||||
else {
|
||||
//this is a true Map mapping
|
||||
final String mapKeyType = getKeyType( property );
|
||||
final PersistentClass collectionEntity = persistentClasses.get( mapKeyType );
|
||||
final boolean isIndexOfEntities = collectionEntity != null;
|
||||
final ManyToOne element;
|
||||
org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
|
||||
if ( isIndexOfEntities ) {
|
||||
element = handleCollectionKeyedByEntities( buildingContext, mapKeyType, map );
|
||||
}
|
||||
else {
|
||||
element = null;
|
||||
final XClass keyClass;
|
||||
final AnnotatedClassType classType;
|
||||
if ( PRIMITIVE_NAMES.contains( mapKeyType ) ) {
|
||||
classType = AnnotatedClassType.NONE;
|
||||
keyClass = null;
|
||||
}
|
||||
else {
|
||||
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
|
||||
final Class<Object> mapKeyClass = bootstrapContext.getClassLoaderAccess().classForName( mapKeyType );
|
||||
keyClass = bootstrapContext.getReflectionManager().toXClass( mapKeyClass );
|
||||
// force in case of attribute override naming the key
|
||||
classType = isEmbedded || mappingDefinedAttributeOverrideOnMapKey( property )
|
||||
? AnnotatedClassType.EMBEDDABLE
|
||||
: buildingContext.getMetadataCollector().getClassType( keyClass );
|
||||
}
|
||||
handleMapKey( persistentClasses, property, isEmbedded, mapKeyColumns, mapKeyManyToManyColumns, map );
|
||||
}
|
||||
}
|
||||
|
||||
handleIndex(
|
||||
property,
|
||||
mapKeyColumns,
|
||||
mapKeyType,
|
||||
map,
|
||||
keyClass,
|
||||
classType,
|
||||
buildCollectionPropertyHolder( property, map, keyClass ),
|
||||
getAccessType( map )
|
||||
);
|
||||
}
|
||||
//FIXME pass the Index Entity JoinColumns
|
||||
if ( !collection.isOneToMany() ) {
|
||||
//index column should not be null
|
||||
for ( AnnotatedJoinColumn column : mapKeyManyToManyColumns.getJoinColumns() ) {
|
||||
column.forceNotNull();
|
||||
}
|
||||
private void handleMapKey(
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
XProperty property,
|
||||
boolean isEmbedded,
|
||||
AnnotatedColumns mapKeyColumns,
|
||||
AnnotatedJoinColumns mapKeyManyToManyColumns,
|
||||
org.hibernate.mapping.Map map) {
|
||||
final String mapKeyType = getKeyType( property );
|
||||
final PersistentClass collectionEntity = persistentClasses.get( mapKeyType );
|
||||
final boolean isKeyedByEntities = collectionEntity != null;
|
||||
if ( isKeyedByEntities ) {
|
||||
final ManyToOne element = handleCollectionKeyedByEntities( buildingContext, mapKeyType, map );
|
||||
handleForeignKey( property, element );
|
||||
// a map key column has no unique constraint, so pass 'unique=false' here
|
||||
bindManyToManyInverseForeignKey( collectionEntity, mapKeyManyToManyColumns, element, false );
|
||||
}
|
||||
else {
|
||||
final XClass keyClass = mapKeyClass( mapKeyType );
|
||||
handleMapKey(
|
||||
property,
|
||||
mapKeyColumns,
|
||||
mapKeyType,
|
||||
map,
|
||||
keyClass,
|
||||
annotatedMapKeyType( property, isEmbedded, mapKeyType, keyClass ),
|
||||
buildCollectionPropertyHolder( property, map, keyClass ),
|
||||
accessType( property, map.getOwner() )
|
||||
);
|
||||
}
|
||||
//FIXME pass the Index Entity JoinColumns
|
||||
if ( !collection.isOneToMany() ) {
|
||||
//index column should not be null
|
||||
for ( AnnotatedJoinColumn column : mapKeyManyToManyColumns.getJoinColumns() ) {
|
||||
column.forceNotNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( element != null ) {
|
||||
handleForeignKey( property, element );
|
||||
}
|
||||
private AnnotatedClassType annotatedMapKeyType(
|
||||
XProperty property,
|
||||
boolean isEmbedded,
|
||||
String mapKeyType,
|
||||
XClass keyClass) {
|
||||
if ( isPrimitive( mapKeyType ) ) {
|
||||
return AnnotatedClassType.NONE;
|
||||
}
|
||||
else {
|
||||
// force in case of attribute override naming the key
|
||||
return isEmbedded || mappingDefinedAttributeOverrideOnMapKey( property )
|
||||
? AnnotatedClassType.EMBEDDABLE
|
||||
: buildingContext.getMetadataCollector().getClassType( keyClass );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isIndexOfEntities ) {
|
||||
bindManyToManyInverseForeignKey(
|
||||
collectionEntity,
|
||||
mapKeyManyToManyColumns,
|
||||
element,
|
||||
false //a map key column has no unique constraint
|
||||
);
|
||||
}
|
||||
private XClass mapKeyClass(String mapKeyType) {
|
||||
if ( isPrimitive( mapKeyType ) ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
|
||||
final Class<Object> mapKeyClass = bootstrapContext.getClassLoaderAccess().classForName( mapKeyType );
|
||||
return bootstrapContext.getReflectionManager().toXClass( mapKeyClass );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,10 +242,11 @@ public class MapBinder extends CollectionBinder {
|
|||
return void.class.equals( target ) ? property.getMapKey().getName() : target.getName();
|
||||
}
|
||||
|
||||
private void handleExplicitMapKey(
|
||||
private void handleMapKeyProperty(
|
||||
XClass elementType,
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
String mapKeyPropertyName) {
|
||||
String mapKeyPropertyName,
|
||||
org.hibernate.mapping.Map map) {
|
||||
final PersistentClass associatedClass = persistentClasses.get( elementType.getName() );
|
||||
if ( associatedClass == null ) {
|
||||
throw new AnnotationException( "Association '" + safeCollectionRole()
|
||||
|
@ -246,15 +257,14 @@ public class MapBinder extends CollectionBinder {
|
|||
throw new AnnotationException( "Map key property '" + mapKeyPropertyName
|
||||
+ "' not found in target entity '" + associatedClass.getEntityName() + "'" );
|
||||
}
|
||||
final org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
|
||||
// HHH-11005 - if InheritanceType.JOINED then need to find class defining the column
|
||||
final InheritanceState inheritanceState = inheritanceStatePerClass.get(elementType);
|
||||
final InheritanceState inheritanceState = inheritanceStatePerClass.get( elementType );
|
||||
final PersistentClass targetEntity = InheritanceType.JOINED == inheritanceState.getType()
|
||||
? mapProperty.getPersistentClass()
|
||||
: associatedClass;
|
||||
final Value indexValue = createFormulatedValue( mapProperty.getValue(), map, associatedClass, targetEntity );
|
||||
map.setIndex( indexValue );
|
||||
map.setMapKeyPropertyName(mapKeyPropertyName);
|
||||
map.setMapKeyPropertyName( mapKeyPropertyName );
|
||||
}
|
||||
|
||||
private CollectionPropertyHolder buildCollectionPropertyHolder(
|
||||
|
@ -298,8 +308,7 @@ public class MapBinder extends CollectionBinder {
|
|||
MetadataBuildingContext context,
|
||||
String mapKeyType,
|
||||
org.hibernate.mapping.Map map) {
|
||||
final ManyToOne element;
|
||||
element = new ManyToOne( context, map.getCollectionTable() );
|
||||
final ManyToOne element = new ManyToOne( context, map.getCollectionTable() );
|
||||
map.setIndex( element );
|
||||
element.setReferencedEntityName( mapKeyType );
|
||||
//element.setFetchMode( fetchMode );
|
||||
|
@ -311,29 +320,7 @@ public class MapBinder extends CollectionBinder {
|
|||
return element;
|
||||
}
|
||||
|
||||
private static AccessType getAccessType(org.hibernate.mapping.Map map) {
|
||||
final PersistentClass owner = map.getOwner();
|
||||
final AccessType accessType;
|
||||
// FIXME support @Access for collection of elements
|
||||
// String accessType = access != null ? access.value() : null;
|
||||
if ( owner.getIdentifierProperty() != null ) {
|
||||
accessType = owner.getIdentifierProperty().getPropertyAccessorName().equals( "property" )
|
||||
? AccessType.PROPERTY
|
||||
: AccessType.FIELD;
|
||||
}
|
||||
else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().getPropertySpan() > 0 ) {
|
||||
Property prop = owner.getIdentifierMapper().getProperties().get(0);
|
||||
accessType = prop.getPropertyAccessorName().equals( "property" )
|
||||
? AccessType.PROPERTY
|
||||
: AccessType.FIELD;
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure( "Unable to guess collection property accessor name" );
|
||||
}
|
||||
return accessType;
|
||||
}
|
||||
|
||||
private void handleIndex(
|
||||
private void handleMapKey(
|
||||
XProperty property,
|
||||
AnnotatedColumns mapKeyColumns,
|
||||
String mapKeyType,
|
||||
|
@ -344,55 +331,74 @@ public class MapBinder extends CollectionBinder {
|
|||
AccessType accessType) {
|
||||
final Class<? extends CompositeUserType<?>> compositeUserType =
|
||||
resolveCompositeUserType( property, keyClass, buildingContext );
|
||||
|
||||
if ( AnnotatedClassType.EMBEDDABLE == classType || compositeUserType != null ) {
|
||||
final EntityBinder entityBinder = new EntityBinder();
|
||||
final PropertyData inferredData = isHibernateExtensionMapping()
|
||||
? new PropertyPreloadedData( AccessType.PROPERTY, "index", keyClass)
|
||||
// "key" is the JPA 2 prefix for map keys
|
||||
: new PropertyPreloadedData( AccessType.PROPERTY, "key", keyClass);
|
||||
//TODO be smart with isNullable
|
||||
final Component component = AnnotationBinder.fillComponent(
|
||||
holder,
|
||||
inferredData,
|
||||
accessType,
|
||||
true,
|
||||
entityBinder,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
compositeUserType,
|
||||
buildingContext,
|
||||
inheritanceStatePerClass
|
||||
);
|
||||
map.setIndex( component );
|
||||
handleCompositeMapKey( map, keyClass, holder, accessType, compositeUserType );
|
||||
}
|
||||
else {
|
||||
final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext );
|
||||
elementBinder.setReturnedClassName( mapKeyType );
|
||||
final AnnotatedColumns keyColumns = createElementColumnsIfNecessary(
|
||||
collection,
|
||||
mapKeyColumns,
|
||||
Collection.DEFAULT_KEY_COLUMN_NAME,
|
||||
Size.DEFAULT_LENGTH, //TODO: is this really necessary??!!
|
||||
buildingContext
|
||||
);
|
||||
elementBinder.setColumns( keyColumns );
|
||||
//do not call setType as it extracts the type from @Type
|
||||
//the algorithm generally does not apply for map key anyway
|
||||
elementBinder.setType(
|
||||
property,
|
||||
keyClass,
|
||||
collection.getOwnerEntityName(),
|
||||
holder.mapKeyAttributeConverterDescriptor( property, keyClass )
|
||||
);
|
||||
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
|
||||
elementBinder.setAccessType( accessType );
|
||||
map.setIndex( elementBinder.make() );
|
||||
handleMapKey( property, mapKeyColumns, mapKeyType, map, keyClass, holder, accessType );
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMapKey(
|
||||
XProperty property,
|
||||
AnnotatedColumns mapKeyColumns,
|
||||
String mapKeyType,
|
||||
org.hibernate.mapping.Map map, XClass keyClass,
|
||||
CollectionPropertyHolder holder,
|
||||
AccessType accessType) {
|
||||
final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext );
|
||||
elementBinder.setReturnedClassName(mapKeyType);
|
||||
final AnnotatedColumns keyColumns = createElementColumnsIfNecessary(
|
||||
collection,
|
||||
mapKeyColumns,
|
||||
Collection.DEFAULT_KEY_COLUMN_NAME,
|
||||
Size.DEFAULT_LENGTH, //TODO: is this really necessary??!!
|
||||
buildingContext
|
||||
);
|
||||
elementBinder.setColumns( keyColumns );
|
||||
//do not call setType as it extracts the type from @Type
|
||||
//the algorithm generally does not apply for map key anyway
|
||||
elementBinder.setType(
|
||||
property,
|
||||
keyClass,
|
||||
collection.getOwnerEntityName(),
|
||||
holder.mapKeyAttributeConverterDescriptor( property, keyClass )
|
||||
);
|
||||
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
|
||||
elementBinder.setAccessType( accessType );
|
||||
map.setIndex( elementBinder.make() );
|
||||
}
|
||||
|
||||
private void handleCompositeMapKey(
|
||||
org.hibernate.mapping.Map map,
|
||||
XClass keyClass,
|
||||
CollectionPropertyHolder holder,
|
||||
AccessType accessType,
|
||||
Class<? extends CompositeUserType<?>> compositeUserType) {
|
||||
map.setIndex( AnnotationBinder.fillComponent(
|
||||
holder,
|
||||
propertyPreloadedData( keyClass ),
|
||||
accessType,
|
||||
//TODO be smart with isNullable
|
||||
true,
|
||||
new EntityBinder(),
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
compositeUserType,
|
||||
buildingContext,
|
||||
inheritanceStatePerClass
|
||||
) );
|
||||
}
|
||||
|
||||
private PropertyPreloadedData propertyPreloadedData(XClass keyClass) {
|
||||
return isHibernateExtensionMapping()
|
||||
? new PropertyPreloadedData(AccessType.PROPERTY, "index", keyClass)
|
||||
// "key" is the JPA 2 prefix for map keys
|
||||
: new PropertyPreloadedData(AccessType.PROPERTY, "key", keyClass);
|
||||
}
|
||||
|
||||
private static Class<? extends CompositeUserType<?>> resolveCompositeUserType(
|
||||
XProperty property,
|
||||
XClass returnedClass,
|
||||
|
@ -416,23 +422,22 @@ public class MapBinder extends CollectionBinder {
|
|||
|
||||
private jakarta.persistence.ForeignKey getMapKeyForeignKey(XProperty property) {
|
||||
final MapKeyJoinColumns mapKeyJoinColumns = property.getAnnotation( MapKeyJoinColumns.class );
|
||||
final MapKeyJoinColumn mapKeyJoinColumn = property.getAnnotation( MapKeyJoinColumn.class );
|
||||
if ( mapKeyJoinColumns != null ) {
|
||||
return mapKeyJoinColumns.foreignKey();
|
||||
}
|
||||
else {
|
||||
final MapKeyJoinColumn mapKeyJoinColumn = property.getAnnotation( MapKeyJoinColumn.class );
|
||||
if ( mapKeyJoinColumn != null ) {
|
||||
return mapKeyJoinColumn.foreignKey();
|
||||
}
|
||||
else if ( mapKeyJoinColumn != null ) {
|
||||
return mapKeyJoinColumn.foreignKey();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean mappingDefinedAttributeOverrideOnMapKey(XProperty property) {
|
||||
if ( property.isAnnotationPresent( AttributeOverride.class ) ) {
|
||||
return namedMapKey( property.getAnnotation( AttributeOverride.class ) );
|
||||
}
|
||||
|
||||
if ( property.isAnnotationPresent( AttributeOverrides.class ) ) {
|
||||
final AttributeOverrides annotations = property.getAnnotation( AttributeOverrides.class );
|
||||
for ( AttributeOverride attributeOverride : annotations.value() ) {
|
||||
|
@ -441,7 +446,6 @@ public class MapBinder extends CollectionBinder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -454,94 +458,94 @@ public class MapBinder extends CollectionBinder {
|
|||
Collection collection,
|
||||
PersistentClass associatedClass,
|
||||
PersistentClass targetPropertyPersistentClass) {
|
||||
final Table mapKeyTable;
|
||||
// HHH-11005 - only if we are OneToMany and location of map key property is at a different level, need to add a select
|
||||
if ( !associatedClass.equals( targetPropertyPersistentClass ) ) {
|
||||
mapKeyTable = targetPropertyPersistentClass.getTable();
|
||||
}
|
||||
else {
|
||||
mapKeyTable = associatedClass.getTable();
|
||||
}
|
||||
|
||||
if ( value instanceof Component ) {
|
||||
Component component = (Component) value;
|
||||
Component indexComponent = new Component( getBuildingContext(), collection );
|
||||
indexComponent.setComponentClassName( component.getComponentClassName() );
|
||||
for ( Property current : component.getProperties() ) {
|
||||
Property newProperty = new Property();
|
||||
newProperty.setCascade( current.getCascade() );
|
||||
newProperty.setValueGenerationStrategy( current.getValueGenerationStrategy() );
|
||||
newProperty.setInsertable( false );
|
||||
newProperty.setUpdateable( false );
|
||||
newProperty.setMetaAttributes( current.getMetaAttributes() );
|
||||
newProperty.setName( current.getName() );
|
||||
newProperty.setNaturalIdentifier( false );
|
||||
//newProperty.setOptimisticLocked( false );
|
||||
newProperty.setOptional( false );
|
||||
newProperty.setPersistentClass( current.getPersistentClass() );
|
||||
newProperty.setPropertyAccessorName( current.getPropertyAccessorName() );
|
||||
newProperty.setSelectable( current.isSelectable() );
|
||||
newProperty.setValue(
|
||||
createFormulatedValue( current.getValue(), collection, associatedClass, associatedClass )
|
||||
);
|
||||
indexComponent.addProperty( newProperty );
|
||||
}
|
||||
return indexComponent;
|
||||
}
|
||||
else if ( value instanceof BasicValue ) {
|
||||
final BasicValue sourceValue = (BasicValue) value;
|
||||
final DependantBasicValue dependantBasicValue = new DependantBasicValue(
|
||||
getBuildingContext(),
|
||||
mapKeyTable,
|
||||
sourceValue,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
final Selectable sourceValueColumn = sourceValue.getColumn();
|
||||
if ( sourceValueColumn instanceof Column ) {
|
||||
dependantBasicValue.addColumn( ( (Column) sourceValueColumn ).clone() );
|
||||
}
|
||||
else if ( sourceValueColumn instanceof Formula ) {
|
||||
dependantBasicValue.addFormula( new Formula( ( (Formula) sourceValueColumn ).getFormula() ) );
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure( "Unknown element column type : " + sourceValueColumn.getClass() );
|
||||
}
|
||||
|
||||
return dependantBasicValue;
|
||||
}
|
||||
else if ( value instanceof SimpleValue ) {
|
||||
SimpleValue sourceValue = (SimpleValue) value;
|
||||
SimpleValue targetValue;
|
||||
if ( value instanceof ManyToOne ) {
|
||||
final ManyToOne sourceManyToOne = (ManyToOne) sourceValue;
|
||||
final ManyToOne targetManyToOne = new ManyToOne( getBuildingContext(), mapKeyTable );
|
||||
targetManyToOne.setFetchMode( FetchMode.DEFAULT );
|
||||
targetManyToOne.setLazy( true );
|
||||
//targetValue.setIgnoreNotFound( ); does not make sense for a map key
|
||||
targetManyToOne.setReferencedEntityName( sourceManyToOne.getReferencedEntityName() );
|
||||
targetValue = targetManyToOne;
|
||||
}
|
||||
else {
|
||||
targetValue = new BasicValue( getBuildingContext(), mapKeyTable );
|
||||
targetValue.copyTypeFrom( sourceValue );
|
||||
}
|
||||
for ( Selectable current : sourceValue.getSelectables() ) {
|
||||
if ( current instanceof Column ) {
|
||||
targetValue.addColumn( ( (Column) current ).clone() );
|
||||
}
|
||||
else if ( current instanceof Formula ) {
|
||||
targetValue.addFormula( new Formula( ( (Formula) current ).getFormula() ) );
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure( "Unknown element in column iterator: " + current.getClass() );
|
||||
}
|
||||
}
|
||||
return targetValue;
|
||||
return createIndexComponent( collection, associatedClass, (Component) value );
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure( "Unknown type encountered for map key: " + value.getClass() );
|
||||
// HHH-11005 - only if we are @OneToMany and location of map key property is
|
||||
// at a different level, need to add a select
|
||||
final Table mapKeyTable = !associatedClass.equals( targetPropertyPersistentClass )
|
||||
? targetPropertyPersistentClass.getTable()
|
||||
: associatedClass.getTable();
|
||||
if ( value instanceof BasicValue ) {
|
||||
return createDependantBasicValue( mapKeyTable, (BasicValue) value );
|
||||
}
|
||||
else if ( value instanceof SimpleValue ) {
|
||||
return createTargetValue( mapKeyTable, (SimpleValue) value );
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure( "Unknown type encountered for map key: " + value.getClass() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SimpleValue createTargetValue(Table mapKeyTable, SimpleValue sourceValue) {
|
||||
final SimpleValue targetValue;
|
||||
if ( sourceValue instanceof ManyToOne ) {
|
||||
final ManyToOne sourceManyToOne = (ManyToOne) sourceValue;
|
||||
final ManyToOne targetManyToOne = new ManyToOne( getBuildingContext(), mapKeyTable);
|
||||
targetManyToOne.setFetchMode( FetchMode.DEFAULT );
|
||||
targetManyToOne.setLazy( true );
|
||||
//targetValue.setIgnoreNotFound( ); does not make sense for a map key
|
||||
targetManyToOne.setReferencedEntityName( sourceManyToOne.getReferencedEntityName() );
|
||||
targetValue = targetManyToOne;
|
||||
}
|
||||
else {
|
||||
targetValue = new BasicValue( getBuildingContext(), mapKeyTable);
|
||||
targetValue.copyTypeFrom( sourceValue );
|
||||
}
|
||||
for ( Selectable selectable : sourceValue.getSelectables() ) {
|
||||
addSelectable( targetValue, selectable );
|
||||
}
|
||||
return targetValue;
|
||||
}
|
||||
|
||||
private DependantBasicValue createDependantBasicValue(Table mapKeyTable, BasicValue sourceValue) {
|
||||
final DependantBasicValue dependantBasicValue = new DependantBasicValue(
|
||||
getBuildingContext(),
|
||||
mapKeyTable,
|
||||
sourceValue,
|
||||
false,
|
||||
false
|
||||
);
|
||||
addSelectable( dependantBasicValue, sourceValue.getColumn() );
|
||||
return dependantBasicValue;
|
||||
}
|
||||
|
||||
private static void addSelectable(SimpleValue targetValue, Selectable selectable) {
|
||||
if ( selectable instanceof Column ) {
|
||||
targetValue.addColumn( ( (Column) selectable).clone() );
|
||||
}
|
||||
else if ( selectable instanceof Formula ) {
|
||||
targetValue.addFormula( new Formula( ( (Formula) selectable).getFormula() ) );
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure( "Unknown element in column iterator: " + selectable.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
private Component createIndexComponent(Collection collection, PersistentClass associatedClass, Component component) {
|
||||
final Component indexComponent = new Component( getBuildingContext(), collection);
|
||||
indexComponent.setComponentClassName( component.getComponentClassName() );
|
||||
for ( Property property : component.getProperties() ) {
|
||||
final Property newProperty = new Property();
|
||||
newProperty.setCascade( property.getCascade() );
|
||||
newProperty.setValueGenerationStrategy( property.getValueGenerationStrategy() );
|
||||
newProperty.setInsertable( false );
|
||||
newProperty.setUpdateable( false );
|
||||
newProperty.setMetaAttributes( property.getMetaAttributes() );
|
||||
newProperty.setName( property.getName() );
|
||||
newProperty.setNaturalIdentifier( false );
|
||||
//newProperty.setOptimisticLocked( false );
|
||||
newProperty.setOptional( false );
|
||||
newProperty.setPersistentClass( property.getPersistentClass() );
|
||||
newProperty.setPropertyAccessorName( property.getPropertyAccessorName() );
|
||||
newProperty.setSelectable( property.isSelectable() );
|
||||
newProperty.setValue(
|
||||
createFormulatedValue( property.getValue(), collection, associatedClass, associatedClass)
|
||||
);
|
||||
indexComponent.addProperty( newProperty );
|
||||
}
|
||||
return indexComponent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ import org.hibernate.resource.beans.spi.ManagedBean;
|
|||
import org.hibernate.usertype.UserCollectionType;
|
||||
|
||||
/**
|
||||
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentArrayHolder primitive arrays},
|
||||
* whose mapping model type is {@link org.hibernate.mapping.PrimitiveArray}.
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class PrimitiveArrayBinder extends ArrayBinder {
|
||||
|
|
|
@ -16,7 +16,8 @@ import org.hibernate.resource.beans.spi.ManagedBean;
|
|||
import org.hibernate.usertype.UserCollectionType;
|
||||
|
||||
/**
|
||||
* Bind a set.
|
||||
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentSet sets},
|
||||
* whose mapping model type is {@link org.hibernate.mapping.Set}.
|
||||
*
|
||||
* @author Matthew Inger
|
||||
*/
|
||||
|
|
|
@ -40,7 +40,7 @@ public class PersistentArrayHolder<E> extends AbstractPersistentCollection<E> {
|
|||
protected Object array;
|
||||
|
||||
//just to help out during the load (ugly, i know)
|
||||
private transient Class elementClass;
|
||||
private transient Class<?> elementClass;
|
||||
|
||||
/**
|
||||
* Constructs a PersistentCollection instance for holding an array.
|
||||
|
|
|
@ -839,13 +839,7 @@ public final class StringHelper {
|
|||
final boolean isFirstExpressionNonEmpty = StringHelper.isNotEmpty( firstExpression );
|
||||
final boolean isSecondExpressionNonEmpty = StringHelper.isNotEmpty( secondExpression );
|
||||
if ( isFirstExpressionNonEmpty && isSecondExpressionNonEmpty ) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
buffer.append( "( " )
|
||||
.append( firstExpression )
|
||||
.append( " ) and ( ")
|
||||
.append( secondExpression )
|
||||
.append( " )" );
|
||||
return buffer.toString();
|
||||
return "( " + firstExpression + " ) and ( " + secondExpression + " )";
|
||||
}
|
||||
else if ( isFirstExpressionNonEmpty ) {
|
||||
return firstExpression;
|
||||
|
|
|
@ -473,18 +473,12 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
return converterResolution;
|
||||
}
|
||||
|
||||
final JdbcType jdbcType;
|
||||
if ( explicitJdbcTypeAccess != null ) {
|
||||
jdbcType = explicitJdbcTypeAccess.apply( typeConfiguration );
|
||||
}
|
||||
else {
|
||||
jdbcType = null;
|
||||
}
|
||||
final JdbcType jdbcType = explicitJdbcTypeAccess != null
|
||||
? explicitJdbcTypeAccess.apply( typeConfiguration )
|
||||
: null;
|
||||
|
||||
if ( jtd == null ) {
|
||||
if ( jdbcType != null ) {
|
||||
jtd = jdbcType.getJdbcRecommendedJavaTypeMapping( null, null, typeConfiguration );
|
||||
}
|
||||
if ( jtd == null && jdbcType != null ) {
|
||||
jtd = jdbcType.getJdbcRecommendedJavaTypeMapping( null, null, typeConfiguration );
|
||||
}
|
||||
|
||||
if ( jtd == null ) {
|
||||
|
|
Loading…
Reference in New Issue