use of org.hibernate.mapping.PersistentClass in project hibernate-orm by hibernate.
the class IndexOrUniqueKeySecondPass method doSecondPass.
@Override
public void doSecondPass(Map persistentClasses) throws MappingException {
if (columns != null) {
for (int i = 0; i < columns.length; i++) {
addConstraintToColumn(columns[i]);
}
}
if (column != null) {
this.table = column.getTable();
final PropertyHolder propertyHolder = column.getPropertyHolder();
String entityName = (propertyHolder.isComponent()) ? propertyHolder.getPersistentClass().getEntityName() : propertyHolder.getEntityName();
final PersistentClass persistentClass = (PersistentClass) persistentClasses.get(entityName);
final Property property = persistentClass.getProperty(column.getPropertyName());
if (property.getValue() instanceof Component) {
final Component component = (Component) property.getValue();
List<Column> columns = new ArrayList<>();
component.getColumnIterator().forEachRemaining(selectable -> {
if (selectable instanceof Column) {
columns.add((Column) selectable);
}
});
addConstraintToColumns(columns);
} else {
addConstraintToColumn(buildingContext.getMetadataCollector().getLogicalColumnName(table, column.getMappingColumn().getQuotedName()));
}
}
}
use of org.hibernate.mapping.PersistentClass 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, 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.getBootstrapContext().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.PersistentClass in project hibernate-orm by hibernate.
the class BinderHelper method findColumnOwner.
/**
* Find the column owner (ie PersistentClass or Join) of columnName.
* If columnName is null or empty, persistentClass is returned
*/
public static Object findColumnOwner(PersistentClass persistentClass, String columnName, MetadataBuildingContext context) {
if (StringHelper.isEmpty(columnName)) {
// shortcut for implicit referenced column names
return persistentClass;
}
PersistentClass current = persistentClass;
Object result;
boolean found = false;
do {
result = current;
Table currentTable = current.getTable();
try {
context.getMetadataCollector().getPhysicalColumnName(currentTable, columnName);
found = true;
} catch (MappingException me) {
// swallow it
}
Iterator joins = current.getJoinIterator();
while (!found && joins.hasNext()) {
result = joins.next();
currentTable = ((Join) result).getTable();
try {
context.getMetadataCollector().getPhysicalColumnName(currentTable, columnName);
found = true;
} catch (MappingException me) {
// swallow it
}
}
current = current.getSuperclass();
} while (!found && current != null);
return found ? result : null;
}
use of org.hibernate.mapping.PersistentClass in project hibernate-orm by hibernate.
the class BinderHelper method createSyntheticPropertyReference.
// This is sooooooooo close in terms of not generating a synthetic property if we do not have to (where property ref
// refers to a single property). The sticking point is cases where the `referencedPropertyName` come from subclasses
// or secondary tables. Part of the problem is in PersistentClass itself during attempts to resolve the referenced
// property; currently it only considers non-subclass and non-joined properties. Part of the problem is in terms
// of SQL generation.
// public static void createSyntheticPropertyReference(
// Ejb3JoinColumn[] columns,
// PersistentClass ownerEntity,
// PersistentClass associatedEntity,
// Value value,
// boolean inverse,
// Mappings mappings) {
// //associated entity only used for more precise exception, yuk!
// if ( columns[0].isImplicit() || StringHelper.isNotEmpty( columns[0].getMappedBy() ) ) return;
// int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType( columns, ownerEntity, mappings );
// PersistentClass associatedClass = columns[0].getPropertyHolder() != null ?
// columns[0].getPropertyHolder().getPersistentClass() :
// null;
// if ( Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum ) {
// //find properties associated to a certain column
// Object columnOwner = findColumnOwner( ownerEntity, columns[0].getReferencedColumn(), mappings );
// List<Property> properties = findPropertiesByColumns( columnOwner, columns, mappings );
//
// if ( properties == null ) {
// //TODO use a ToOne type doing a second select
// StringBuilder columnsList = new StringBuilder();
// columnsList.append( "referencedColumnNames(" );
// for (Ejb3JoinColumn column : columns) {
// columnsList.append( column.getReferencedColumn() ).append( ", " );
// }
// columnsList.setLength( columnsList.length() - 2 );
// columnsList.append( ") " );
//
// if ( associatedEntity != null ) {
// //overidden destination
// columnsList.append( "of " )
// .append( associatedEntity.getEntityName() )
// .append( "." )
// .append( columns[0].getPropertyName() )
// .append( " " );
// }
// else {
// if ( columns[0].getPropertyHolder() != null ) {
// columnsList.append( "of " )
// .append( columns[0].getPropertyHolder().getEntityName() )
// .append( "." )
// .append( columns[0].getPropertyName() )
// .append( " " );
// }
// }
// columnsList.append( "referencing " )
// .append( ownerEntity.getEntityName() )
// .append( " not mapped to a single property" );
// throw new AnnotationException( columnsList.toString() );
// }
//
// final String referencedPropertyName;
//
// if ( properties.size() == 1 ) {
// referencedPropertyName = properties.get(0).getName();
// }
// else {
// // Create a synthetic (embedded composite) property to use as the referenced property which
// // contains all the properties mapped to the referenced columns. We need to make a shallow copy
// // of the properties to mark them as non-insertable/updatable.
//
// // todo : what if the columns all match with an existing component?
//
// StringBuilder propertyNameBuffer = new StringBuilder( "_" );
// propertyNameBuffer.append( associatedClass.getEntityName().replace( '.', '_' ) );
// propertyNameBuffer.append( "_" ).append( columns[0].getPropertyName() );
// String syntheticPropertyName = propertyNameBuffer.toString();
// //create an embeddable component
//
// //todo how about properties.size() == 1, this should be much simpler
// Component embeddedComp = columnOwner instanceof PersistentClass ?
// new Component( mappings, (PersistentClass) columnOwner ) :
// new Component( mappings, (Join) columnOwner );
// embeddedComp.setEmbedded( true );
// embeddedComp.setNodeName( syntheticPropertyName );
// embeddedComp.setComponentClassName( embeddedComp.getOwner().getClassName() );
// for (Property property : properties) {
// Property clone = BinderHelper.shallowCopy( property );
// clone.setInsertable( false );
// clone.setUpdateable( false );
// clone.setNaturalIdentifier( false );
// clone.setGeneration( property.getGeneration() );
// embeddedComp.addProperty( clone );
// }
// SyntheticProperty synthProp = new SyntheticProperty();
// synthProp.setName( syntheticPropertyName );
// synthProp.setNodeName( syntheticPropertyName );
// synthProp.setPersistentClass( ownerEntity );
// synthProp.setUpdateable( false );
// synthProp.setInsertable( false );
// synthProp.setValue( embeddedComp );
// synthProp.setPropertyAccessorName( "embedded" );
// ownerEntity.addProperty( synthProp );
// //make it unique
// TableBinder.createUniqueConstraint( embeddedComp );
//
// referencedPropertyName = syntheticPropertyName;
// }
//
// /**
// * creating the property ref to the new synthetic property
// */
// if ( value instanceof ToOne ) {
// ( (ToOne) value ).setReferencedPropertyName( referencedPropertyName );
// mappings.addUniquePropertyReference( ownerEntity.getEntityName(), referencedPropertyName );
// }
// else if ( value instanceof Collection ) {
// ( (Collection) value ).setReferencedPropertyName( referencedPropertyName );
// //not unique because we could create a mtm wo association table
// mappings.addPropertyReference( ownerEntity.getEntityName(), referencedPropertyName );
// }
// else {
// throw new AssertionFailure(
// "Do a property ref on an unexpected Value type: "
// + value.getClass().getName()
// );
// }
// mappings.addPropertyReferencedAssociation(
// ( inverse ? "inverse__" : "" ) + associatedClass.getEntityName(),
// columns[0].getPropertyName(),
// referencedPropertyName
// );
// }
// }
public static void createSyntheticPropertyReference(Ejb3JoinColumn[] columns, PersistentClass ownerEntity, PersistentClass associatedEntity, Value value, boolean inverse, MetadataBuildingContext context) {
// associated entity only used for more precise exception, yuk!
if (columns[0].isImplicit() || StringHelper.isNotEmpty(columns[0].getMappedBy())) {
return;
}
int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType(columns, ownerEntity, context);
PersistentClass associatedClass = columns[0].getPropertyHolder() != null ? columns[0].getPropertyHolder().getPersistentClass() : null;
if (Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum) {
/**
* Create a synthetic property to refer to including an
* embedded component value containing all the properties
* mapped to the referenced columns
* We need to shallow copy those properties to mark them
* as non insertable / non updatable
*/
StringBuilder propertyNameBuffer = new StringBuilder("_");
propertyNameBuffer.append(associatedClass.getEntityName().replace('.', '_'));
propertyNameBuffer.append("_").append(columns[0].getPropertyName().replace('.', '_'));
String syntheticPropertyName = propertyNameBuffer.toString();
// find properties associated to a certain column
Object columnOwner = findColumnOwner(ownerEntity, columns[0].getReferencedColumn(), context);
List<Property> properties = findPropertiesByColumns(columnOwner, columns, context);
// create an embeddable component
Property synthProp;
if (properties != null) {
// todo how about properties.size() == 1, this should be much simpler
Component embeddedComp = columnOwner instanceof PersistentClass ? new Component(context, (PersistentClass) columnOwner) : new Component(context, (Join) columnOwner);
embeddedComp.setEmbedded(true);
embeddedComp.setComponentClassName(embeddedComp.getOwner().getClassName());
for (Property property : properties) {
Property clone = BinderHelper.shallowCopy(property);
clone.setInsertable(false);
clone.setUpdateable(false);
clone.setNaturalIdentifier(false);
clone.setValueGenerationStrategy(property.getValueGenerationStrategy());
embeddedComp.addProperty(clone);
}
synthProp = new SyntheticProperty();
synthProp.setName(syntheticPropertyName);
synthProp.setPersistentClass(ownerEntity);
synthProp.setUpdateable(false);
synthProp.setInsertable(false);
synthProp.setValue(embeddedComp);
synthProp.setPropertyAccessorName("embedded");
ownerEntity.addProperty(synthProp);
// make it unique
TableBinder.createUniqueConstraint(embeddedComp);
} else {
// TODO use a ToOne type doing a second select
StringBuilder columnsList = new StringBuilder();
columnsList.append("referencedColumnNames(");
for (Ejb3JoinColumn column : columns) {
columnsList.append(column.getReferencedColumn()).append(", ");
}
columnsList.setLength(columnsList.length() - 2);
columnsList.append(") ");
if (associatedEntity != null) {
// overidden destination
columnsList.append("of ").append(associatedEntity.getEntityName()).append(".").append(columns[0].getPropertyName()).append(" ");
} else {
if (columns[0].getPropertyHolder() != null) {
columnsList.append("of ").append(columns[0].getPropertyHolder().getEntityName()).append(".").append(columns[0].getPropertyName()).append(" ");
}
}
columnsList.append("referencing ").append(ownerEntity.getEntityName()).append(" not mapped to a single property");
throw new AnnotationException(columnsList.toString());
}
/**
* creating the property ref to the new synthetic property
*/
if (value instanceof ToOne) {
((ToOne) value).setReferencedPropertyName(syntheticPropertyName);
((ToOne) value).setReferenceToPrimaryKey(syntheticPropertyName == null);
context.getMetadataCollector().addUniquePropertyReference(ownerEntity.getEntityName(), syntheticPropertyName);
} else if (value instanceof Collection) {
((Collection) value).setReferencedPropertyName(syntheticPropertyName);
// not unique because we could create a mtm wo association table
context.getMetadataCollector().addPropertyReference(ownerEntity.getEntityName(), syntheticPropertyName);
} else {
throw new AssertionFailure("Do a property ref on an unexpected Value type: " + value.getClass().getName());
}
context.getMetadataCollector().addPropertyReferencedAssociation((inverse ? "inverse__" : "") + associatedClass.getEntityName(), columns[0].getPropertyName(), syntheticPropertyName);
}
}
use of org.hibernate.mapping.PersistentClass in project hibernate-orm by hibernate.
the class BinderHelper method findPropertiesByColumns.
private static List<Property> findPropertiesByColumns(Object columnOwner, Ejb3JoinColumn[] columns, MetadataBuildingContext context) {
Map<Column, Set<Property>> columnsToProperty = new HashMap<>();
List<Column> orderedColumns = new ArrayList<>(columns.length);
Table referencedTable;
if (columnOwner instanceof PersistentClass) {
referencedTable = ((PersistentClass) columnOwner).getTable();
} else if (columnOwner instanceof Join) {
referencedTable = ((Join) columnOwner).getTable();
} else {
throw new AssertionFailure(columnOwner == null ? "columnOwner is null" : "columnOwner neither PersistentClass nor Join: " + columnOwner.getClass());
}
// build the list of column names
for (Ejb3JoinColumn column1 : columns) {
Column column = new Column(context.getMetadataCollector().getPhysicalColumnName(referencedTable, column1.getReferencedColumn()));
orderedColumns.add(column);
columnsToProperty.put(column, new HashSet<>());
}
boolean isPersistentClass = columnOwner instanceof PersistentClass;
Iterator it = isPersistentClass ? ((PersistentClass) columnOwner).getPropertyIterator() : ((Join) columnOwner).getPropertyIterator();
while (it.hasNext()) {
matchColumnsByProperty((Property) it.next(), columnsToProperty);
}
if (isPersistentClass) {
matchColumnsByProperty(((PersistentClass) columnOwner).getIdentifierProperty(), columnsToProperty);
}
// first naive implementation
// only check 1 columns properties
// TODO make it smarter by checking correctly ordered multi column properties
List<Property> orderedProperties = new ArrayList<>();
for (Column column : orderedColumns) {
boolean found = false;
for (Property property : columnsToProperty.get(column)) {
if (property.getColumnSpan() == 1) {
orderedProperties.add(property);
found = true;
break;
}
}
if (!found) {
// have to find it the hard way
return null;
}
}
return orderedProperties;
}
Aggregations