use of org.hibernate.mapping.Property in project hibernate-orm by hibernate.
the class MapBinder method bindKeyFromAssociationTable.
private void bindKeyFromAssociationTable(XClass collType, Map persistentClasses, String mapKeyPropertyName, XProperty property, boolean isEmbedded, MetadataBuildingContext buildingContext, Ejb3Column[] mapKeyColumns, Ejb3JoinColumn[] mapKeyManyToManyColumns, String targetPropertyName) {
if (mapKeyPropertyName != null) {
//this is an EJB3 @MapKey
PersistentClass associatedClass = (PersistentClass) persistentClasses.get(collType.getName());
if (associatedClass == null)
throw new AnnotationException("Associated class not found: " + collType);
Property mapProperty = BinderHelper.findPropertyByName(associatedClass, mapKeyPropertyName);
if (mapProperty == null) {
throw new AnnotationException("Map key property not found: " + collType + "." + mapKeyPropertyName);
}
org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
// HHH-11005 - if InheritanceType.JOINED then need to find class defining the column
InheritanceState inheritanceState = inheritanceStatePerClass.get(collType);
PersistentClass targetPropertyPersistentClass = InheritanceType.JOINED.equals(inheritanceState.getType()) ? mapProperty.getPersistentClass() : associatedClass;
Value indexValue = createFormulatedValue(mapProperty.getValue(), map, targetPropertyName, associatedClass, targetPropertyPersistentClass, buildingContext);
map.setIndex(indexValue);
} else {
//this is a true Map mapping
//TODO ugly copy/pastle from CollectionBinder.bindManyToManySecondPass
String mapKeyType;
Class target = void.class;
/*
* target has priority over reflection for the map key type
* JPA 2 has priority
*/
if (property.isAnnotationPresent(MapKeyClass.class)) {
target = property.getAnnotation(MapKeyClass.class).value();
}
if (!void.class.equals(target)) {
mapKeyType = target.getName();
} else {
mapKeyType = property.getMapKey().getName();
}
PersistentClass collectionEntity = (PersistentClass) persistentClasses.get(mapKeyType);
boolean isIndexOfEntities = collectionEntity != null;
ManyToOne element = null;
org.hibernate.mapping.Map mapValue = (org.hibernate.mapping.Map) this.collection;
if (isIndexOfEntities) {
element = new ManyToOne(buildingContext.getMetadataCollector(), mapValue.getCollectionTable());
mapValue.setIndex(element);
element.setReferencedEntityName(mapKeyType);
//element.setFetchMode( fetchMode );
//element.setLazy( fetchMode != FetchMode.JOIN );
//make the second join non lazy
element.setFetchMode(FetchMode.JOIN);
element.setLazy(false);
//does not make sense for a map key element.setIgnoreNotFound( ignoreNotFound );
} else {
XClass keyXClass;
AnnotatedClassType classType;
if (BinderHelper.PRIMITIVE_NAMES.contains(mapKeyType)) {
classType = AnnotatedClassType.NONE;
keyXClass = null;
} else {
try {
keyXClass = buildingContext.getBuildingOptions().getReflectionManager().classForName(mapKeyType);
} catch (ClassLoadingException e) {
throw new AnnotationException("Unable to find class: " + mapKeyType, e);
}
classType = buildingContext.getMetadataCollector().getClassType(keyXClass);
// force in case of attribute override naming the key
if (isEmbedded || mappingDefinedAttributeOverrideOnMapKey(property)) {
classType = AnnotatedClassType.EMBEDDABLE;
}
}
CollectionPropertyHolder holder = PropertyHolderBuilder.buildPropertyHolder(mapValue, StringHelper.qualify(mapValue.getRole(), "mapkey"), keyXClass, property, propertyHolder, buildingContext);
// 'propertyHolder' is the PropertyHolder for the owner of the collection
// 'holder' is the CollectionPropertyHolder.
// 'property' is the collection XProperty
propertyHolder.startingProperty(property);
holder.prepare(property);
PersistentClass owner = mapValue.getOwner();
AccessType accessType;
// 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 = (Property) owner.getIdentifierMapper().getPropertyIterator().next();
accessType = prop.getPropertyAccessorName().equals("property") ? AccessType.PROPERTY : AccessType.FIELD;
} else {
throw new AssertionFailure("Unable to guess collection property accessor name");
}
if (AnnotatedClassType.EMBEDDABLE.equals(classType)) {
EntityBinder entityBinder = new EntityBinder();
PropertyData inferredData;
if (isHibernateExtensionMapping()) {
inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "index", keyXClass);
} else {
//"key" is the JPA 2 prefix for map keys
inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "key", keyXClass);
}
//TODO be smart with isNullable
Component component = AnnotationBinder.fillComponent(holder, inferredData, accessType, true, entityBinder, false, false, true, buildingContext, inheritanceStatePerClass);
mapValue.setIndex(component);
} else {
SimpleValueBinder elementBinder = new SimpleValueBinder();
elementBinder.setBuildingContext(buildingContext);
elementBinder.setReturnedClassName(mapKeyType);
Ejb3Column[] elementColumns = mapKeyColumns;
if (elementColumns == null || elementColumns.length == 0) {
elementColumns = new Ejb3Column[1];
Ejb3Column column = new Ejb3Column();
column.setImplicit(false);
column.setNullable(true);
column.setLength(Ejb3Column.DEFAULT_COLUMN_LENGTH);
column.setLogicalColumnName(Collection.DEFAULT_KEY_COLUMN_NAME);
//TODO create an EMPTY_JOINS collection
column.setJoins(new HashMap<String, Join>());
column.setBuildingContext(buildingContext);
column.bind();
elementColumns[0] = column;
}
//override the table
for (Ejb3Column column : elementColumns) {
column.setTable(mapValue.getCollectionTable());
}
elementBinder.setColumns(elementColumns);
//do not call setType as it extract the type from @Type
//the algorithm generally does not apply for map key anyway
elementBinder.setKey(true);
elementBinder.setType(property, keyXClass, this.collection.getOwnerEntityName(), holder.mapKeyAttributeConverterDescriptor(property, keyXClass));
elementBinder.setPersistentClassName(propertyHolder.getEntityName());
elementBinder.setAccessType(accessType);
mapValue.setIndex(elementBinder.make());
}
}
//FIXME pass the Index Entity JoinColumns
if (!collection.isOneToMany()) {
//index column shoud not be null
for (Ejb3JoinColumn col : mapKeyManyToManyColumns) {
col.forceNotNull();
}
}
if (element != null) {
final javax.persistence.ForeignKey foreignKey = getMapKeyForeignKey(property);
if (foreignKey != null) {
if (foreignKey.value() == ConstraintMode.NO_CONSTRAINT) {
element.setForeignKeyName("none");
} else {
element.setForeignKeyName(StringHelper.nullIfEmpty(foreignKey.name()));
element.setForeignKeyDefinition(StringHelper.nullIfEmpty(foreignKey.foreignKeyDefinition()));
}
}
}
if (isIndexOfEntities) {
bindManytoManyInverseFk(collectionEntity, mapKeyManyToManyColumns, element, //a map key column has no unique constraint
false, buildingContext);
}
}
}
use of org.hibernate.mapping.Property in project hibernate-orm by hibernate.
the class MapBinder method createFormulatedValue.
protected Value createFormulatedValue(Value value, Collection collection, String targetPropertyName, PersistentClass associatedClass, PersistentClass targetPropertyPersistentClass, MetadataBuildingContext buildingContext) {
Value element = collection.getElement();
String fromAndWhere = null;
if (!(element instanceof OneToMany)) {
String referencedPropertyName = null;
if (element instanceof ToOne) {
referencedPropertyName = ((ToOne) element).getReferencedPropertyName();
} else if (element instanceof DependantValue) {
//TODO this never happen I think
if (propertyName != null) {
referencedPropertyName = collection.getReferencedPropertyName();
} else {
throw new AnnotationException("SecondaryTable JoinColumn cannot reference a non primary key");
}
}
Iterator<Selectable> referencedEntityColumns;
if (referencedPropertyName == null) {
referencedEntityColumns = associatedClass.getIdentifier().getColumnIterator();
} else {
Property referencedProperty = associatedClass.getRecursiveProperty(referencedPropertyName);
referencedEntityColumns = referencedProperty.getColumnIterator();
}
fromAndWhere = getFromAndWhereFormula(associatedClass.getTable().getName(), element.getColumnIterator(), referencedEntityColumns);
} else {
// 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)) {
fromAndWhere = getFromAndWhereFormula(targetPropertyPersistentClass.getTable().getQualifiedTableName().toString(), element.getColumnIterator(), associatedClass.getIdentifier().getColumnIterator());
}
}
if (value instanceof Component) {
Component component = (Component) value;
Iterator properties = component.getPropertyIterator();
Component indexComponent = new Component(getBuildingContext().getMetadataCollector(), collection);
indexComponent.setComponentClassName(component.getComponentClassName());
while (properties.hasNext()) {
Property current = (Property) properties.next();
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, targetPropertyName, associatedClass, associatedClass, buildingContext));
indexComponent.addProperty(newProperty);
}
return indexComponent;
} else if (value instanceof SimpleValue) {
SimpleValue sourceValue = (SimpleValue) value;
SimpleValue targetValue;
if (value instanceof ManyToOne) {
ManyToOne sourceManyToOne = (ManyToOne) sourceValue;
ManyToOne targetManyToOne = new ManyToOne(getBuildingContext().getMetadataCollector(), collection.getCollectionTable());
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 SimpleValue(getBuildingContext().getMetadataCollector(), collection.getCollectionTable());
targetValue.copyTypeFrom(sourceValue);
}
Iterator columns = sourceValue.getColumnIterator();
Random random = new Random();
while (columns.hasNext()) {
Object current = columns.next();
Formula formula = new Formula();
String formulaString;
if (current instanceof Column) {
formulaString = ((Column) current).getQuotedName();
} else if (current instanceof Formula) {
formulaString = ((Formula) current).getFormula();
} else {
throw new AssertionFailure("Unknown element in column iterator: " + current.getClass());
}
if (fromAndWhere != null) {
formulaString = Template.renderWhereStringTemplate(formulaString, "$alias$", new HSQLDialect());
formulaString = "(select " + formulaString + fromAndWhere + ")";
formulaString = StringHelper.replace(formulaString, "$alias$", "a" + random.nextInt(16));
}
formula.setFormula(formulaString);
targetValue.addFormula(formula);
}
return targetValue;
} else {
throw new AssertionFailure("Unknown type encounters for map key: " + value.getClass());
}
}
use of org.hibernate.mapping.Property in project hibernate-orm by hibernate.
the class PropertyBinder method makeProperty.
//used when the value is provided and the binding is done elsewhere
public Property makeProperty() {
validateMake();
LOG.debugf("Building property %s", name);
Property prop = new Property();
prop.setName(name);
prop.setValue(value);
prop.setLazy(lazy);
prop.setLazyGroup(lazyGroup);
prop.setCascade(cascade);
prop.setPropertyAccessorName(accessType.getType());
if (property != null) {
prop.setValueGenerationStrategy(determineValueGenerationStrategy(property));
}
NaturalId naturalId = property != null ? property.getAnnotation(NaturalId.class) : null;
if (naturalId != null) {
if (!entityBinder.isRootEntity()) {
throw new AnnotationException("@NaturalId only valid on root entity (or its @MappedSuperclasses)");
}
if (!naturalId.mutable()) {
updatable = false;
}
prop.setNaturalIdentifier(true);
}
// HHH-4635 -- needed for dialect-specific property ordering
Lob lob = property != null ? property.getAnnotation(Lob.class) : null;
prop.setLob(lob != null);
prop.setInsertable(insertable);
prop.setUpdateable(updatable);
// this is already handled for collections in CollectionBinder...
if (Collection.class.isInstance(value)) {
prop.setOptimisticLocked(((Collection) value).isOptimisticLocked());
} else {
final OptimisticLock lockAnn = property != null ? property.getAnnotation(OptimisticLock.class) : null;
if (lockAnn != null) {
//TODO this should go to the core as a mapping validation checking
if (lockAnn.excluded() && (property.isAnnotationPresent(javax.persistence.Version.class) || property.isAnnotationPresent(Id.class) || property.isAnnotationPresent(EmbeddedId.class))) {
throw new AnnotationException("@OptimisticLock.exclude=true incompatible with @Id, @EmbeddedId and @Version: " + StringHelper.qualify(holder.getPath(), name));
}
}
// && updatable as well???
final boolean isOwnedValue = !isToOneValue(value) || insertable;
final boolean includeInOptimisticLockChecks = (lockAnn != null) ? !lockAnn.excluded() : isOwnedValue;
prop.setOptimisticLocked(includeInOptimisticLockChecks);
}
LOG.tracev("Cascading {0} with {1}", name, cascade);
this.mappingProperty = prop;
return prop;
}
use of org.hibernate.mapping.Property in project hibernate-orm by hibernate.
the class TableBinder method bindFk.
public static void bindFk(PersistentClass referencedEntity, PersistentClass destinationEntity, Ejb3JoinColumn[] columns, SimpleValue value, boolean unique, MetadataBuildingContext buildingContext) {
PersistentClass associatedClass;
if (destinationEntity != null) {
//overridden destination
associatedClass = destinationEntity;
} else {
associatedClass = columns[0].getPropertyHolder() == null ? null : columns[0].getPropertyHolder().getPersistentClass();
}
final String mappedByProperty = columns[0].getMappedBy();
if (StringHelper.isNotEmpty(mappedByProperty)) {
/**
* Get the columns of the mapped-by property
* copy them and link the copy to the actual value
*/
LOG.debugf("Retrieving property %s.%s", associatedClass.getEntityName(), mappedByProperty);
final Property property = associatedClass.getRecursiveProperty(columns[0].getMappedBy());
Iterator mappedByColumns;
if (property.getValue() instanceof Collection) {
Collection collection = ((Collection) property.getValue());
Value element = collection.getElement();
if (element == null) {
throw new AnnotationException("Illegal use of mappedBy on both sides of the relationship: " + associatedClass.getEntityName() + "." + mappedByProperty);
}
mappedByColumns = element.getColumnIterator();
} else {
mappedByColumns = property.getValue().getColumnIterator();
}
while (mappedByColumns.hasNext()) {
Column column = (Column) mappedByColumns.next();
columns[0].overrideFromReferencedColumnIfNecessary(column);
columns[0].linkValueUsingAColumnCopy(column, value);
}
} else if (columns[0].isImplicit()) {
/**
* if columns are implicit, then create the columns based on the
* referenced entity id columns
*/
Iterator idColumns;
if (referencedEntity instanceof JoinedSubclass) {
idColumns = referencedEntity.getKey().getColumnIterator();
} else {
idColumns = referencedEntity.getIdentifier().getColumnIterator();
}
while (idColumns.hasNext()) {
Column column = (Column) idColumns.next();
columns[0].linkValueUsingDefaultColumnNaming(column, referencedEntity, value);
columns[0].overrideFromReferencedColumnIfNecessary(column);
}
} else {
int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType(columns, referencedEntity, buildingContext);
if (Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum) {
String referencedPropertyName;
if (value instanceof ToOne) {
referencedPropertyName = ((ToOne) value).getReferencedPropertyName();
} else if (value instanceof DependantValue) {
String propertyName = columns[0].getPropertyName();
if (propertyName != null) {
Collection collection = (Collection) referencedEntity.getRecursiveProperty(propertyName).getValue();
referencedPropertyName = collection.getReferencedPropertyName();
} else {
throw new AnnotationException("SecondaryTable JoinColumn cannot reference a non primary key");
}
} else {
throw new AssertionFailure("Do a property ref on an unexpected Value type: " + value.getClass().getName());
}
if (referencedPropertyName == null) {
throw new AssertionFailure("No property ref found while expected");
}
Property synthProp = referencedEntity.getReferencedProperty(referencedPropertyName);
if (synthProp == null) {
throw new AssertionFailure("Cannot find synthProp: " + referencedEntity.getEntityName() + "." + referencedPropertyName);
}
linkJoinColumnWithValueOverridingNameIfImplicit(referencedEntity, synthProp.getColumnIterator(), columns, value);
} else {
if (Ejb3JoinColumn.NO_REFERENCE == fkEnum) {
//implicit case, we hope PK and FK columns are in the same order
if (columns.length != referencedEntity.getIdentifier().getColumnSpan()) {
throw new AnnotationException("A Foreign key refering " + referencedEntity.getEntityName() + " from " + associatedClass.getEntityName() + " has the wrong number of column. should be " + referencedEntity.getIdentifier().getColumnSpan());
}
linkJoinColumnWithValueOverridingNameIfImplicit(referencedEntity, referencedEntity.getIdentifier().getColumnIterator(), columns, value);
} else {
//explicit referencedColumnName
Iterator idColItr = referencedEntity.getKey().getColumnIterator();
org.hibernate.mapping.Column col;
//works cause the pk has to be on the primary table
Table table = referencedEntity.getTable();
if (!idColItr.hasNext()) {
LOG.debug("No column in the identifier!");
}
while (idColItr.hasNext()) {
boolean match = false;
//for each PK column, find the associated FK column.
col = (org.hibernate.mapping.Column) idColItr.next();
for (Ejb3JoinColumn joinCol : columns) {
String referencedColumn = joinCol.getReferencedColumn();
referencedColumn = buildingContext.getMetadataCollector().getPhysicalColumnName(table, referencedColumn);
//In JPA 2 referencedColumnName is case insensitive
if (referencedColumn.equalsIgnoreCase(col.getQuotedName(buildingContext.getMetadataCollector().getDatabase().getJdbcEnvironment().getDialect()))) {
//proper join column
if (joinCol.isNameDeferred()) {
joinCol.linkValueUsingDefaultColumnNaming(col, referencedEntity, value);
} else {
joinCol.linkWithValue(value);
}
joinCol.overrideFromReferencedColumnIfNecessary(col);
match = true;
break;
}
}
if (!match) {
throw new AnnotationException("Column name " + col.getName() + " of " + referencedEntity.getEntityName() + " not found in JoinColumns.referencedColumnName");
}
}
}
}
}
value.createForeignKey();
if (unique) {
createUniqueConstraint(value);
}
}
use of org.hibernate.mapping.Property in project hibernate-orm by hibernate.
the class CopyIdentifierComponentSecondPass method doSecondPass.
@SuppressWarnings({ "unchecked" })
public void doSecondPass(Map persistentClasses) throws MappingException {
PersistentClass referencedPersistentClass = (PersistentClass) persistentClasses.get(referencedEntityName);
// TODO better error names
if (referencedPersistentClass == null) {
throw new AnnotationException("Unknown entity name: " + referencedEntityName);
}
if (!(referencedPersistentClass.getIdentifier() instanceof Component)) {
throw new AssertionFailure("Unexpected identifier type on the referenced entity when mapping a @MapsId: " + referencedEntityName);
}
Component referencedComponent = (Component) referencedPersistentClass.getIdentifier();
Iterator<Property> properties = referencedComponent.getPropertyIterator();
//prepare column name structure
boolean isExplicitReference = true;
Map<String, Ejb3JoinColumn> columnByReferencedName = new HashMap<String, Ejb3JoinColumn>(joinColumns.length);
for (Ejb3JoinColumn joinColumn : joinColumns) {
final String referencedColumnName = joinColumn.getReferencedColumn();
if (referencedColumnName == null || BinderHelper.isEmptyAnnotationValue(referencedColumnName)) {
break;
}
//JPA 2 requires referencedColumnNames to be case insensitive
columnByReferencedName.put(referencedColumnName.toLowerCase(Locale.ROOT), joinColumn);
}
//try default column orientation
AtomicInteger index = new AtomicInteger(0);
if (columnByReferencedName.isEmpty()) {
isExplicitReference = false;
for (Ejb3JoinColumn joinColumn : joinColumns) {
columnByReferencedName.put("" + index.get(), joinColumn);
index.getAndIncrement();
}
index.set(0);
}
while (properties.hasNext()) {
Property referencedProperty = properties.next();
if (referencedProperty.isComposite()) {
Property property = createComponentProperty(referencedPersistentClass, isExplicitReference, columnByReferencedName, index, referencedProperty);
component.addProperty(property);
} else {
Property property = createSimpleProperty(referencedPersistentClass, isExplicitReference, columnByReferencedName, index, referencedProperty);
component.addProperty(property);
}
}
}
Aggregations