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
parent 7c0f8474f5
commit ed5a2496d7
5 changed files with 193 additions and 86 deletions

View File

@ -56,6 +56,7 @@ import org.hibernate.cfg.AttributeConverterDefinition;
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 class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
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 class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
}
}
private ArrayList<IdGeneratorResolverSecondPass> idGeneratorResolverSecondPassList;
private ArrayList<PkDrivenByDefaultMapsIdSecondPass> pkDrivenByDefaultMapsIdSecondPassList;
private ArrayList<SetSimpleValueTypeSecondPass> setSimpleValueTypeSecondPassList;
private ArrayList<CopyIdentifierComponentSecondPass> copyIdentifierComponentSecondPasList;
@ -1460,7 +1464,10 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
@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 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
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 class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
inSecondPass = true;
try {
processSecondPasses( idGeneratorResolverSecondPassList );
processSecondPasses( implicitColumnNamingSecondPassList );
processSecondPasses( pkDrivenByDefaultMapsIdSecondPassList );
processSecondPasses( setSimpleValueTypeSecondPassList );

View File

@ -10,7 +10,6 @@ import java.lang.annotation.Annotation;
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;
@ -35,7 +34,6 @@ import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.InheritanceType;
@ -415,8 +413,10 @@ public final class AnnotationBinder {
}
}
private static IdentifierGeneratorDefinition buildIdGenerator(java.lang.annotation.Annotation ann, MetadataBuildingContext context) {
if ( ann == null ) {
private static IdentifierGeneratorDefinition buildIdGenerator(
java.lang.annotation.Annotation generatorAnn,
MetadataBuildingContext context) {
if ( generatorAnn == null ) {
return null;
}
@ -436,26 +436,26 @@ public final class AnnotationBinder {
);
}
if ( ann instanceof TableGenerator ) {
if ( generatorAnn instanceof TableGenerator ) {
context.getBuildingOptions().getIdGenerationTypeInterpreter().interpretTableGenerator(
(TableGenerator) ann,
(TableGenerator) generatorAnn,
definitionBuilder
);
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Add table generator with name: {0}", definitionBuilder.getName() );
}
}
else if ( ann instanceof SequenceGenerator ) {
else if ( generatorAnn instanceof SequenceGenerator ) {
context.getBuildingOptions().getIdGenerationTypeInterpreter().interpretSequenceGenerator(
(SequenceGenerator) ann,
(SequenceGenerator) generatorAnn,
definitionBuilder
);
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Add sequence generator with name: {0}", definitionBuilder.getName() );
}
}
else if ( ann instanceof GenericGenerator ) {
GenericGenerator genGen = ( GenericGenerator ) ann;
else if ( generatorAnn instanceof GenericGenerator ) {
GenericGenerator genGen = ( GenericGenerator ) generatorAnn;
definitionBuilder.setName( genGen.name() );
definitionBuilder.setStrategy( genGen.strategy() );
Parameter[] params = genGen.parameters();
@ -467,7 +467,7 @@ public final class AnnotationBinder {
}
}
else {
throw new AssertionFailure( "Unknown Generator annotation: " + ann );
throw new AssertionFailure( "Unknown Generator annotation: " + generatorAnn );
}
return definitionBuilder.build();
@ -725,15 +725,14 @@ public final class AnnotationBinder {
}
// 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,
@ -2157,7 +2156,7 @@ public final class AnnotationBinder {
}
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 );
}
@ -2265,22 +2264,23 @@ public final class AnnotationBinder {
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(),
foreignGenerator.getStrategy(),
foreignGenerator.getName(),
context,
localGenerators
foreignGenerator
);
context.getMetadataCollector().addSecondPass( secondPass );
}
if ( isId ) {
//components and regular basic types create SimpleValue objects
@ -2367,20 +2367,21 @@ public final class AnnotationBinder {
+ BinderHelper.getPath( propertyHolder, inferredData )
);
}
XClass returnedClass = inferredData.getClassOrElement();
XProperty property = inferredData.getProperty();
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( property, 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)
final boolean isComponent = returnedClass.isAnnotationPresent( Embeddable.class )
|| property.isAnnotationPresent( EmbeddedId.class );
final boolean isComponent = entityXClass.isAnnotationPresent( Embeddable.class )
|| idXProperty.isAnnotationPresent( EmbeddedId.class );
GeneratedValue generatedValue = property.getAnnotation( GeneratedValue.class );
GeneratedValue generatedValue = idXProperty.getAnnotation( GeneratedValue.class );
String generatorType = generatedValue != null
? generatorType( generatedValue.strategy(), buildingContext, returnedClass )
? generatorType( generatedValue, buildingContext, entityXClass )
: "assigned";
String generatorName = generatedValue != null
? generatedValue.generator()
@ -2389,13 +2390,41 @@ public final class AnnotationBinder {
//a component must not have any generator
generatorType = "assigned";
}
BinderHelper.makeIdGenerator( idValue, generatorType, generatorName, buildingContext, localGenerators );
SecondPass secondPass = new IdGeneratorResolverSecondPass(
idValue,
generatorType,
generatorName,
buildingContext
);
buildingContext.getMetadataCollector().addSecondPass( secondPass );
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Bind {0} on {1}", ( isComponent ? "@EmbeddedId" : "@Id" ), inferredData.getPropertyName() );
}
}
public static String generatorType(
GeneratedValue generatedValueAnn,
final MetadataBuildingContext buildingContext,
final XClass javaTypeXClass) {
return buildingContext.getBuildingOptions().getIdGenerationTypeInterpreter().determineGeneratorName(
generatedValueAnn.strategy(),
new IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext() {
Class javaType = null;
@Override
public Class getIdType() {
if ( javaType == null ) {
javaType = buildingContext.getBuildingOptions()
.getReflectionManager()
.toClass( javaTypeXClass );
}
return javaType;
}
}
);
}
//TODO move that to collection binder?
private static void bindJoinedTableAssociation(
@ -2700,22 +2729,23 @@ public final class AnnotationBinder {
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.strategy(), buildingContext, property.getType() )
? 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(),
generatorType,
generator,
buildingContext,
localGenerators
buildingContext
);
buildingContext.getMetadataCollector().addSecondPass( secondPass );
}
}
@ -2815,13 +2845,14 @@ public final class AnnotationBinder {
id = value.make();
}
rootClass.setIdentifier( id );
BinderHelper.makeIdGenerator(
SecondPass secondPass = new IdGeneratorResolverSecondPass(
id,
generatorType,
generatorName,
buildingContext,
Collections.<String, IdentifierGeneratorDefinition>emptyMap()
buildingContext
);
buildingContext.getMetadataCollector().addSecondPass( secondPass );
if ( isEmbedded ) {
rootClass.setEmbeddedIdentifier( inferredData.getPropertyClass() == null );
}
@ -3211,27 +3242,6 @@ public final class AnnotationBinder {
propertyHolder.addProperty( prop, columns, inferredData.getDeclaringClass() );
}
private static String generatorType(
GenerationType generatorEnum,
final MetadataBuildingContext buildingContext,
final XClass javaTypeXClass) {
return buildingContext.getBuildingOptions().getIdGenerationTypeInterpreter().determineGeneratorName(
generatorEnum,
new IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext() {
Class javaType = null;
@Override
public Class getIdType() {
if ( javaType == null ) {
javaType = buildingContext.getBuildingOptions()
.getReflectionManager()
.toClass( javaTypeXClass );
}
return javaType;
}
}
);
}
private static EnumSet<CascadeType> convertToHibernateCascadeType(javax.persistence.CascadeType[] ejbCascades) {
EnumSet<CascadeType> hibernateCascadeSet = EnumSet.noneOf( CascadeType.class );
if ( ejbCascades != null && ejbCascades.length > 0 ) {
@ -3337,8 +3347,8 @@ public final class AnnotationBinder {
}
}
private static HashMap<String, IdentifierGeneratorDefinition> buildLocalGenerators(XAnnotatedElement annElt, MetadataBuildingContext context) {
HashMap<String, IdentifierGeneratorDefinition> generators = new HashMap<String, IdentifierGeneratorDefinition>();
private static HashMap<String, IdentifierGeneratorDefinition> buildGenerators(XAnnotatedElement annElt, MetadataBuildingContext context) {
HashMap<String, IdentifierGeneratorDefinition> generators = new HashMap<>();
TableGenerator tabGen = annElt.getAnnotation( TableGenerator.class );
SequenceGenerator seqGen = annElt.getAnnotation( SequenceGenerator.class );
GenericGenerator genGen = annElt.getAnnotation( GenericGenerator.class );
@ -3354,6 +3364,11 @@ public final class AnnotationBinder {
IdentifierGeneratorDefinition idGen = buildIdGenerator( genGen, context );
generators.put( idGen.getName(), idGen );
}
generators.forEach( (name, idGenerator) -> {
context.getMetadataCollector().addIdentifierGenerator( idGenerator );
} );
return generators;
}

View File

@ -6,6 +6,17 @@
*/
package org.hibernate.cfg;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
@ -39,18 +50,8 @@ import org.hibernate.mapping.SyntheticProperty;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.jboss.logging.Logger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import org.jboss.logging.Logger;
/**
* @author Emmanuel Bernard
@ -65,7 +66,7 @@ public class 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() );
@ -260,7 +261,7 @@ public class BinderHelper {
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 ?
@ -358,9 +359,9 @@ public class BinderHelper {
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();
}
@ -383,7 +384,7 @@ public class BinderHelper {
)
);
orderedColumns.add( column );
columnsToProperty.put( column, new HashSet<Property>() );
columnsToProperty.put( column, new HashSet<>() );
}
boolean isPersistentClass = columnOwner instanceof PersistentClass;
Iterator it = isPersistentClass ?
@ -399,7 +400,7 @@ public class BinderHelper {
//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 ) ) {
@ -685,7 +686,24 @@ public class BinderHelper {
id.setIdentifierGeneratorProperties( params );
}
public static IdentifierGeneratorDefinition getIdentifierGenerator(
/**
* apply an id generator to a SimpleValue
*/
public static void makeIdGenerator(
SimpleValue id,
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, generatorType, generatorName, buildingContext, localIdentifiers );
}
private static IdentifierGeneratorDefinition getIdentifierGenerator(
String name,
Map<String, IdentifierGeneratorDefinition> localGenerators,
MetadataBuildingContext buildingContext) {
@ -894,7 +912,7 @@ public class BinderHelper {
}
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() );
@ -904,7 +922,7 @@ public class BinderHelper {
}
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,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.cfg;
import java.util.Map;
import org.hibernate.MappingException;
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 String generatorType;
private String generatorName;
private MetadataBuildingContext buildingContext;
private IdentifierGeneratorDefinition localIdentifierGeneratorDefinition;
public IdGeneratorResolverSecondPass(
SimpleValue id,
String generatorType,
String generatorName,
MetadataBuildingContext buildingContext) {
this.id = id;
this.generatorType = generatorType;
this.generatorName = generatorName;
this.buildingContext = buildingContext;
}
public IdGeneratorResolverSecondPass(
SimpleValue id,
String generatorType,
String generatorName,
MetadataBuildingContext buildingContext,
IdentifierGeneratorDefinition localIdentifierGeneratorDefinition) {
this(id,generatorType,generatorName,buildingContext);
this.localIdentifierGeneratorDefinition = localIdentifierGeneratorDefinition;
}
@Override
public void doSecondPass(Map idGeneratorDefinitionMap) throws MappingException {
BinderHelper.makeIdGenerator( id, generatorType, generatorName, buildingContext, localIdentifierGeneratorDefinition );
}
}

View File

@ -18,8 +18,10 @@ import org.hibernate.boot.spi.MetadataBuildingContext;
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,7 +106,14 @@ public class IdBagBinder extends BagBinder {
else {
generatorType = null;
}
BinderHelper.makeIdGenerator( id, generatorType, generator, getBuildingContext(), localGenerators );
SecondPass secondPass = new IdGeneratorResolverSecondPass(
id,
generatorType,
generator,
getBuildingContext()
);
buildingContext.getMetadataCollector().addSecondPass( secondPass );
}
return result;
}