HHH-15813 add @Imported annotation

This commit is contained in:
Gavin 2022-12-05 14:26:00 +01:00 committed by Gavin King
parent c29f2eaf60
commit 9526eb89b7
8 changed files with 93 additions and 35 deletions

View File

@ -0,0 +1,31 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Marks an arbitrary class as available for use in HQL queries by its unqualified name.
* <p>
* By default, non-entity class names must be fully-qualified in the query language.
*
* @author Gavin King
*
* @since 6.2
*/
@Target(TYPE)
@Retention(RUNTIME)
public @interface Imported {
/**
* Provide an alias for the class, to avoid collisions.
*/
String rename() default "";
}

View File

@ -27,6 +27,7 @@ import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.SessionFactory;
import org.hibernate.annotations.CollectionTypeRegistration;
import org.hibernate.annotations.Imported;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.boot.CacheRegionDefinition;
@ -808,12 +809,12 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
}
@Override
public void addImport(String importName, String entityName) {
if ( importName == null || entityName == null ) {
public void addImport(String importName, String className) {
if ( importName == null || className == null ) {
throw new IllegalArgumentException( "Import name or entity name is null" );
}
log.tracev( "Import: {0} -> {1}", importName, entityName );
String old = imports.put( importName, entityName );
log.tracev( "Import: {0} -> {1}", importName, className);
String old = imports.put( importName, className);
if ( old != null ) {
log.debugf( "import name [%s] overrode previous [{%s}]", importName, old );
}
@ -1185,23 +1186,29 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
@Override
public AnnotatedClassType addClassType(XClass clazz) {
AnnotatedClassType type;
if ( clazz.isAnnotationPresent( Entity.class ) ) {
type = AnnotatedClassType.ENTITY;
}
else if ( clazz.isAnnotationPresent( Embeddable.class ) ) {
type = AnnotatedClassType.EMBEDDABLE;
}
else if ( clazz.isAnnotationPresent( jakarta.persistence.MappedSuperclass.class ) ) {
type = AnnotatedClassType.MAPPED_SUPERCLASS;
}
else {
type = AnnotatedClassType.NONE;
}
final AnnotatedClassType type = getAnnotatedClassType(clazz);
annotatedClassTypeMap.put( clazz.getName(), type );
return type;
}
private static AnnotatedClassType getAnnotatedClassType(XClass clazz) {
if ( clazz.isAnnotationPresent( Entity.class ) ) {
return AnnotatedClassType.ENTITY;
}
else if ( clazz.isAnnotationPresent( Embeddable.class ) ) {
return AnnotatedClassType.EMBEDDABLE;
}
else if ( clazz.isAnnotationPresent( jakarta.persistence.MappedSuperclass.class ) ) {
return AnnotatedClassType.MAPPED_SUPERCLASS;
}
else if ( clazz.isAnnotationPresent( Imported.class ) ) {
return AnnotatedClassType.IMPORTED;
}
else {
return AnnotatedClassType.NONE;
}
}
@Override
public void addMappedSuperclass(Class type, MappedSuperclass mappedSuperclass) {

View File

@ -12,6 +12,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.annotations.Imported;
import org.hibernate.annotations.common.reflection.MetadataProviderInjector;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
@ -19,7 +20,6 @@ import org.hibernate.boot.AttributeConverterInfo;
import org.hibernate.boot.internal.MetadataBuildingContextRootImpl;
import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.model.convert.internal.AttributeConverterManager;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.process.spi.ManagedResources;
import org.hibernate.boot.model.source.spi.MetadataSourceProcessor;
@ -117,10 +117,9 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc
attributeConverterManager.addAttributeConverter( (Class<? extends AttributeConverter<?,?>>) annotatedClass );
}
else if ( xClass.isAnnotationPresent( Entity.class )
|| xClass.isAnnotationPresent( MappedSuperclass.class ) ) {
xClasses.add( xClass );
}
else if ( xClass.isAnnotationPresent( Embeddable.class ) ) {
|| xClass.isAnnotationPresent( MappedSuperclass.class )
|| xClass.isAnnotationPresent( Embeddable.class )
|| xClass.isAnnotationPresent( Imported.class ) ) {
xClasses.add( xClass );
}
else {

View File

@ -86,15 +86,15 @@ public interface InFlightMetadataCollector extends Mapping, MetadataImplementor
void registerComponent(Component component);
/**
* Adds an import (HQL entity rename).
* Adds an import (for use in HQL).
*
* @param entityName The entity name being renamed.
* @param rename The rename
* @param importName The name to be used in HQL
* @param className The fully-qualified name of the class
*
* @throws DuplicateMappingException If rename already is mapped to another
* @throws DuplicateMappingException If className already is mapped to another
* entity name in this repository.
*/
void addImport(String entityName, String rename) throws DuplicateMappingException;
void addImport(String importName, String className) throws DuplicateMappingException;
/**
* Add collection mapping metadata to this repository.

View File

@ -7,6 +7,8 @@
package org.hibernate.cfg;
import org.hibernate.annotations.Imported;
/**
* Type of annotation of a class will give its type
*
@ -17,6 +19,10 @@ public enum AnnotatedClassType {
* has no relevant top level annotation
*/
NONE,
/**
* has an {@link Imported} annotation
*/
IMPORTED,
/**
* has an {@link jakarta.persistence.Entity} annotation
*/

View File

@ -38,6 +38,7 @@ import org.hibernate.annotations.Formula;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.GenericGenerators;
import org.hibernate.annotations.IdGeneratorType;
import org.hibernate.annotations.Imported;
import org.hibernate.annotations.Index;
import org.hibernate.annotations.JavaTypeRegistration;
import org.hibernate.annotations.JavaTypeRegistrations;
@ -77,6 +78,7 @@ import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.GenericsHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Any;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Join;
@ -148,12 +150,12 @@ import static org.hibernate.cfg.BinderHelper.getPath;
import static org.hibernate.cfg.BinderHelper.getPropertyOverriddenByMapperOrMapsId;
import static org.hibernate.cfg.BinderHelper.getRelativePath;
import static org.hibernate.cfg.BinderHelper.hasToOneAnnotation;
import static org.hibernate.cfg.BinderHelper.isEmptyAnnotationValue;
import static org.hibernate.cfg.BinderHelper.makeIdGenerator;
import static org.hibernate.cfg.InheritanceState.getInheritanceStateOfSuperEntity;
import static org.hibernate.cfg.InheritanceState.getSuperclassInheritanceState;
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
import static org.hibernate.cfg.annotations.HCANNHelper.findContainingAnnotation;
import static org.hibernate.cfg.annotations.PropertyBinder.generatorCreator;
import static org.hibernate.cfg.annotations.PropertyBinder.identifierGeneratorCreator;
import static org.hibernate.internal.CoreLogging.messageLogger;
import static org.hibernate.mapping.Constraint.hashedName;
@ -517,6 +519,8 @@ public final class AnnotationBinder {
bindQueries( annotatedClass, context );
bindFilterDefs( annotatedClass, context );
//fall through:
case IMPORTED:
handleImport( annotatedClass, context );
case EMBEDDABLE:
case NONE:
return;
@ -535,6 +539,15 @@ public final class AnnotationBinder {
EntityBinder.bindEntityClass( annotatedClass, inheritanceStatePerClass, generators, context );
}
private static void handleImport(XClass annotatedClass, MetadataBuildingContext context) {
if ( annotatedClass.isAnnotationPresent(Imported.class) ) {
String qualifiedName = annotatedClass.getName();
String name = StringHelper.unqualify( qualifiedName );
String rename = annotatedClass.getAnnotation(Imported.class).rename();
context.getMetadataCollector().addImport( isEmptyAnnotationValue( rename ) ? name : rename, qualifiedName );
}
}
private static void detectMappedSuperclassProblems(XClass annotatedClass) {
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
if ( annotatedClass.isAnnotationPresent( Entity.class )

View File

@ -375,7 +375,7 @@ public class PropertyBinder {
property.setUpdateable( updatable );
property.setPropertyAccessStrategy( propertyAccessStrategy );
inferOptimisticLocking(property);
inferOptimisticLocking( property );
LOG.tracev( "Cascading {0} with {1}", name, cascade );
return property;

View File

@ -16,6 +16,7 @@ import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Imported;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.testing.TestForIssue;
@ -31,7 +32,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
@TestForIssue( jiraKey = "HHH-13619" )
@DomainModel( annotatedClasses = { ManyToManySizeTest.Company.class, ManyToManySizeTest.Customer.class } )
@DomainModel( annotatedClasses = { ManyToManySizeTest.Company.class, ManyToManySizeTest.Customer.class, ManyToManySizeTest.CompanyDto.class } )
@SessionFactory
public class ManyToManySizeTest {
@ -82,7 +83,7 @@ public class ManyToManySizeTest {
scope.inTransaction(
(session) -> {
final List results = session.createQuery(
"select new org.hibernate.orm.test.query.hql.size.ManyToManySizeTest$CompanyDto(" +
"select new ManyToManySizeTest$CompanyDto(" +
" c.id, c.name, size( c.customers ) )" +
" from Company c" +
" group by c.id, c.name" +
@ -111,7 +112,7 @@ public class ManyToManySizeTest {
scope.inTransaction(
(session) -> {
final List results = session.createQuery(
"select new org.hibernate.orm.test.query.hql.size.ManyToManySizeTest$CompanyDto(" +
"select new ManyToManySizeTest$CompanyDto(" +
" c.id, c.name, size( c.customers ) )" +
" from Company c left join c.customers cu" +
" group by c.id, c.name" +
@ -140,7 +141,7 @@ public class ManyToManySizeTest {
scope.inTransaction(
(session) -> {
final List results = session.createQuery(
"select new org.hibernate.orm.test.query.hql.size.ManyToManySizeTest$CompanyDto(" +
"select new ManyToManySizeTest$CompanyDto(" +
" c.id, c.name, size( c.customers ) )" +
" from Company c inner join c.customers cu" +
" group by c.id, c.name" +
@ -165,7 +166,7 @@ public class ManyToManySizeTest {
scope.inTransaction(
(session) -> {
final List results = session.createQuery(
"select new org.hibernate.orm.test.query.hql.size.ManyToManySizeTest$CompanyDto(" +
"select new ManyToManySizeTest$CompanyDto(" +
" c.id, c.name, size( cu ) )" +
" from Company c inner join c.customers cu" +
" group by c.id, c.name" +
@ -190,7 +191,7 @@ public class ManyToManySizeTest {
scope.inTransaction(
session -> {
final List results = session.createQuery(
"select new org.hibernate.orm.test.query.hql.size.ManyToManySizeTest$CompanyDto(" +
"select new ManyToManySizeTest$CompanyDto(" +
" c.id, c.name, size( c.customers ) )" +
" from Company c" +
" where c.id != 0" +
@ -335,6 +336,7 @@ public class ManyToManySizeTest {
}
}
@Imported
public static class CompanyDto {
public int id;