HHH-12157 - TableGenerator defined on one class is not visible on another

(cherry picked from commit 8ae3dc4078597c69588ca8237591f1eab64c6bd7)
This commit is contained in:
Andrea Boriero 2017-12-11 14:59:48 +00:00 committed by Steve Ebersole
parent 9fe921db52
commit b1a9c816a7
5 changed files with 139 additions and 44 deletions

View File

@ -56,6 +56,7 @@
import org.hibernate.cfg.CopyIdentifierComponentSecondPass;
import org.hibernate.cfg.CreateKeySecondPass;
import org.hibernate.cfg.FkSecondPass;
import org.hibernate.cfg.IdGeneratorResolverSecondPass;
import org.hibernate.cfg.JPAIndexHolder;
import org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass;
import org.hibernate.cfg.PropertyData;
@ -441,10 +442,12 @@ public void addIdentifierGenerator(IdentifierGeneratorDefinition generator) {
if ( defaultIdentifierGeneratorNames.contains( generator.getName() ) ) {
return;
}
final IdentifierGeneratorDefinition old = idGeneratorDefinitionMap.put( generator.getName(), generator );
if ( old != null ) {
log.duplicateGeneratorName( old.getName() );
if ( !old.equals( generator ) ) {
throw new IllegalArgumentException( "Duplicate generator name " + old.getName() );
}
// log.duplicateGeneratorName( old.getName() );
}
}
@ -1442,6 +1445,7 @@ public Join locateJoin(Identifier tableName) {
}
}
private ArrayList<IdGeneratorResolverSecondPass> idGeneratorResolverSecondPassList;
private ArrayList<PkDrivenByDefaultMapsIdSecondPass> pkDrivenByDefaultMapsIdSecondPassList;
private ArrayList<SetSimpleValueTypeSecondPass> setSimpleValueTypeSecondPassList;
private ArrayList<CopyIdentifierComponentSecondPass> copyIdentifierComponentSecondPasList;
@ -1460,7 +1464,10 @@ public void addSecondPass(SecondPass secondPass) {
@Override
public void addSecondPass(SecondPass secondPass, boolean onTopOfTheQueue) {
if ( secondPass instanceof PkDrivenByDefaultMapsIdSecondPass ) {
if ( secondPass instanceof IdGeneratorResolverSecondPass ) {
addIdGeneratorResolverSecondPass( (IdGeneratorResolverSecondPass) secondPass, onTopOfTheQueue );
}
else if ( secondPass instanceof PkDrivenByDefaultMapsIdSecondPass ) {
addPkDrivenByDefaultMapsIdSecondPass( (PkDrivenByDefaultMapsIdSecondPass) secondPass, onTopOfTheQueue );
}
else if ( secondPass instanceof SetSimpleValueTypeSecondPass ) {
@ -1518,6 +1525,13 @@ private void addSetSimpleValueTypeSecondPass(SetSimpleValueTypeSecondPass second
addSecondPass( secondPass, setSimpleValueTypeSecondPassList, onTopOfTheQueue );
}
private void addIdGeneratorResolverSecondPass(IdGeneratorResolverSecondPass secondPass, boolean onTopOfTheQueue) {
if ( idGeneratorResolverSecondPassList == null ) {
idGeneratorResolverSecondPassList = new ArrayList<>();
}
addSecondPass( secondPass, idGeneratorResolverSecondPassList, onTopOfTheQueue );
}
private void addCopyIdentifierComponentSecondPass(
CopyIdentifierComponentSecondPass secondPass,
boolean onTopOfTheQueue) {
@ -1573,8 +1587,8 @@ public void processSecondPasses(MetadataBuildingContext buildingContext) {
inSecondPass = true;
try {
processSecondPasses( idGeneratorResolverSecondPassList );
processSecondPasses( implicitColumnNamingSecondPassList );
processSecondPasses( pkDrivenByDefaultMapsIdSecondPassList );
processSecondPasses( setSimpleValueTypeSecondPassList );

View File

@ -9,7 +9,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
@ -763,15 +762,14 @@ else if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.getType() ) ) {
}
// try to find class level generators
HashMap<String, IdentifierGeneratorDefinition> classGenerators = buildLocalGenerators( clazzToProcess, context );
HashMap<String, IdentifierGeneratorDefinition> classGenerators = buildGenerators( clazzToProcess, context );
// check properties
final InheritanceState.ElementsToProcess elementsToProcess = inheritanceState.getElementsToProcess();
inheritanceState.postProcess( persistentClass, entityBinder );
final boolean subclassAndSingleTableStrategy = inheritanceState.getType() == InheritanceType.SINGLE_TABLE
&& inheritanceState.hasParents();
Set<String> idPropertiesIfIdClass = new HashSet<String>();
Set<String> idPropertiesIfIdClass = new HashSet<>();
boolean isIdClass = mapAsIdClass(
inheritanceStatePerClass,
inheritanceState,
@ -2134,7 +2132,7 @@ else if ( property.isAnnotationPresent( ManyToAny.class ) ) {
}
if ( property.isAnnotationPresent( CollectionId.class ) ) { //do not compute the generators unless necessary
HashMap<String, IdentifierGeneratorDefinition> localGenerators = ( HashMap<String, IdentifierGeneratorDefinition> ) classGenerators.clone();
localGenerators.putAll( buildLocalGenerators( property, context ) );
localGenerators.putAll( buildGenerators( property, context ) );
collectionBinder.setLocalGenerators( localGenerators );
}
@ -2242,23 +2240,24 @@ else if ( !isId || !entityBinder.isIgnoreIdAnnotations() ) {
final PropertyData mapsIdProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId(
isId, propertyHolder, property.getName(), context
);
Map<String, IdentifierGeneratorDefinition> localGenerators = ( HashMap<String, IdentifierGeneratorDefinition> ) classGenerators.clone();
final IdentifierGeneratorDefinition.Builder foreignGeneratorBuilder = new IdentifierGeneratorDefinition.Builder();
foreignGeneratorBuilder.setName( "Hibernate-local--foreign generator" );
foreignGeneratorBuilder.setStrategy( "foreign" );
foreignGeneratorBuilder.addParam( "property", mapsIdProperty.getPropertyName() );
final IdentifierGeneratorDefinition foreignGenerator = foreignGeneratorBuilder.build();
localGenerators.put( foreignGenerator.getName(), foreignGenerator );
// Map<String, IdentifierGeneratorDefinition> localGenerators = ( HashMap<String, IdentifierGeneratorDefinition> ) classGenerators.clone();
// localGenerators.put( foreignGenerator.getName(), foreignGenerator );
BinderHelper.makeIdGenerator(
SecondPass secondPass = new IdGeneratorResolverSecondPass(
( SimpleValue ) propertyBinder.getValue(),
property,
foreignGenerator.getStrategy(),
foreignGenerator.getName(),
context,
localGenerators
foreignGenerator
);
context.getMetadataCollector().addSecondPass( secondPass );
}
if ( isId ) {
//components and regular basic types create SimpleValue objects
@ -2348,8 +2347,9 @@ private static void processId(
XClass entityXClass = inferredData.getClassOrElement();
XProperty idXProperty = inferredData.getProperty();
//clone classGenerator and override with local values
HashMap<String, IdentifierGeneratorDefinition> localGenerators = ( HashMap<String, IdentifierGeneratorDefinition> ) classGenerators.clone();
localGenerators.putAll( buildLocalGenerators( idXProperty, buildingContext ) );
// HashMap<String, IdentifierGeneratorDefinition> localGenerators = ( HashMap<String, IdentifierGeneratorDefinition> ) classGenerators.clone();
// localGenerators.putAll( buildGenerators( idXProperty, buildingContext ) );
buildGenerators( idXProperty, buildingContext );
//manage composite related metadata
//guess if its a component and find id data access (property, field etc)
@ -2367,14 +2367,15 @@ private static void processId(
//a component must not have any generator
generatorType = "assigned";
}
BinderHelper.makeIdGenerator(
SecondPass secondPass = new IdGeneratorResolverSecondPass(
idValue,
idXProperty,
generatorType,
generatorName,
buildingContext,
localGenerators
buildingContext
);
buildingContext.getMetadataCollector().addSecondPass( secondPass );
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Bind {0} on {1}", ( isComponent ? "@EmbeddedId" : "@Id" ), inferredData.getPropertyName() );
@ -2711,23 +2712,24 @@ public static Component fillComponent(
if ( property.isAnnotationPresent( GeneratedValue.class ) &&
property.isAnnotationPresent( Id.class ) ) {
//clone classGenerator and override with local values
Map<String, IdentifierGeneratorDefinition> localGenerators = new HashMap<String, IdentifierGeneratorDefinition>();
localGenerators.putAll( buildLocalGenerators( property, buildingContext ) );
// Map<String, IdentifierGeneratorDefinition> localGenerators = new HashMap<>();
// localGenerators.putAll( buildGenerators( property, buildingContext ) );
buildGenerators( property, buildingContext );
GeneratedValue generatedValue = property.getAnnotation( GeneratedValue.class );
String generatorType = generatedValue != null
? generatorType( generatedValue, buildingContext, property.getType() )
: "assigned";
String generator = generatedValue != null ? generatedValue.generator() : BinderHelper.ANNOTATION_STRING_DEFAULT;
BinderHelper.makeIdGenerator(
SecondPass secondPass = new IdGeneratorResolverSecondPass(
( SimpleValue ) comp.getProperty( property.getName() ).getValue(),
property,
generatorType,
generator,
buildingContext,
localGenerators
buildingContext
);
buildingContext.getMetadataCollector().addSecondPass( secondPass );
}
}
@ -2827,14 +2829,15 @@ private static void bindIdClass(
id = value.make();
}
rootClass.setIdentifier( id );
BinderHelper.makeIdGenerator(
SecondPass secondPass = new IdGeneratorResolverSecondPass(
id,
inferredData.getProperty(),
generatorType,
generatorName,
buildingContext,
Collections.<String, IdentifierGeneratorDefinition>emptyMap()
buildingContext
);
buildingContext.getMetadataCollector().addSecondPass( secondPass );
if ( isEmbedded ) {
rootClass.setEmbeddedIdentifier( inferredData.getPropertyClass() == null );
}
@ -3329,7 +3332,7 @@ public static FetchMode getFetchMode(FetchType fetch) {
}
}
private static HashMap<String, IdentifierGeneratorDefinition> buildLocalGenerators(XAnnotatedElement annElt, MetadataBuildingContext context) {
private static HashMap<String, IdentifierGeneratorDefinition> buildGenerators(XAnnotatedElement annElt, MetadataBuildingContext context) {
HashMap<String, IdentifierGeneratorDefinition> generators = new HashMap<>();
TableGenerators tableGenerators = annElt.getAnnotation( TableGenerators.class );
@ -3367,6 +3370,11 @@ private static HashMap<String, IdentifierGeneratorDefinition> buildLocalGenerato
IdentifierGeneratorDefinition idGen = buildIdGenerator( genGen, context );
generators.put( idGen.getName(), idGen );
}
generators.forEach( (name, idGenerator) -> {
context.getMetadataCollector().addIdentifierGenerator( idGenerator );
} );
return generators;
}

View File

@ -42,12 +42,9 @@
import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.cfg.annotations.Nullability;
import org.hibernate.cfg.annotations.TableBinder;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.MultipleHiLoPerTableGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
@ -55,7 +52,6 @@
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.IdGenerator;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass;
@ -82,7 +78,7 @@ private BinderHelper() {
}
static {
Set<String> primitiveNames = new HashSet<String>();
Set<String> primitiveNames = new HashSet<>();
primitiveNames.add( byte.class.getName() );
primitiveNames.add( short.class.getName() );
primitiveNames.add( int.class.getName() );
@ -277,7 +273,7 @@ public static void createSyntheticPropertyReference(
Object columnOwner = findColumnOwner( ownerEntity, columns[0].getReferencedColumn(), context );
List<Property> properties = findPropertiesByColumns( columnOwner, columns, context );
//create an embeddable component
Property synthProp = null;
Property synthProp;
if ( properties != null ) {
//todo how about properties.size() == 1, this should be much simpler
Component embeddedComp = columnOwner instanceof PersistentClass ?
@ -375,9 +371,9 @@ private static List<Property> findPropertiesByColumns(
Object columnOwner,
Ejb3JoinColumn[] columns,
MetadataBuildingContext context) {
Map<Column, Set<Property>> columnsToProperty = new HashMap<Column, Set<Property>>();
List<Column> orderedColumns = new ArrayList<Column>( columns.length );
Table referencedTable = null;
Map<Column, Set<Property>> columnsToProperty = new HashMap<>();
List<Column> orderedColumns = new ArrayList<>( columns.length );
Table referencedTable;
if ( columnOwner instanceof PersistentClass ) {
referencedTable = ( (PersistentClass) columnOwner ).getTable();
}
@ -400,7 +396,7 @@ else if ( columnOwner instanceof Join ) {
)
);
orderedColumns.add( column );
columnsToProperty.put( column, new HashSet<Property>() );
columnsToProperty.put( column, new HashSet<>() );
}
boolean isPersistentClass = columnOwner instanceof PersistentClass;
Iterator it = isPersistentClass ?
@ -416,7 +412,7 @@ else if ( columnOwner instanceof Join ) {
//first naive implementation
//only check 1 columns properties
//TODO make it smarter by checking correctly ordered multi column properties
List<Property> orderedProperties = new ArrayList<Property>();
List<Property> orderedProperties = new ArrayList<>();
for (Column column : orderedColumns) {
boolean found = false;
for (Property property : columnsToProperty.get( column ) ) {
@ -714,7 +710,25 @@ public static void makeIdGenerator(
id.setIdentifierGeneratorProperties( params );
}
public static IdentifierGeneratorDefinition getIdentifierGenerator(
/**
* apply an id generator to a SimpleValue
*/
public static void makeIdGenerator(
SimpleValue id,
XProperty idXProperty,
String generatorType,
String generatorName,
MetadataBuildingContext buildingContext,
IdentifierGeneratorDefinition foreignKGeneratorDefinition) {
Map<String, IdentifierGeneratorDefinition> localIdentifiers = null;
if ( foreignKGeneratorDefinition != null ) {
localIdentifiers = new HashMap<>();
localIdentifiers.put( foreignKGeneratorDefinition.getName(), foreignKGeneratorDefinition );
}
makeIdGenerator( id, idXProperty, generatorType, generatorName, buildingContext, localIdentifiers );
}
private static IdentifierGeneratorDefinition getIdentifierGenerator(
String name,
XProperty idXProperty,
Map<String, IdentifierGeneratorDefinition> localGenerators,
@ -1106,7 +1120,7 @@ static PropertyData getPropertyOverriddenByMapperOrMapsId(
}
public static Map<String,String> toAliasTableMap(SqlFragmentAlias[] aliases){
Map<String,String> ret = new HashMap<String,String>();
Map<String,String> ret = new HashMap<>();
for ( int i = 0; i < aliases.length; i++ ){
if ( StringHelper.isNotEmpty( aliases[i].table() ) ){
ret.put( aliases[i].alias(), aliases[i].table() );
@ -1116,7 +1130,7 @@ public static Map<String,String> toAliasTableMap(SqlFragmentAlias[] aliases){
}
public static Map<String,String> toAliasEntityMap(SqlFragmentAlias[] aliases){
Map<String,String> ret = new HashMap<String,String>();
Map<String,String> ret = new HashMap<>();
for (int i = 0; i < aliases.length; i++){
if (aliases[i].entity() != void.class){
ret.put( aliases[i].alias(), aliases[i].entity().getName() );

View File

@ -0,0 +1,56 @@
/*
* 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.cfg;
import java.util.Map;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.mapping.SimpleValue;
/**
* @author Andrea Boriero
*/
public class IdGeneratorResolverSecondPass implements SecondPass {
private SimpleValue id;
private XProperty idXProperty;
private String generatorType;
private String generatorName;
private MetadataBuildingContext buildingContext;
private IdentifierGeneratorDefinition localIdentifierGeneratorDefinition;
public IdGeneratorResolverSecondPass(
SimpleValue id,
XProperty idXProperty,
String generatorType,
String generatorName,
MetadataBuildingContext buildingContext) {
this.id = id;
this.idXProperty = idXProperty;
this.generatorType = generatorType;
this.generatorName = generatorName;
this.buildingContext = buildingContext;
}
public IdGeneratorResolverSecondPass(
SimpleValue id,
XProperty idXProperty,
String generatorType,
String generatorName,
MetadataBuildingContext buildingContext,
IdentifierGeneratorDefinition localIdentifierGeneratorDefinition) {
this(id,idXProperty,generatorType,generatorName,buildingContext);
this.localIdentifierGeneratorDefinition = localIdentifierGeneratorDefinition;
}
@Override
public void doSecondPass(Map idGeneratorDefinitionMap) throws MappingException {
BinderHelper.makeIdGenerator( id, idXProperty, generatorType, generatorName, buildingContext, localIdentifierGeneratorDefinition );
}
}

View File

@ -18,8 +18,10 @@
import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.Ejb3Column;
import org.hibernate.cfg.Ejb3JoinColumn;
import org.hibernate.cfg.IdGeneratorResolverSecondPass;
import org.hibernate.cfg.PropertyData;
import org.hibernate.cfg.PropertyInferredData;
import org.hibernate.cfg.SecondPass;
import org.hibernate.cfg.WrappedInferredData;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Collection;
@ -104,14 +106,15 @@ property, unique, associationTableBinder, ignoreNotFound, getBuildingContext()
else {
generatorType = null;
}
BinderHelper.makeIdGenerator(
SecondPass secondPass = new IdGeneratorResolverSecondPass(
id,
property,
generatorType,
generator,
getBuildingContext(),
localGenerators
getBuildingContext()
);
buildingContext.getMetadataCollector().addSecondPass( secondPass );
}
return result;
}