Skip to content

Commit

Permalink
[Blazebit#1436] Fix boot issue when model contains an association to …
Browse files Browse the repository at this point in the history
…an entity type that has an id class
  • Loading branch information
beikov committed Jan 26, 2022
1 parent 4092ddc commit 0bcb21b
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 25 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ Not yet released

### New features

None yet
* Support Spring Boot/Data 2.6

### Bug fixes

None yet
* Fix issues in Quarkus integration preventing the use of the Hibernate 5.6 integration in native mode
* Fix boot issue when model contains an association to an entity type that has an id class

### Backwards-incompatible changes

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2014 - 2022 Blazebit.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.blazebit.persistence.testsuite;

import com.blazebit.persistence.parser.EntityMetamodel;
import com.blazebit.persistence.spi.ExtendedAttribute;
import com.blazebit.persistence.spi.ExtendedManagedType;
import org.junit.Test;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import java.io.Serializable;

import static org.junit.Assert.assertEquals;

/**
* @author Christian Beikov
* @since 1.6.6
*/
public class Issue1436Test extends AbstractCoreTest {

@Override
protected Class<?>[] getEntityClasses() {
return new Class<?>[]{ OrderItem.class, Item.class };
}

@Test
public void testBuild() {
ExtendedAttribute attribute = cbf.getService(EntityMetamodel.class)
.getManagedType(ExtendedManagedType.class, OrderItem.class)
.getAttribute("item.id1");
assertEquals(1, attribute.getColumnNames().length);
}

@Entity
public static class Item implements Serializable {
@Id
Long id1;
@Id
Long id2;

public Item() {
}
}

@Entity
public static class OrderItem implements Serializable {
@Id
Long id;
@Id
@ManyToOne
Item item;

public OrderItem() {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.blazebit.persistence.spi.JpaMetamodelAccessor;
import com.blazebit.persistence.spi.JpaProvider;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.engine.spi.CascadingAction;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.Mapping;
Expand All @@ -47,6 +48,7 @@
import org.hibernate.type.AssociationType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.CustomType;
import org.hibernate.type.EmbeddedComponentType;
import org.hibernate.type.ForeignKeyDirection;
Expand Down Expand Up @@ -522,7 +524,7 @@ public String[] getDiscriminatorColumnCheck(EntityType<?> entityType) {
@Override
public boolean isForeignJoinColumn(EntityType<?> ownerType, String attributeName) {
AbstractEntityPersister persister = getEntityPersister(ownerType);
Type propertyType = persister.getPropertyType(attributeName);
Type propertyType = getPropertyType(persister, attributeName);

if (propertyType instanceof org.hibernate.type.EntityType) {
org.hibernate.type.EntityType entityType = (org.hibernate.type.EntityType) propertyType;
Expand Down Expand Up @@ -579,7 +581,7 @@ public ConstraintType requiresTreatFilter(EntityType<?> ownerType, String attrib
return ConstraintType.WHERE;
}
AbstractEntityPersister persister = getEntityPersister(ownerType);
Type propertyType = persister.getPropertyType(attributeName);
Type propertyType = getPropertyType(persister, attributeName);

if (!(propertyType instanceof AssociationType)) {
return ConstraintType.NONE;
Expand Down Expand Up @@ -638,7 +640,7 @@ private boolean isColumnShared(AbstractEntityPersister subclassPersister, String
List<String> propertiesToCheck = new ArrayList<>(Arrays.asList(subclassPersister.getPropertyNames()));
while (!propertiesToCheck.isEmpty()) {
String propertyName = propertiesToCheck.remove(propertiesToCheck.size() - 1);
Type propertyType = subclassPersister.getPropertyType(propertyName);
Type propertyType = getPropertyType(subclassPersister, propertyName);
if (propertyType instanceof ComponentType) {
ComponentType componentType = (ComponentType) propertyType;
for (String subPropertyName : componentType.getPropertyNames()) {
Expand Down Expand Up @@ -666,8 +668,8 @@ public String getMappedBy(EntityType<?> ownerType, String attributeName) {
return "";
}
} else {
EntityPersister entityPersister = getEntityPersister(ownerType);
Type propertyType = entityPersister.getPropertyType(attributeName);
AbstractEntityPersister entityPersister = getEntityPersister(ownerType);
Type propertyType = getPropertyType(entityPersister, attributeName);
if (propertyType instanceof OneToOneType) {
return ((OneToOneType) propertyType).getRHSUniqueKeyPropertyName();
}
Expand Down Expand Up @@ -770,7 +772,7 @@ private Set<String> removeIdentifierAccess(EntityType<?> elementType, Set<String
List<String> addedAttributeNames = new ArrayList<>();
for (String attributeName : columnMatchingAttributeNames) {
String elementAttributeName = iterator.next();
Type propertyType = entityPersister.getPropertyType(attributeName);
Type propertyType = getPropertyType(entityPersister, attributeName);
if (propertyType instanceof org.hibernate.type.EntityType) {
// If the columns refer to an association, we map that through instead of trying to set just the identifier properties
if (elementPersister.getEntityName().equals(((org.hibernate.type.EntityType) propertyType).getAssociatedEntityName())) {
Expand Down Expand Up @@ -807,16 +809,54 @@ protected String getMappedBy(CollectionPersister persister) {
public String[] getColumnNames(EntityType<?> entityType, String attributeName) {
QueryableCollection collectionPersister = getCollectionPersister(entityType, attributeName);
if (collectionPersister == null) {
try {
return getEntityPersister(entityType).getPropertyColumnNames(attributeName);
} catch (MappingException e) {
throw new RuntimeException("Unknown property [" + attributeName + "] of entity [" + entityType.getJavaType() + "]", e);
}
return getColumnNames(getEntityPersister(entityType), attributeName);
} else {
return collectionPersister.getElementColumnNames();
}
}

public String[] getColumnNames(AbstractEntityPersister entityPersister, String attributeName) {
try {
return entityPersister.getPropertyColumnNames(attributeName);
} catch (MappingException e) {
// Workaround for HHH-15051
int dotIndex = attributeName.lastIndexOf('.');
if (dotIndex != -1) {
String attributePrefix = attributeName.substring(0, dotIndex);
Type propertyType = getPropertyType(entityPersister, attributePrefix);
if (propertyType instanceof org.hibernate.type.EntityType) {
String[] columnNames = getColumnNames(entityPersister, attributePrefix);
org.hibernate.type.EntityType hibernateEntityType = (org.hibernate.type.EntityType) propertyType;
Type idType = hibernateEntityType.getIdentifierOrUniqueKeyType(entityPersister.getFactory());
String attributeSubName = attributeName.substring(dotIndex + 1);
if (idType instanceof CompositeType && ((CompositeType) idType).isEmbedded()) {
CompositeType idClassType = (CompositeType) idType;
int columnSpan = 0;
int propertyIndex = -1;
String[] propertyNames = idClassType.getPropertyNames();
Type[] subtypes = idClassType.getSubtypes();
for (int i = 0; i < propertyNames.length; i++) {
if (propertyNames[i].equals(attributeSubName)) {
propertyIndex = i;
break;
}
columnSpan += subtypes[i].getColumnSpan(entityPersister.getFactory());
}

if (propertyIndex != -1) {
String[] actualColumns = new String[subtypes[propertyIndex].getColumnSpan(entityPersister.getFactory())];
System.arraycopy(columnNames, columnSpan, actualColumns, 0, actualColumns.length);
return actualColumns;
}
} else if (attributeSubName.equals(hibernateEntityType.getIdentifierOrUniqueKeyPropertyName(entityPersister.getFactory()))) {
return columnNames;
}
}
}
throw new RuntimeException("Unknown property [" + attributeName + "] of entity [" + entityPersister.getEntityName() + "]", e);
}
}

@Override
public String[] getColumnNames(EntityType<?> ownerType, String elementCollectionPath, String attributeName) {
QueryableCollection persister = getCollectionPersister(ownerType, elementCollectionPath);
Expand Down Expand Up @@ -891,7 +931,7 @@ private String[] columnNamesByPropertyName(AbstractEntityPersister persister, St
int offset = 0;
for (int i = 0; i < propertyNames.length; i++) {
String propertyName = propertyNames[i];
Type propertyType = persister.getPropertyType(prefix + propertyName);
Type propertyType = getPropertyType(persister, prefix + propertyName);
int span = propertyType.getColumnSpan(factory);
if (subAttributeName.equals(propertyName)) {
String[] columnNames = new String[span];
Expand Down Expand Up @@ -925,7 +965,7 @@ public String[] getColumnTypes(EntityType<?> entityType, String attributeName) {
if (collectionPersister == null) {
AbstractEntityPersister entityPersister = getEntityPersister(entityType);
SessionFactoryImplementor sfi = entityPersister.getFactory();
String[] columnNames = entityPersister.getPropertyColumnNames(attributeName);
String[] columnNames = getColumnNames(entityPersister, attributeName);
Database database = sfi.getServiceRegistry().locateServiceBinding(Database.class).getService();
Table[] tables;

Expand All @@ -951,7 +991,7 @@ public String[] getColumnTypes(EntityType<?> entityType, String attributeName) {
boolean isSubselect = tables.length == 1 && tables[0] == null;

if (isSubselect || isFormula(columnNames)) {
Type propertyType = entityPersister.getPropertyType(attributeName);
Type propertyType = getPropertyType(entityPersister, attributeName);
return getColumnTypeForPropertyType(entityType, attributeName, sfi, propertyType);
}

Expand Down Expand Up @@ -1163,7 +1203,7 @@ public JoinTable getJoinTable(EntityType<?> ownerType, String attributeName) {
String identifierOrUniqueKeyPropertyName = ((ManyToOneType) persister.getElementType()).getIdentifierOrUniqueKeyPropertyName(persister.getFactory());
String[] targetPrimaryKeyColumnMetaData = identifierOrUniqueKeyPropertyName == null ?
elementPersister.getKeyColumnNames() : // IdClass returns null for getIdentifierOrUniqueKeyPropertyName
elementPersister.getPropertyColumnNames(identifierOrUniqueKeyPropertyName);
getColumnNames(elementPersister, identifierOrUniqueKeyPropertyName);

Map<String, String> targetIdColumnMapping = new LinkedHashMap<>();

Expand Down Expand Up @@ -1198,7 +1238,7 @@ private JoinTable createJoinTable(EntityType<?> ownerType, QueryableCollection q
String[] propertyNames = ((EmbeddedComponentType) queryableCollection.getKeyType()).getPropertyNames();
List<String> columnNames = new ArrayList<>(propertyNames.length);
for (String propertyName : propertyNames) {
for (String propertyColumnName : ownerEntityPersister.getPropertyColumnNames(propertyName)) {
for (String propertyColumnName : getColumnNames(ownerEntityPersister, propertyName)) {
columnNames.add(propertyColumnName);
}
}
Expand Down Expand Up @@ -1411,7 +1451,7 @@ public boolean hasJoinCondition(ManagedType<?> owner, String elementCollectionPa

propertyType = componentType.getSubtypes()[componentType.getPropertyIndex(propertyParts[propertyParts.length - 1])];
} else {
propertyType = entityPersister.getPropertyType(attributeName);
propertyType = getPropertyType(entityPersister, attributeName);
}

if (propertyType instanceof CollectionType) {
Expand Down Expand Up @@ -1450,6 +1490,33 @@ public boolean hasJoinCondition(ManagedType<?> owner, String elementCollectionPa
return false;
}

private Type getPropertyType(AbstractEntityPersister entityPersister, String attributeName) {
try {
return entityPersister.getPropertyType(attributeName);
} catch (QueryException ex) {
// Workaround for HHH-15051
int dotIndex = attributeName.lastIndexOf('.');
if (dotIndex != -1) {
Type propertyType = getPropertyType(entityPersister, attributeName.substring(0, dotIndex));
if (propertyType instanceof org.hibernate.type.EntityType) {
org.hibernate.type.EntityType entityType = (org.hibernate.type.EntityType) propertyType;
Type idType = entityType.getIdentifierOrUniqueKeyType(entityPersister.getFactory());
String attributeSubName = attributeName.substring(dotIndex + 1);
if (idType instanceof CompositeType && ((CompositeType) idType).isEmbedded()) {
CompositeType idClassType = (CompositeType) idType;
int propertyIndex = Arrays.asList(idClassType.getPropertyNames()).indexOf(attributeSubName);
if (propertyIndex != -1) {
return idClassType.getSubtypes()[propertyIndex];
}
} else if (attributeSubName.equals(entityType.getIdentifierOrUniqueKeyPropertyName(entityPersister.getFactory()))) {
return idType;
}
}
}
throw ex;
}
}

@Override
public boolean containsEntity(EntityManager em, Class<?> entityClass, Object id) {
SessionImplementor session = em.unwrap(SessionImplementor.class);
Expand Down Expand Up @@ -1548,7 +1615,7 @@ public Map<String, String> getJoinMappingPropertyNames(EntityType<?> owner, Stri

propertyType = componentType.getSubtypes()[componentType.getPropertyIndex(propertyParts[propertyParts.length - 1])];
} else {
propertyType = entityPersister.getPropertyType(attributeName);
propertyType = getPropertyType(entityPersister, attributeName);
}

List<String> identifierOrUniqueKeyPropertyNames = new ArrayList<>();
Expand All @@ -1573,7 +1640,7 @@ public Map<String, String> getJoinMappingPropertyNames(EntityType<?> owner, Stri
}
} else {
AbstractEntityPersister elementPersister = (AbstractEntityPersister) entityPersisters.get(((org.hibernate.type.EntityType) elementType).getAssociatedEntityName());
collectPropertyNames(sourceIdentifierOrUniqueKeyPropertyNames, null, elementPersister.getPropertyType(mappedBy), factory);
collectPropertyNames(sourceIdentifierOrUniqueKeyPropertyNames, null, getPropertyType(elementPersister, mappedBy), factory);
// if (sourceIdentifierOrUniqueKeyPropertyNames.size() != identifierOrUniqueKeyPropertyNames.size()) {
// // We have a inverse map or inverse indexed list here
// // Maybe at some point we can determine the index property name mapping as well
Expand All @@ -1585,10 +1652,10 @@ public Map<String, String> getJoinMappingPropertyNames(EntityType<?> owner, Stri
} else {
AbstractEntityPersister elementPersister = (AbstractEntityPersister) entityPersisters.get(((org.hibernate.type.EntityType) elementType).getAssociatedEntityName());
for (String targetAttributeName : targetAttributeNames) {
collectPropertyNames(identifierOrUniqueKeyPropertyNames, targetAttributeName, elementPersister.getPropertyType(targetAttributeName), factory);
collectPropertyNames(identifierOrUniqueKeyPropertyNames, targetAttributeName, getPropertyType(elementPersister, targetAttributeName), factory);
}
for (String idAttributeName : joinTable.getIdAttributeNames()) {
collectPropertyNames(sourceIdentifierOrUniqueKeyPropertyNames, idAttributeName, entityPersister.getPropertyType(idAttributeName), factory);
collectPropertyNames(sourceIdentifierOrUniqueKeyPropertyNames, idAttributeName, getPropertyType(entityPersister, idAttributeName), factory);
}
}
}
Expand All @@ -1610,7 +1677,7 @@ public Map<String, String> getJoinMappingPropertyNames(EntityType<?> owner, Stri
if (mappedBy == null || mappedBy.isEmpty()) {
throw new IllegalArgumentException("One-to-one using natural key is unsupported!");
} else {
collectPropertyNames(sourceIdentifierOrUniqueKeyPropertyNames, null, elementPersister.getPropertyType(mappedBy), factory);
collectPropertyNames(sourceIdentifierOrUniqueKeyPropertyNames, null, getPropertyType(elementPersister, mappedBy), factory);
}
}
}
Expand Down Expand Up @@ -1658,7 +1725,7 @@ public boolean supportsEnumLiteral(ManagedType<?> ownerType, String attributeNam
if (ownerType instanceof EntityType<?>) {
AbstractEntityPersister entityPersister = getEntityPersister(ownerType);
Type propertyType;
propertyType = entityPersister.getPropertyType(attributeName);
propertyType = getPropertyType(entityPersister, attributeName);
if (propertyType instanceof CollectionType) {
CollectionPersister collectionPersister = entityPersister.getFactory().getCollectionPersister(((CollectionType) propertyType).getRole());
if (key) {
Expand Down

0 comments on commit 0bcb21b

Please sign in to comment.