public EntityMetamodel( PersistentClass persistentClass, AbstractEntityPersister persister, SessionFactoryImplementor sessionFactory) { this.sessionFactory = sessionFactory; this.persister = persister; name = persistentClass.getEntityName(); rootName = persistentClass.getRootClass().getEntityName(); entityType = sessionFactory.getTypeResolver().getTypeFactory().manyToOne(name); identifierAttribute = PropertyFactory.buildIdentifierAttribute( persistentClass, sessionFactory.getIdentifierGenerator(rootName)); versioned = persistentClass.isVersioned(); instrumentationMetadata = persistentClass.hasPojoRepresentation() ? Environment.getBytecodeProvider() .getEntityInstrumentationMetadata(persistentClass.getMappedClass()) : new NonPojoInstrumentationMetadata(persistentClass.getEntityName()); boolean hasLazy = false; propertySpan = persistentClass.getPropertyClosureSpan(); properties = new NonIdentifierAttribute[propertySpan]; List<Integer> naturalIdNumbers = new ArrayList<Integer>(); // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ propertyNames = new String[propertySpan]; propertyTypes = new Type[propertySpan]; propertyUpdateability = new boolean[propertySpan]; propertyInsertability = new boolean[propertySpan]; nonlazyPropertyUpdateability = new boolean[propertySpan]; propertyCheckability = new boolean[propertySpan]; propertyNullability = new boolean[propertySpan]; propertyVersionability = new boolean[propertySpan]; propertyLaziness = new boolean[propertySpan]; cascadeStyles = new CascadeStyle[propertySpan]; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // generated value strategies // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ this.inMemoryValueGenerationStrategies = new InMemoryValueGenerationStrategy[propertySpan]; this.inDatabaseValueGenerationStrategies = new InDatabaseValueGenerationStrategy[propertySpan]; boolean foundPreInsertGeneratedValues = false; boolean foundPreUpdateGeneratedValues = false; boolean foundPostInsertGeneratedValues = false; boolean foundPostUpdateGeneratedValues = false; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Iterator iter = persistentClass.getPropertyClosureIterator(); int i = 0; int tempVersionProperty = NO_VERSION_INDX; boolean foundCascade = false; boolean foundCollection = false; boolean foundMutable = false; boolean foundNonIdentifierPropertyNamedId = false; boolean foundInsertGeneratedValue = false; boolean foundUpdateGeneratedValue = false; boolean foundUpdateableNaturalIdProperty = false; while (iter.hasNext()) { Property prop = (Property) iter.next(); if (prop == persistentClass.getVersion()) { tempVersionProperty = i; properties[i] = PropertyFactory.buildVersionProperty( persister, sessionFactory, i, prop, instrumentationMetadata.isInstrumented()); } else { properties[i] = PropertyFactory.buildEntityBasedAttribute( persister, sessionFactory, i, prop, instrumentationMetadata.isInstrumented()); } if (prop.isNaturalIdentifier()) { naturalIdNumbers.add(i); if (prop.isUpdateable()) { foundUpdateableNaturalIdProperty = true; } } if ("id".equals(prop.getName())) { foundNonIdentifierPropertyNamedId = true; } // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ boolean lazy = prop.isLazy() && instrumentationMetadata.isInstrumented(); if (lazy) hasLazy = true; propertyLaziness[i] = lazy; propertyNames[i] = properties[i].getName(); propertyTypes[i] = properties[i].getType(); propertyNullability[i] = properties[i].isNullable(); propertyUpdateability[i] = properties[i].isUpdateable(); propertyInsertability[i] = properties[i].isInsertable(); propertyVersionability[i] = properties[i].isVersionable(); nonlazyPropertyUpdateability[i] = properties[i].isUpdateable() && !lazy; propertyCheckability[i] = propertyUpdateability[i] || (propertyTypes[i].isAssociationType() && ((AssociationType) propertyTypes[i]).isAlwaysDirtyChecked()); cascadeStyles[i] = properties[i].getCascadeStyle(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // generated value strategies // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GenerationStrategyPair pair = buildGenerationStrategyPair(sessionFactory, prop); inMemoryValueGenerationStrategies[i] = pair.getInMemoryStrategy(); inDatabaseValueGenerationStrategies[i] = pair.getInDatabaseStrategy(); if (pair.getInMemoryStrategy() != null) { final GenerationTiming timing = pair.getInMemoryStrategy().getGenerationTiming(); if (timing != GenerationTiming.NEVER) { final ValueGenerator generator = pair.getInMemoryStrategy().getValueGenerator(); if (generator != null) { // we have some level of generation indicated if (timing == GenerationTiming.INSERT) { foundPreInsertGeneratedValues = true; } else if (timing == GenerationTiming.ALWAYS) { foundPreInsertGeneratedValues = true; foundPreUpdateGeneratedValues = true; } } } } if (pair.getInDatabaseStrategy() != null) { final GenerationTiming timing = pair.getInDatabaseStrategy().getGenerationTiming(); if (timing == GenerationTiming.INSERT) { foundPostInsertGeneratedValues = true; } else if (timing == GenerationTiming.ALWAYS) { foundPostInsertGeneratedValues = true; foundPostUpdateGeneratedValues = true; } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (properties[i].isLazy()) { hasLazy = true; } if (properties[i].getCascadeStyle() != CascadeStyles.NONE) { foundCascade = true; } if (indicatesCollection(properties[i].getType())) { foundCollection = true; } if (propertyTypes[i].isMutable() && propertyCheckability[i]) { foundMutable = true; } mapPropertyToIndex(prop, i); i++; } if (naturalIdNumbers.size() == 0) { naturalIdPropertyNumbers = null; hasImmutableNaturalId = false; hasCacheableNaturalId = false; } else { naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers); hasImmutableNaturalId = !foundUpdateableNaturalIdProperty; hasCacheableNaturalId = persistentClass.getNaturalIdCacheRegionName() != null; } this.hasPreInsertGeneratedValues = foundPreInsertGeneratedValues; this.hasPreUpdateGeneratedValues = foundPreUpdateGeneratedValues; this.hasInsertGeneratedValues = foundPostInsertGeneratedValues; this.hasUpdateGeneratedValues = foundPostUpdateGeneratedValues; hasCascades = foundCascade; hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId; versionPropertyIndex = tempVersionProperty; hasLazyProperties = hasLazy; if (hasLazyProperties) LOG.lazyPropertyFetchingAvailable(name); lazy = persistentClass.isLazy() && ( // TODO: this disables laziness even in non-pojo entity modes: !persistentClass.hasPojoRepresentation() || !ReflectHelper.isFinalClass(persistentClass.getProxyInterface())); mutable = persistentClass.isMutable(); if (persistentClass.isAbstract() == null) { // legacy behavior (with no abstract attribute specified) isAbstract = persistentClass.hasPojoRepresentation() && ReflectHelper.isAbstractClass(persistentClass.getMappedClass()); } else { isAbstract = persistentClass.isAbstract().booleanValue(); if (!isAbstract && persistentClass.hasPojoRepresentation() && ReflectHelper.isAbstractClass(persistentClass.getMappedClass())) { LOG.entityMappedAsNonAbstract(name); } } selectBeforeUpdate = persistentClass.hasSelectBeforeUpdate(); dynamicUpdate = persistentClass.useDynamicUpdate(); dynamicInsert = persistentClass.useDynamicInsert(); polymorphic = persistentClass.isPolymorphic(); explicitPolymorphism = persistentClass.isExplicitPolymorphism(); inherited = persistentClass.isInherited(); superclass = inherited ? persistentClass.getSuperclass().getEntityName() : null; hasSubclasses = persistentClass.hasSubclasses(); optimisticLockStyle = persistentClass.getOptimisticLockStyle(); final boolean isAllOrDirty = optimisticLockStyle == OptimisticLockStyle.ALL || optimisticLockStyle == OptimisticLockStyle.DIRTY; if (isAllOrDirty && !dynamicUpdate) { throw new MappingException( "optimistic-lock=all|dirty requires dynamic-update=\"true\": " + name); } if (versionPropertyIndex != NO_VERSION_INDX && isAllOrDirty) { throw new MappingException( "version and optimistic-lock=all|dirty are not a valid combination : " + name); } hasCollections = foundCollection; hasMutableProperties = foundMutable; iter = persistentClass.getSubclassIterator(); while (iter.hasNext()) { subclassEntityNames.add(((PersistentClass) iter.next()).getEntityName()); } subclassEntityNames.add(name); if (persistentClass.hasPojoRepresentation()) { entityNameByInheritenceClassMap.put( persistentClass.getMappedClass(), persistentClass.getEntityName()); iter = persistentClass.getSubclassIterator(); while (iter.hasNext()) { final PersistentClass pc = (PersistentClass) iter.next(); entityNameByInheritenceClassMap.put(pc.getMappedClass(), pc.getEntityName()); } } entityMode = persistentClass.hasPojoRepresentation() ? EntityMode.POJO : EntityMode.MAP; final EntityTuplizerFactory entityTuplizerFactory = sessionFactory.getSettings().getEntityTuplizerFactory(); final String tuplizerClassName = persistentClass.getTuplizerImplClassName(entityMode); if (tuplizerClassName == null) { entityTuplizer = entityTuplizerFactory.constructDefaultTuplizer(entityMode, this, persistentClass); } else { entityTuplizer = entityTuplizerFactory.constructTuplizer(tuplizerClassName, this, persistentClass); } }
public EntityMetamodel(EntityBinding entityBinding, SessionFactoryImplementor sessionFactory) { this.sessionFactory = sessionFactory; name = entityBinding.getEntity().getName(); rootName = entityBinding.getHierarchyDetails().getRootEntityBinding().getEntity().getName(); entityType = sessionFactory.getTypeResolver().getTypeFactory().manyToOne(name); identifierProperty = PropertyFactory.buildIdentifierProperty( entityBinding, sessionFactory.getIdentifierGenerator(rootName)); versioned = entityBinding.isVersioned(); boolean hasPojoRepresentation = false; Class<?> mappedClass = null; Class<?> proxyInterfaceClass = null; if (entityBinding.getEntity().getClassReferenceUnresolved() != null) { hasPojoRepresentation = true; mappedClass = entityBinding.getEntity().getClassReference(); proxyInterfaceClass = entityBinding.getProxyInterfaceType().getValue(); } instrumentationMetadata = Environment.getBytecodeProvider().getEntityInstrumentationMetadata(mappedClass); boolean hasLazy = false; // TODO: Fix after HHH-6337 is fixed; for now assume entityBinding is the root binding BasicAttributeBinding rootEntityIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(); // entityBinding.getAttributeClosureSpan() includes the identifier binding; // "properties" here excludes the ID, so subtract 1 if the identifier binding is non-null propertySpan = rootEntityIdentifier == null ? entityBinding.getAttributeBindingClosureSpan() : entityBinding.getAttributeBindingClosureSpan() - 1; properties = new StandardProperty[propertySpan]; List naturalIdNumbers = new ArrayList(); // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ propertyNames = new String[propertySpan]; propertyTypes = new Type[propertySpan]; propertyUpdateability = new boolean[propertySpan]; propertyInsertability = new boolean[propertySpan]; insertInclusions = new ValueInclusion[propertySpan]; updateInclusions = new ValueInclusion[propertySpan]; nonlazyPropertyUpdateability = new boolean[propertySpan]; propertyCheckability = new boolean[propertySpan]; propertyNullability = new boolean[propertySpan]; propertyVersionability = new boolean[propertySpan]; propertyLaziness = new boolean[propertySpan]; cascadeStyles = new CascadeStyle[propertySpan]; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int i = 0; int tempVersionProperty = NO_VERSION_INDX; boolean foundCascade = false; boolean foundCollection = false; boolean foundMutable = false; boolean foundNonIdentifierPropertyNamedId = false; boolean foundInsertGeneratedValue = false; boolean foundUpdateGeneratedValue = false; boolean foundUpdateableNaturalIdProperty = false; for (AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure()) { if (attributeBinding == rootEntityIdentifier) { // skip the identifier attribute binding continue; } if (attributeBinding == entityBinding.getHierarchyDetails().getVersioningAttributeBinding()) { tempVersionProperty = i; properties[i] = PropertyFactory.buildVersionProperty( entityBinding.getHierarchyDetails().getVersioningAttributeBinding(), instrumentationMetadata.isInstrumented()); } else { properties[i] = PropertyFactory.buildStandardProperty( attributeBinding, instrumentationMetadata.isInstrumented()); } // TODO: fix when natural IDs are added (HHH-6354) // if ( attributeBinding.isNaturalIdentifier() ) { // naturalIdNumbers.add( i ); // if ( attributeBinding.isUpdateable() ) { // foundUpdateableNaturalIdProperty = true; // } // } if ("id".equals(attributeBinding.getAttribute().getName())) { foundNonIdentifierPropertyNamedId = true; } // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ boolean lazy = attributeBinding.isLazy() && instrumentationMetadata.isInstrumented(); if (lazy) hasLazy = true; propertyLaziness[i] = lazy; propertyNames[i] = properties[i].getName(); propertyTypes[i] = properties[i].getType(); propertyNullability[i] = properties[i].isNullable(); propertyUpdateability[i] = properties[i].isUpdateable(); propertyInsertability[i] = properties[i].isInsertable(); insertInclusions[i] = determineInsertValueGenerationType(attributeBinding, properties[i]); updateInclusions[i] = determineUpdateValueGenerationType(attributeBinding, properties[i]); propertyVersionability[i] = properties[i].isVersionable(); nonlazyPropertyUpdateability[i] = properties[i].isUpdateable() && !lazy; propertyCheckability[i] = propertyUpdateability[i] || (propertyTypes[i].isAssociationType() && ((AssociationType) propertyTypes[i]).isAlwaysDirtyChecked()); cascadeStyles[i] = properties[i].getCascadeStyle(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (properties[i].isLazy()) { hasLazy = true; } if (properties[i].getCascadeStyle() != CascadeStyles.NONE) { foundCascade = true; } if (indicatesCollection(properties[i].getType())) { foundCollection = true; } if (propertyTypes[i].isMutable() && propertyCheckability[i]) { foundMutable = true; } if (insertInclusions[i] != ValueInclusion.NONE) { foundInsertGeneratedValue = true; } if (updateInclusions[i] != ValueInclusion.NONE) { foundUpdateGeneratedValue = true; } mapPropertyToIndex(attributeBinding.getAttribute(), i); i++; } if (naturalIdNumbers.size() == 0) { naturalIdPropertyNumbers = null; hasImmutableNaturalId = false; hasCacheableNaturalId = false; } else { naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers); hasImmutableNaturalId = !foundUpdateableNaturalIdProperty; hasCacheableNaturalId = false; // See previous TODO and HHH-6354 } hasInsertGeneratedValues = foundInsertGeneratedValue; hasUpdateGeneratedValues = foundUpdateGeneratedValue; hasCascades = foundCascade; hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId; versionPropertyIndex = tempVersionProperty; hasLazyProperties = hasLazy; if (hasLazyProperties) { LOG.lazyPropertyFetchingAvailable(name); } lazy = entityBinding.isLazy() && ( // TODO: this disables laziness even in non-pojo entity modes: !hasPojoRepresentation || !ReflectHelper.isFinalClass(proxyInterfaceClass)); mutable = entityBinding.isMutable(); if (entityBinding.isAbstract() == null) { // legacy behavior (with no abstract attribute specified) isAbstract = hasPojoRepresentation && ReflectHelper.isAbstractClass(mappedClass); } else { isAbstract = entityBinding.isAbstract().booleanValue(); if (!isAbstract && hasPojoRepresentation && ReflectHelper.isAbstractClass(mappedClass)) { LOG.entityMappedAsNonAbstract(name); } } selectBeforeUpdate = entityBinding.isSelectBeforeUpdate(); dynamicUpdate = entityBinding.isDynamicUpdate(); dynamicInsert = entityBinding.isDynamicInsert(); hasSubclasses = entityBinding.hasSubEntityBindings(); polymorphic = entityBinding.isPolymorphic(); explicitPolymorphism = entityBinding.getHierarchyDetails().isExplicitPolymorphism(); inherited = !entityBinding.isRoot(); superclass = inherited ? entityBinding.getEntity().getSuperType().getName() : null; optimisticLockStyle = entityBinding.getHierarchyDetails().getOptimisticLockStyle(); final boolean isAllOrDirty = optimisticLockStyle == OptimisticLockStyle.ALL || optimisticLockStyle == OptimisticLockStyle.DIRTY; if (isAllOrDirty && !dynamicUpdate) { throw new MappingException( "optimistic-lock=all|dirty requires dynamic-update=\"true\": " + name); } if (versionPropertyIndex != NO_VERSION_INDX && isAllOrDirty) { throw new MappingException( "version and optimistic-lock=all|dirty are not a valid combination : " + name); } hasCollections = foundCollection; hasMutableProperties = foundMutable; for (EntityBinding subEntityBinding : entityBinding.getPostOrderSubEntityBindingClosure()) { subclassEntityNames.add(subEntityBinding.getEntity().getName()); if (subEntityBinding.getEntity().getClassReference() != null) { entityNameByInheritenceClassMap.put( subEntityBinding.getEntity().getClassReference(), subEntityBinding.getEntity().getName()); } } subclassEntityNames.add(name); if (mappedClass != null) { entityNameByInheritenceClassMap.put(mappedClass, name); } entityMode = hasPojoRepresentation ? EntityMode.POJO : EntityMode.MAP; final EntityTuplizerFactory entityTuplizerFactory = sessionFactory.getSettings().getEntityTuplizerFactory(); Class<? extends EntityTuplizer> tuplizerClass = entityBinding.getCustomEntityTuplizerClass(); if (tuplizerClass == null) { entityTuplizer = entityTuplizerFactory.constructDefaultTuplizer(entityMode, this, entityBinding); } else { entityTuplizer = entityTuplizerFactory.constructTuplizer(tuplizerClass, this, entityBinding); } }