diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java index ba867dbca700..367fa0ed0dc9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java @@ -154,10 +154,7 @@ public ManagedDomainType managedType(String typeName) { return null; } final ManagedDomainType managedType = managedTypeByName.get( entityName ); - if ( !( managedType instanceof EntityDomainType entityDomainType ) ) { - return null; - } - return entityDomainType; + return managedType instanceof EntityDomainType entityDomainType ? entityDomainType : null; } @Override diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/Post.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/Post.java new file mode 100644 index 000000000000..b0bb73627155 --- /dev/null +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/Post.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.data.processingorder; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; + +@Entity +public class Post { + @Id + Integer id; + + String posterId; + + @ManyToOne + protected Topic topic; +} diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/PostRepository.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/PostRepository.java new file mode 100644 index 000000000000..80e50fb77262 --- /dev/null +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/PostRepository.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.data.processingorder; + +import jakarta.data.repository.DataRepository; +import jakarta.data.repository.Query; +import jakarta.data.repository.Repository; + +import java.util.List; + +@Repository +public interface PostRepository extends DataRepository { + + @Query("from Post p where p.topic=:topic") + List getPostsByTopic(Topic topic); +} diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/ProcessingOrderTest.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/ProcessingOrderTest.java new file mode 100644 index 000000000000..3bb6f8b93fca --- /dev/null +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/ProcessingOrderTest.java @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.data.processingorder; + +import org.hibernate.processor.test.util.CompilationTest; +import org.hibernate.processor.test.util.WithClasses; +import org.junit.Test; + +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.util.List; + +import static org.hibernate.processor.test.util.TestUtil.assertMetamodelClassGeneratedFor; +import static org.hibernate.processor.test.util.TestUtil.assertPresenceOfMethodInMetamodelFor; +import static org.hibernate.processor.test.util.TestUtil.getMethodFromMetamodelFor; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +public class ProcessingOrderTest extends CompilationTest { + @Test + @WithClasses({Post.class, PostRepository.class, Topic.class}) + public void test() { + assertMetamodelClassGeneratedFor( PostRepository.class ); + + assertPresenceOfMethodInMetamodelFor( PostRepository.class, "getPostsByTopic", Topic.class ); + final Method method = getMethodFromMetamodelFor( PostRepository.class, "getPostsByTopic", Topic.class ); + assertEquals( Topic.class, method.getParameterTypes()[0] ); + if ( method.getGenericReturnType() instanceof ParameterizedType parameterizedType ) { + assertEquals( List.class, parameterizedType.getRawType() ); + assertEquals( Post.class, parameterizedType.getActualTypeArguments()[0] ); + } + else { + fail(); + } + } +} diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/Topic.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/Topic.java new file mode 100644 index 000000000000..8db46cd10a5e --- /dev/null +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/processingorder/Topic.java @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.data.processingorder; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderBy; + +import java.util.List; + +@Entity +public class Topic { + @Id + Integer id; + + @OneToMany(mappedBy = "topic", targetEntity = Post.class) + @OrderBy + private List posts; + +} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java index e5ddf7fa215b..765530d53ddd 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java @@ -2723,11 +2723,12 @@ private boolean checkReturnedEntity(EntityDomainType model, TypeMirror return if ( returnType.getKind() == TypeKind.DECLARED ) { final DeclaredType declaredType = (DeclaredType) returnType; final TypeElement typeElement = (TypeElement) declaredType.asElement(); - final AnnotationMirror mirror = getAnnotationMirror(typeElement, ENTITY ); - if ( mirror != null ) { - final String entityName = entityName(declaredType, mirror); - return model.getHibernateEntityName().equals( entityName ); - } +// final AnnotationMirror mirror = getAnnotationMirror(typeElement, ENTITY ); +// if ( mirror != null ) { +// message( element, "entity return type '" + typeElement.getQualifiedName() +// + "' was not annotated '@Entity'", Diagnostic.Kind.WARNING ); +// } + return typeElement.getQualifiedName().contentEquals( model.getHibernateEntityName() ); } return false; } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java index 6a0fd9c0b77b..773ef2c325a1 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java @@ -122,7 +122,6 @@ import org.hibernate.type.descriptor.jdbc.ObjectJdbcType; import org.hibernate.type.spi.TypeConfiguration; -import javax.lang.model.element.TypeElement; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -281,16 +280,16 @@ static CollectionType createCollectionType(String role, String name) { */ abstract MockCollectionPersister createMockCollectionPersister(String role); - abstract boolean isEntityDefined(String entityName); + abstract boolean isEntityDefined(String jpaEntityName); - abstract TypeElement findEntityClass(String entityName); - - abstract String qualifyName(String entityName); + abstract String qualifyName(String jpaEntityName); abstract boolean isAttributeDefined(String entityName, String fieldName); abstract boolean isClassDefined(String qualifiedName); + protected abstract boolean isEntity(String entityName); + abstract boolean isEnum(String className); abstract boolean isEnumConstant(String className, String terminal); @@ -809,22 +808,16 @@ public MockJpaMetamodelImpl() { } @Override - public EntityDomainType entity(String entityName) { - if ( isEntityDefined(entityName) ) { - final TypeElement entityClass = findEntityClass( entityName ); - final String entityTypeName = entityClass == null ? entityName : entityClass.getQualifiedName().toString(); - return new MockEntityDomainType<>(entityName, new MockJavaType<>( entityTypeName )); + public @Nullable EntityDomainType findEntityType(@Nullable String jpaEntityName) { + final String entityTypeName = qualifyName(jpaEntityName); + if ( entityTypeName != null ) { + return new MockEntityDomainType<>(new MockJavaType<>(entityTypeName), jpaEntityName); } else { return null; } } - @Override - public @Nullable EntityDomainType findEntityType(@Nullable String entityName) { - return entity( entityName ); - } - @Override public String qualifyImportableName(String queryName) { if (isClassDefined(queryName)) { @@ -838,45 +831,22 @@ else if (isEntityDefined(queryName)) { } } - @Override - public ManagedDomainType managedType(String typeName) { - final ManagedDomainType managedType = findManagedType( typeName ); - if ( managedType == null ) { - throw new IllegalArgumentException("Not a managed type: " + typeName); - } - return managedType; - } - @Override public @Nullable ManagedDomainType findManagedType(@Nullable String typeName) { - final String entityName = qualifyName( typeName ); - //noinspection unchecked - return entityName == null ? null : (ManagedDomainType) findEntityType( entityName ); + // TODO: not every ManagedDomainType is an EntityDomainType! + return typeName == null ? null : new MockEntityDomainType<>(new MockJavaType<>(typeName)); } @Override public ManagedDomainType findManagedType(Class cls) { - throw new UnsupportedOperationException("operation not supported"); + return findManagedType( cls.getName() ); } @Override public EntityDomainType findEntityType(Class cls) { - if ( isEntityDefined( cls.getName() ) ) { - return new MockEntityDomainType<>( cls.getName(), new MockJavaType( cls.getName() )); - } - else { - return null; - } - } - - @Override - public ManagedDomainType managedType(Class cls) { - throw new UnsupportedOperationException("operation not supported"); - } - - @Override - public EntityDomainType entity(Class cls) { - throw new UnsupportedOperationException("operation not supported"); + return !cls.isArray() && !cls.isPrimitive() && isEntity(cls.getName()) + ? new MockEntityDomainType<>(new MockJavaType<>(cls.getName())) + : null; } @Override @@ -945,8 +915,13 @@ public PersistentAttribute findDeclaredAttribute(String name) { class MockEntityDomainType extends EntityTypeImpl { - public MockEntityDomainType(String entityName, JavaType javaType) { - super(entityName, entityName, false, true, false, javaType, null, + public MockEntityDomainType(JavaType javaType) { + this(javaType, getJpaEntityName(javaType.getTypeName())); + } + + public MockEntityDomainType(JavaType javaType, String jpaEntityName) { + super(javaType.getTypeName(), jpaEntityName, + false, true, false, javaType, null, metamodel.getJpaMetamodel()); } @@ -1027,10 +1002,14 @@ public SqmPathSource findSubPathSource(String name, boolean includeSubtypes) return (SqmPathSource) superattribute; } for (Map.Entry entry : entityPersistersByName.entrySet()) { - if (!entry.getValue().getEntityName().equals(getHibernateEntityName()) - && isSubtype(entry.getValue().getEntityName(), getHibernateEntityName())) { - final PersistentAttribute subattribute - = new MockEntityDomainType<>(entry.getValue().getEntityName(), new MockJavaType<>(entry.getValue().getEntityName()) ).findAttribute(name); + final MockEntityPersister entityPersister = entry.getValue(); + if (!entityPersister.getEntityName().equals(getHibernateEntityName()) + && isSubtype(entityPersister.getEntityName(), getHibernateEntityName())) { + final MockEntityDomainType entityDomainType = + new MockEntityDomainType<>(new MockJavaType<>(entityPersister.getEntityName()), + entityPersister.getJpaEntityName()); + final PersistentAttribute subattribute = + entityDomainType.findAttribute(name); if (subattribute != null) { return (SqmPathSource) subattribute; } @@ -1063,6 +1042,8 @@ public PersistentAttribute findDeclaredAttribute(String name) { } } + protected abstract String getJpaEntityName(String typeName); + private AbstractAttribute createAttribute(String name, String entityName, Type type, ManagedDomainType owner) { if (type==null) { throw new UnsupportedOperationException(entityName + "." + name); @@ -1076,7 +1057,7 @@ else if ( type.isEntityType() ) { owner, name, AttributeClassification.MANY_TO_ONE, - new MockEntityDomainType<>(type.getName(), new MockJavaType<>(type.getName())), + new MockEntityDomainType<>(new MockJavaType<>(type.getName())), null, null, false, @@ -1131,12 +1112,11 @@ private DomainType getMapKeyDomainType(String entityName, CollectionType coll return getDomainType(entityName, collectionType, owner, keyType); } - private DomainType getDomainType(String entityName, CollectionType collectionType, ManagedDomainType owner, Type elementType) { + private DomainType getDomainType( + String entityName, CollectionType collectionType, ManagedDomainType owner, Type elementType) { if ( elementType.isEntityType() ) { - final String associatedEntityName = collectionType.getAssociatedEntityName(MockSessionFactory.this); - final TypeElement associatedEntityEntityClass = findEntityClass( associatedEntityName ); - final String associatedEntityTypeName = associatedEntityEntityClass == null ? associatedEntityName : associatedEntityEntityClass.getQualifiedName().toString(); - return new MockEntityDomainType<>(associatedEntityName, new MockJavaType<>(associatedEntityTypeName)); + final String associatedEntityName = collectionType.getAssociatedEntityName(this); + return new MockEntityDomainType<>(new MockJavaType<>(associatedEntityName)); } else if ( elementType.isComponentType() ) { final CompositeType compositeType = (CompositeType) elementType; diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/ProcessorSessionFactory.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/ProcessorSessionFactory.java index 8d1842f59aac..fa733a79d68b 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/ProcessorSessionFactory.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/ProcessorSessionFactory.java @@ -380,7 +380,7 @@ public String getRootEntityName() { } superclass = typeElement.getSuperclass(); } - return ProcessorSessionFactory.getEntityName(result); + return getHibernateEntityName(result); } @Override @@ -476,13 +476,13 @@ Type getElementPropertyType(String propertyPath) { } @Override - boolean isEntityDefined(String entityName) { - return findEntityClass(entityName) != null; + boolean isEntityDefined(String jpaEntityName) { + return findEntityByUnqualifiedName(jpaEntityName) != null; } @Override - String qualifyName(String entityName) { - final TypeElement entityClass = findEntityClass(entityName); + String qualifyName(String jpaEntityName) { + final TypeElement entityClass = findEntityByUnqualifiedName(jpaEntityName); return entityClass == null ? null : entityClass.getQualifiedName().toString(); } @@ -493,17 +493,8 @@ boolean isAttributeDefined(String entityName, String fieldName) { && findPropertyByPath(entityClass, fieldName, getDefaultAccessType(entityClass)) != null; } - @Override public TypeElement findEntityClass(String entityName) { - if (entityName == null) { - return null; - } - else if (entityName.indexOf('.')>0) { - return findEntityByQualifiedName(entityName); - } - else { - return findEntityByUnqualifiedName(entityName); - } + return entityName == null ? null : findEntityByQualifiedName( entityName ); } private TypeElement findEntityByQualifiedName(String entityName) { @@ -587,7 +578,7 @@ private static boolean isMatchingEntity(Element symbol, String entityName) { if (symbol.getKind() == ElementKind.CLASS) { final TypeElement type = (TypeElement) symbol; return isEntity(type) - && getEntityName(type).equals(entityName); + && getJpaEntityName(type).equals(entityName); } else { return false; @@ -671,6 +662,11 @@ static boolean isMappedClass(TypeElement type) { || hasAnnotation(type, "MappedSuperclass"); } + @Override + protected boolean isEntity(String entityName) { + return isEntity(elementUtil.getTypeElement(entityName)); + } + static boolean isEntity(TypeElement member) { return member.getKind() == ElementKind.CLASS // && member.getAnnotation(entityAnnotation)!=null; @@ -873,7 +869,12 @@ private static AccessType getAccessType(TypeElement type, AccessType defaultAcce } } - static String getEntityName(TypeElement type) { + @Override + protected String getJpaEntityName(String typeName) { + return getJpaEntityName(findClassByQualifiedName(typeName)); + } + + static String getJpaEntityName(TypeElement type) { if ( type == null ) { return null; } @@ -886,11 +887,27 @@ static String getEntityName(TypeElement type) { else { final String name = (String) getAnnotationMember(entityAnnotation, "name"); - //entity names are unqualified class names + //JPA entity names are unqualified class names return name==null ? simpleName(type) : name; } } + static String getHibernateEntityName(TypeElement type) { + if ( type == null ) { + return null; + } + final AnnotationMirror entityAnnotation = + getAnnotation(type, "Entity"); + if (entityAnnotation==null) { + //not an entity! + return null; + } + else { + //entity names are qualified class names + return qualifiedName(type); + } + } + private TypeMirror getCollectionElementType(Element property) { final DeclaredType declaredType = (DeclaredType) memberType(property); final List typeArguments = declaredType.getTypeArguments(); @@ -910,8 +927,8 @@ private static String getToOneTargetEntity(Element property) { : classType; final Element element = asElement(targetType); return element != null && element.getKind() == ElementKind.CLASS - //entity names are unqualified class names - ? getEntityName((TypeElement) element) + //entity names are qualified class names + ? getHibernateEntityName((TypeElement) element) : null; } @@ -925,8 +942,8 @@ private String getToManyTargetEntityName(Element property) { : classType; final Element element = asElement(targetType); return element != null && element.getKind() == ElementKind.CLASS - //entity names are unqualified class names - ? getEntityName((TypeElement) element) + //entity names are qualified class names + ? getHibernateEntityName((TypeElement) element) : null; } @@ -997,8 +1014,7 @@ boolean isConstructorDefined(String qualifiedClassName, List argumentTypes else { final TypeElement typeClass; if ( type instanceof EntityType entityType ) { - final String entityName = entityType.getAssociatedEntityName(); - typeClass = findEntityClass(entityName); + typeClass = findEntityClass(entityType.getAssociatedEntityName()); } //TODO: // else if (type instanceof CompositeCustomType) { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/Validation.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/Validation.java index bbfc7b9f1f5f..3f83888723fb 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/Validation.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/Validation.java @@ -29,7 +29,7 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import static org.hibernate.processor.validation.ProcessorSessionFactory.getEntityName; +import static org.hibernate.processor.validation.ProcessorSessionFactory.getHibernateEntityName; import static org.hibernate.processor.validation.ProcessorSessionFactory.isEntity; @@ -109,7 +109,7 @@ private static SemanticQueryBuilder createSemanticQueryBuilder( final String typeName = typeElement.getQualifiedName().toString(); final String shortName = typeElement.getSimpleName().toString(); return isEntity( typeElement ) - ? new SemanticQueryBuilder<>( typeName, shortName, getEntityName(typeElement), CREATION_OPTIONS, factory, hql ) + ? new SemanticQueryBuilder<>( typeName, shortName, getHibernateEntityName(typeElement), CREATION_OPTIONS, factory, hql ) : new SemanticQueryBuilder<>( typeName, shortName, Object[].class, CREATION_OPTIONS, factory, hql ); } else {