Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#1436] Fix boot issue when model contains an association to an entity type that has an id class #1438

Merged
merged 1 commit into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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