From 43905c657f4e5bc7ec3575f96d617a7169c78694 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sat, 24 Feb 2024 09:34:01 +0100 Subject: [PATCH] some cleanup in static metamodel code --- .../annotation/AnnotationMetaAttribute.java | 11 +- .../annotation/AnnotationMetaEntity.java | 95 ++++---- .../annotation/BasicAttributeVisitor.java | 77 +++++++ .../MetaAttributeGenerationVisitor.java | 210 ++++++------------ .../hibernate/jpamodelgen/util/Constants.java | 1 + .../util/TypeRenderingVisitor.java | 4 +- .../hibernate/jpamodelgen/util/TypeUtils.java | 65 ++++-- .../validation/ProcessorSessionFactory.java | 3 +- 8 files changed, 251 insertions(+), 215 deletions(-) create mode 100644 tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/BasicAttributeVisitor.java diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java index 4141b9c4c2..8857306401 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java @@ -14,6 +14,7 @@ import javax.lang.model.util.Elements; import org.hibernate.jpamodelgen.model.MetaAttribute; import org.hibernate.jpamodelgen.model.Metamodel; +import static java.beans.Introspector.decapitalize; import static org.hibernate.jpamodelgen.util.StringUtil.getUpperUnderscoreCaseFromLowerCamelCase; /** @@ -82,19 +83,19 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute { @Override public String getPropertyName() { - Elements elementsUtil = parent.getContext().getElementUtils(); + final Elements elementsUtil = parent.getContext().getElementUtils(); if ( element.getKind() == ElementKind.FIELD ) { return element.getSimpleName().toString(); } else if ( element.getKind() == ElementKind.METHOD ) { - String name = element.getSimpleName().toString(); + final String name = element.getSimpleName().toString(); if ( name.startsWith( "get" ) ) { - return elementsUtil.getName( Introspector.decapitalize( name.substring( "get".length() ) ) ).toString(); + return elementsUtil.getName( decapitalize( name.substring( "get".length() ) ) ).toString(); } else if ( name.startsWith( "is" ) ) { - return ( elementsUtil.getName( Introspector.decapitalize( name.substring( "is".length() ) ) ) ).toString(); + return ( elementsUtil.getName( decapitalize( name.substring( "is".length() ) ) ) ).toString(); } - return elementsUtil.getName( Introspector.decapitalize( name ) ).toString(); + return elementsUtil.getName( decapitalize( name ) ).toString(); } else { return elementsUtil.getName( element.getSimpleName() + "/* " + element.getKind() + " */" ).toString(); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java index 4cc666b741..ee7397545e 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java @@ -90,6 +90,7 @@ import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationMirror; import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationValue; import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationValueRef; import static org.hibernate.jpamodelgen.util.TypeUtils.hasAnnotation; +import static org.hibernate.jpamodelgen.util.TypeUtils.primitiveClassMatchesKind; /** * Class used to collect meta information about an annotated type (entity, embeddable or mapped superclass). @@ -1141,43 +1142,46 @@ public class AnnotationMetaEntity extends AnnotationMeta { StringTokenizer tokens, String token) { final Name memberName = candidate.getSimpleName(); - final TypeMirror type; - if ( accessType == AccessType.FIELD && candidate.getKind() == ElementKind.FIELD ) { - if ( !fieldMatches(token, memberName) ) { - return null; - } - else { - type = candidate.asType(); - } - } - else if ( accessType == AccessType.PROPERTY && candidate.getKind() == ElementKind.METHOD ) { - if ( !getterMatches(token, memberName) ) { - return null; - } - else { - final ExecutableElement method = (ExecutableElement) candidate; - type = method.getReturnType(); - } - } - else { + final TypeMirror type = memberType( candidate, accessType, token, memberName ); + if (type == null) { return null; } - - if ( tokens.hasMoreTokens() ) { - if ( type.getKind() == TypeKind.DECLARED ) { - final DeclaredType declaredType = (DeclaredType) type; - final TypeElement memberType = (TypeElement) declaredType.asElement(); - memberTypes.put( qualify( entityType.getQualifiedName().toString(), memberName.toString() ), - memberType.getQualifiedName().toString() ); - return memberMatchingPath( memberType, tokens ); - } - return null; + else if ( tokens.hasMoreTokens() ) { + return type.getKind() == TypeKind.DECLARED + ? memberForPath( entityType, tokens, (DeclaredType) type, memberName ) + : null; } else { return candidate; } } + private @Nullable Element memberForPath( + TypeElement entityType, StringTokenizer tokens, DeclaredType type, Name memberName) { + final TypeElement memberType = (TypeElement) type.asElement(); + memberTypes.put( qualify( entityType.getQualifiedName().toString(), memberName.toString() ), + memberType.getQualifiedName().toString() ); // NOTE SIDE EFFECT! + return memberMatchingPath( memberType, tokens ); + } + + private static @Nullable TypeMirror memberType(Element candidate, AccessType accessType, String token, Name memberName) { + final ElementKind kind = candidate.getKind(); + if ( accessType == AccessType.FIELD && kind == ElementKind.FIELD ) { + return fieldMatches(token, memberName) + ? candidate.asType() + : null; + } + else if ( accessType == AccessType.PROPERTY && kind == ElementKind.METHOD ) { + final ExecutableElement executable = (ExecutableElement) candidate; + return getterMatches(token, memberName) + ? executable.getReturnType() + : null; + } + else { + return null; + } + } + private static boolean fieldMatches(String token, Name fieldName) { return fieldName.contentEquals( token ); } @@ -1464,30 +1468,12 @@ public class AnnotationMetaEntity extends AnnotationMeta { return paramTypeElement.getQualifiedName().contentEquals(itemTypeName); } else if ( kind.isPrimitive() ) { - switch ( kind ) { - case SHORT: - return itemType.equals(Short.class); - case INT: - return itemType.equals(Integer.class); - case LONG: - return itemType.equals(Long.class); - case BOOLEAN: - return itemType.equals(Boolean.class); - case FLOAT: - return itemType.equals(Float.class); - case DOUBLE: - return itemType.equals(Double.class); - case CHAR: - return itemType.equals(Character.class); - case BYTE: - return itemType.equals(Byte.class); - default: - return false; - } + return primitiveClassMatchesKind( itemType, kind ); } else if ( kind == TypeKind.ARRAY ) { + final ArrayType arrayType = (ArrayType) parameterType; return itemType.isArray() - && parameterMatches( ((ArrayType) parameterType).getComponentType(), itemType.getComponentType() ); + && parameterMatches( arrayType.getComponentType(), itemType.getComponentType() ); } else { return false; @@ -1499,7 +1485,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { if ( componentType.getKind() == TypeKind.DECLARED ) { final DeclaredType declaredType = (DeclaredType) componentType; final TypeElement typeElement = (TypeElement) declaredType.asElement(); - return typeElement.getQualifiedName().contentEquals("java.lang.Object"); + return typeElement.getQualifiedName().contentEquals(Constants.JAVA_OBJECT); } else { return false; @@ -1696,12 +1682,17 @@ public class AnnotationMetaEntity extends AnnotationMeta { } private static boolean parameterIsMissing(String hql, int i, String param, String type) { - return !Pattern.compile( ".*(:" + param + "|\\?" + i + ")\\b.*", Pattern.DOTALL ).matcher( hql ).matches() + return !hasParameter(hql, i, param) && !isSessionParameter(type) && !isPageParam(type) && !isOrderParam(type); } + private static boolean hasParameter(String hql, int i, String param) { + return Pattern.compile(".*(:" + param + "|\\?" + i + ")\\b.*", Pattern.DOTALL) + .matcher(hql).matches(); + } + private static boolean isSessionParameter(String type) { return SESSION_TYPES.contains(type); } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/BasicAttributeVisitor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/BasicAttributeVisitor.java new file mode 100644 index 0000000000..fe5630ad2e --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/BasicAttributeVisitor.java @@ -0,0 +1,77 @@ +/* + * 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 . + */ +package org.hibernate.jpamodelgen.annotation; + +import org.hibernate.jpamodelgen.Context; +import org.hibernate.jpamodelgen.util.Constants; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.SimpleTypeVisitor8; +import java.io.Serializable; + +import static org.hibernate.jpamodelgen.util.Constants.BASIC_ARRAY_TYPES; +import static org.hibernate.jpamodelgen.util.Constants.BASIC_TYPES; +import static org.hibernate.jpamodelgen.util.TypeUtils.hasAnnotation; +import static org.hibernate.jpamodelgen.util.TypeUtils.isClassOrRecordType; + +/** + * Checks whether the visited type is a basic attribute according to the JPA 2 spec + * ( section 2.8 Mapping Defaults for Non-Relationship Fields or Properties) + */ +class BasicAttributeVisitor extends SimpleTypeVisitor8 { + + private final Context context; + + public BasicAttributeVisitor(Context context) { + super(false); + this.context = context; + } + + @Override + public Boolean visitPrimitive(PrimitiveType primitiveType, Element element) { + return true; + } + + @Override + public Boolean visitArray(ArrayType arrayType, Element element) { + final TypeElement componentElement = (TypeElement) + context.getTypeUtils().asElement( arrayType.getComponentType() ); + return BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() ); + } + + @Override + public Boolean visitDeclared(DeclaredType declaredType, Element element) { + final ElementKind kind = element.getKind(); + if ( kind == ElementKind.ENUM ) { + return true; + } + else if ( isClassOrRecordType(element) || kind == ElementKind.INTERFACE ) { + final TypeElement typeElement = (TypeElement) element; + return BASIC_TYPES.contains( typeElement.getQualifiedName().toString() ) + || hasAnnotation( element, Constants.EMBEDDABLE ) + || isSerializable( typeElement ); + } + else { + return false; + } + } + + private boolean isSerializable(TypeElement typeElement) { + final TypeMirror serializableType = + context.getElementUtils() + .getTypeElement(Serializable.class.getName()) + .asType(); + return context.getTypeUtils() + .isSubtype( typeElement.asType(), serializableType ); + } +} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/MetaAttributeGenerationVisitor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/MetaAttributeGenerationVisitor.java index 49307a1bb1..516c938ed9 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/MetaAttributeGenerationVisitor.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/MetaAttributeGenerationVisitor.java @@ -19,19 +19,29 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeVariable; import javax.lang.model.util.SimpleTypeVisitor8; +import javax.lang.model.util.Types; import javax.tools.Diagnostic; import org.hibernate.jpamodelgen.Context; +import org.hibernate.jpamodelgen.util.AccessType; import org.hibernate.jpamodelgen.util.AccessTypeInformation; import org.hibernate.jpamodelgen.util.Constants; import org.checkerframework.checker.nullness.qual.Nullable; -import static org.hibernate.jpamodelgen.util.TypeUtils.isClassOrRecordType; +import static org.hibernate.jpamodelgen.util.Constants.BASIC; +import static org.hibernate.jpamodelgen.util.Constants.ELEMENT_COLLECTION; +import static org.hibernate.jpamodelgen.util.Constants.EMBEDDED_ID; +import static org.hibernate.jpamodelgen.util.Constants.ID; +import static org.hibernate.jpamodelgen.util.Constants.MANY_TO_ANY; +import static org.hibernate.jpamodelgen.util.Constants.MANY_TO_MANY; +import static org.hibernate.jpamodelgen.util.Constants.MANY_TO_ONE; +import static org.hibernate.jpamodelgen.util.Constants.ONE_TO_MANY; +import static org.hibernate.jpamodelgen.util.Constants.ONE_TO_ONE; +import static org.hibernate.jpamodelgen.util.TypeUtils.hasAnnotation; import static org.hibernate.jpamodelgen.util.NullnessUtil.castNonNull; import static org.hibernate.jpamodelgen.util.StringUtil.isProperty; import static org.hibernate.jpamodelgen.util.TypeUtils.DEFAULT_ANNOTATION_PARAMETER_NAME; -import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation; import static org.hibernate.jpamodelgen.util.TypeUtils.determineAnnotationSpecifiedAccessType; import static org.hibernate.jpamodelgen.util.TypeUtils.extractClosestRealTypeAsString; import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationMirror; @@ -67,49 +77,36 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor8<@Nullable this.context = context; } - @Override - public @Nullable AnnotationMetaAttribute visitPrimitive(PrimitiveType t, Element element) { - return new AnnotationMetaSingleAttribute( entity, element, toTypeString( t ) ); + private Types typeUtils() { + return context.getTypeUtils(); } @Override - public @Nullable AnnotationMetaAttribute visitArray(ArrayType t, Element element) { - // METAGEN-2 - For now we handle arrays as SingularAttribute - // The code below is an attempt to be closer to the spec and only allow byte[], Byte[], char[] and Character[] -// AnnotationMetaSingleAttribute attribute = null; -// TypeMirror componentMirror = t.getComponentType(); -// if ( TypeKind.CHAR.equals( componentMirror.getKind() ) -// || TypeKind.BYTE.equals( componentMirror.getKind() ) ) { -// attribute = new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toTypeString( t ) ); -// } -// else if ( TypeKind.DECLARED.equals( componentMirror.getKind() ) ) { -// TypeElement componentElement = ( TypeElement ) context.getProcessingEnvironment() -// .getTypeUtils() -// .asElement( componentMirror ); -// if ( BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() ) ) { -// attribute = new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toTypeString( t ) ); -// } -// } -// return attribute; - return new AnnotationMetaSingleAttribute( entity, element, toArrayTypeString( t, context ) ); + public @Nullable AnnotationMetaAttribute visitPrimitive(PrimitiveType primitiveType, Element element) { + return new AnnotationMetaSingleAttribute( entity, element, toTypeString( primitiveType ) ); } @Override - public @Nullable AnnotationMetaAttribute visitTypeVariable(TypeVariable t, Element element) { + public @Nullable AnnotationMetaAttribute visitArray(ArrayType arrayType, Element element) { + return new AnnotationMetaSingleAttribute( entity, element, toArrayTypeString( arrayType, context ) ); + } + + @Override + public @Nullable AnnotationMetaAttribute visitTypeVariable(TypeVariable typeVariable, Element element) { // METAGEN-29 - for a type variable we use the upper bound - final TypeMirror erasedType = context.getTypeUtils().erasure( t.getUpperBound() ); - return new AnnotationMetaSingleAttribute( entity, element, erasedType.toString() ); + return new AnnotationMetaSingleAttribute( entity, element, + typeUtils().erasure( typeVariable.getUpperBound() ).toString() ); } @Override public @Nullable AnnotationMetaAttribute visitDeclared(DeclaredType declaredType, Element element) { - final TypeElement returnedElement = (TypeElement) context.getTypeUtils().asElement( declaredType ); + final TypeElement returnedElement = (TypeElement) typeUtils().asElement( declaredType ); // WARNING: .toString() is necessary here since Name equals does not compare to String - final String fqNameOfReturnType = returnedElement.getQualifiedName().toString(); - final String collection = Constants.COLLECTIONS.get( fqNameOfReturnType ); + final String returnTypeName = returnedElement.getQualifiedName().toString(); + final String collection = Constants.COLLECTIONS.get( returnTypeName ); final String targetEntity = getTargetEntity( element.getAnnotationMirrors() ); if ( collection != null ) { - return createMetaCollectionAttribute( declaredType, element, fqNameOfReturnType, collection, targetEntity ); + return createMetaCollectionAttribute( declaredType, element, returnTypeName, collection, targetEntity ); } else if ( isBasicAttribute( element, returnedElement ) ) { final String type = targetEntity != null ? targetEntity : returnedElement.getQualifiedName().toString(); @@ -121,15 +118,14 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor8<@Nullable } private AnnotationMetaAttribute createMetaCollectionAttribute( - DeclaredType declaredType, Element element, String fqNameOfReturnType, String collection, + DeclaredType declaredType, Element element, String returnTypeName, String collection, @Nullable String targetEntity) { - if ( containsAnnotation( element, Constants.ELEMENT_COLLECTION ) ) { + if ( hasAnnotation( element, ELEMENT_COLLECTION ) ) { final String explicitTargetEntity = getTargetEntity( element.getAnnotationMirrors() ); final TypeMirror collectionElementType = - getCollectionElementType( declaredType, fqNameOfReturnType, explicitTargetEntity, context ); + getCollectionElementType( declaredType, returnTypeName, explicitTargetEntity, context ); if ( collectionElementType.getKind() == TypeKind.DECLARED ) { - final TypeElement collectionElement = (TypeElement) - context.getTypeUtils().asElement( collectionElementType ); + final TypeElement collectionElement = (TypeElement) typeUtils().asElement( collectionElementType ); setAccessType( collectionElementType, collectionElement ); } } @@ -138,74 +134,59 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor8<@Nullable private AnnotationMetaAttribute createMetaAttribute( DeclaredType declaredType, Element element, String collection, @Nullable String targetEntity) { - if ( containsAnnotation( element, - Constants.ONE_TO_MANY, Constants.MANY_TO_MANY, - Constants.MANY_TO_ANY, Constants.ELEMENT_COLLECTION ) ) { + if ( hasAnnotation( element, ONE_TO_MANY, MANY_TO_MANY, MANY_TO_ANY, ELEMENT_COLLECTION ) ) { + final String elementType = getElementType( declaredType, targetEntity ); if ( collection.equals( Constants.MAP_ATTRIBUTE ) ) { //TODO: pretty fragile! - return new AnnotationMetaMap( - entity, - element, - collection, - getMapKeyType( declaredType, element ), - getElementType( declaredType, targetEntity ) - ); + final String keyType = getMapKeyType( declaredType, element ); + return new AnnotationMetaMap( entity, element, collection, keyType, elementType ); } else { - return new AnnotationMetaCollection( - entity, - element, - collection, - getElementType( declaredType, targetEntity ) - ); + return new AnnotationMetaCollection( entity, element, collection, elementType ); } } else { - final String typeWithVariablesErased = extractClosestRealTypeAsString( declaredType, context ); - return new AnnotationMetaSingleAttribute( entity, element, typeWithVariablesErased ); + return new AnnotationMetaSingleAttribute( entity, element, + extractClosestRealTypeAsString( declaredType, context ) ); } } private void setAccessType(TypeMirror collectionElementType, TypeElement collectionElement) { - final AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( collectionElementType.toString() ); + final String elementTypeName = collectionElementType.toString(); + final AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( elementTypeName ); + final AccessType entityAccessType = entity.getEntityAccessTypeInfo().getAccessType(); if ( accessTypeInfo == null ) { - final AccessTypeInformation newAccessTypeInfo = new AccessTypeInformation( - collectionElementType.toString(), - collectionElement == null ? null : determineAnnotationSpecifiedAccessType( collectionElement ), - entity.getEntityAccessTypeInfo().getAccessType() + context.addAccessTypeInformation( + elementTypeName, + new AccessTypeInformation( + elementTypeName, + collectionElement == null ? null + : determineAnnotationSpecifiedAccessType( collectionElement ), + entityAccessType + ) ); - context.addAccessTypeInformation( collectionElementType.toString(), newAccessTypeInfo ); } else { - accessTypeInfo.setDefaultAccessType( entity.getEntityAccessTypeInfo().getAccessType() ); + accessTypeInfo.setDefaultAccessType( entityAccessType ); } } @Override - public @Nullable AnnotationMetaAttribute visitExecutable(ExecutableType t, Element p) { - if ( p.getKind() == ElementKind.METHOD - && isProperty( p.getSimpleName().toString(), toTypeString( t.getReturnType() ) ) ) { - return t.getReturnType().accept( this, p ); - } - else { - return null; - } + public @Nullable AnnotationMetaAttribute visitExecutable(ExecutableType executable, Element element) { + return isPropertyGetter( executable, element ) + ? executable.getReturnType().accept(this, element) + : null; + } + + private static boolean isPropertyGetter(ExecutableType executable, Element element) { + return element.getKind() == ElementKind.METHOD + && isProperty( element.getSimpleName().toString(), + toTypeString( executable.getReturnType() ) ); } private boolean isBasicAttribute(Element element, Element returnedElement) { - if ( containsAnnotation( element, Constants.BASIC ) - || containsAnnotation( element, Constants.ONE_TO_ONE ) - || containsAnnotation( element, Constants.MANY_TO_ONE ) - || containsAnnotation( element, Constants.EMBEDDED_ID ) - || containsAnnotation( element, Constants.ID ) ) { - return true; - } - - // METAGEN-28 - if ( getAnnotationMirror( element, ORG_HIBERNATE_ANNOTATIONS_TYPE ) != null ) { - return true; - } - - return returnedElement.asType().accept( new BasicAttributeVisitor( context ), returnedElement ); + return hasAnnotation( element, BASIC, ONE_TO_ONE, MANY_TO_ONE, EMBEDDED_ID, ID ) + || hasAnnotation( element, ORG_HIBERNATE_ANNOTATIONS_TYPE ) // METAGEN-28 + || returnedElement.asType().accept( new BasicAttributeVisitor( context ), returnedElement ); } private String getMapKeyType(DeclaredType declaredType, Element element) { @@ -245,13 +226,13 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor8<@Nullable */ private @Nullable String getTargetEntity(List annotations) { for ( AnnotationMirror mirror : annotations ) { - if ( isAnnotationMirrorOfType( mirror, Constants.ELEMENT_COLLECTION ) ) { + if ( isAnnotationMirrorOfType( mirror, ELEMENT_COLLECTION ) ) { return getFullyQualifiedClassNameOfTargetEntity( mirror, "targetClass" ); } - else if ( isAnnotationMirrorOfType( mirror, Constants.ONE_TO_MANY ) - || isAnnotationMirrorOfType( mirror, Constants.MANY_TO_MANY ) - || isAnnotationMirrorOfType( mirror, Constants.MANY_TO_ONE ) - || isAnnotationMirrorOfType( mirror, Constants.ONE_TO_ONE ) ) { + else if ( isAnnotationMirrorOfType( mirror, ONE_TO_MANY ) + || isAnnotationMirrorOfType( mirror, MANY_TO_MANY ) + || isAnnotationMirrorOfType( mirror, MANY_TO_ONE ) + || isAnnotationMirrorOfType( mirror, ONE_TO_ONE ) ) { return getFullyQualifiedClassNameOfTargetEntity( mirror, "targetEntity" ); } else if ( isAnnotationMirrorOfType( mirror, ORG_HIBERNATE_ANNOTATIONS_TARGET ) ) { @@ -276,56 +257,3 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor8<@Nullable } } -/** - * Checks whether the visited type is a basic attribute according to the JPA 2 spec - * ( section 2.8 Mapping Defaults for Non-Relationship Fields or Properties) - */ -class BasicAttributeVisitor extends SimpleTypeVisitor8 { - - private final Context context; - - public BasicAttributeVisitor(Context context) { - super( false ); - this.context = context; - } - - @Override - public Boolean visitPrimitive(PrimitiveType primitiveType, Element element) { - return true; - } - - @Override - public Boolean visitArray(ArrayType arrayType, Element element) { - final TypeElement componentElement = (TypeElement) - context.getTypeUtils().asElement( arrayType.getComponentType() ); - return Constants.BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() ); - } - - @Override - public Boolean visitDeclared(DeclaredType declaredType, Element element) { - if ( ElementKind.ENUM.equals( element.getKind() ) ) { - return true; - } - - if ( isClassOrRecordType( element ) - || element.getKind() == ElementKind.INTERFACE ) { - final TypeElement typeElement = (TypeElement) element; - final String typeName = typeElement.getQualifiedName().toString(); - if ( Constants.BASIC_TYPES.contains( typeName ) ) { - return true; - } - if ( containsAnnotation( element, Constants.EMBEDDABLE ) ) { - return true; - } - final TypeMirror serializableType = - context.getElementUtils() - .getTypeElement(java.io.Serializable.class.getName()) - .asType(); - if ( context.getTypeUtils().isSubtype( typeElement.asType(), serializableType) ) { - return true; - } - } - - return false; - } -} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java index 204b2701a9..a80e56ba39 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java @@ -93,6 +93,7 @@ public final class Constants { public static final String LIST_ATTRIBUTE = "jakarta.persistence.metamodel.ListAttribute"; public static final String MAP_ATTRIBUTE = "jakarta.persistence.metamodel.MapAttribute"; + public static final String JAVA_OBJECT = Object.class.getName(); public static final String COLLECTION = java.util.Collection.class.getName(); public static final String LIST = java.util.List.class.getName(); public static final String MAP = java.util.Map.class.getName(); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java index 632dcc4fe9..0ff9a2db83 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java @@ -28,6 +28,8 @@ import javax.lang.model.util.SimpleTypeVisitor8; import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.jpamodelgen.util.Constants.JAVA_OBJECT; + /** * @author Christian Beikov */ @@ -134,7 +136,7 @@ public final class TypeRenderingVisitor extends SimpleTypeVisitor8<@Nullable Obj if ( typeVariableElement instanceof TypeParameterElement ) { final TypeParameterElement typeParameter = (TypeParameterElement) typeVariableElement; sb.append( typeParameter ); - if ( !"java.lang.Object".equals( t.getUpperBound().toString() ) && visitedTypeVariables.add( t ) ) { + if ( !JAVA_OBJECT.equals( t.getUpperBound().toString() ) && visitedTypeVariables.add( t ) ) { sb.append( " extends " ); t.getUpperBound().accept( this, null ); visitedTypeVariables.remove( t ); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java index 0de22ab211..cfbda3bf4f 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java @@ -17,6 +17,7 @@ import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.ArrayType; @@ -35,6 +36,7 @@ import org.hibernate.jpamodelgen.MetaModelGenerationException; import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.jpamodelgen.util.Constants.JAVA_OBJECT; import static org.hibernate.jpamodelgen.util.NullnessUtil.castNonNull; import static org.hibernate.jpamodelgen.util.StringUtil.isProperty; @@ -51,6 +53,9 @@ public final class TypeUtils { private static final Map PRIMITIVE_WRAPPERS = new HashMap<>(); private static final Map PRIMITIVES = new HashMap<>(); + private static final String PROPERTY = AccessType.PROPERTY.toString(); + private static final String FIELD = AccessType.FIELD.toString(); + static { PRIMITIVE_WRAPPERS.put( TypeKind.CHAR, "Character" ); @@ -131,7 +136,13 @@ public final class TypeUtils { } private static @Nullable TypeMirror upperBound(@Nullable TypeMirror bound) { - return bound == null || (bound.getKind() == TypeKind.DECLARED && bound.toString().equals("java.lang.Object")) ? null : bound; + if ( bound !=null && bound.getKind() == TypeKind.DECLARED ) { + final DeclaredType type = (DeclaredType) bound; + return type.asElement().getSimpleName().contentEquals(JAVA_OBJECT) ? null : bound; + } + else { + return null; + } } public static @Nullable TypeMirror extractClosestRealType(TypeMirror type, Context context, Set beingVisited) { @@ -316,20 +327,20 @@ public final class TypeUtils { } public static TypeMirror getCollectionElementType( - DeclaredType t, String fqNameOfReturnedType, @Nullable String explicitTargetEntityName, Context context) { + DeclaredType type, String returnTupeName, @Nullable String explicitTargetEntityName, Context context) { if ( explicitTargetEntityName != null ) { return context.getElementUtils().getTypeElement( explicitTargetEntityName ).asType(); } else { - final List typeArguments = t.getTypeArguments(); - if ( typeArguments.size() == 0 ) { + final List typeArguments = type.getTypeArguments(); + if ( typeArguments.isEmpty() ) { throw new MetaModelGenerationException( "Unable to determine collection type" ); } - else if ( Map.class.getCanonicalName().equals( fqNameOfReturnedType ) ) { - return t.getTypeArguments().get( 1 ); + else if ( Map.class.getCanonicalName().equals( returnTupeName ) ) { + return typeArguments.get( 1 ); } else { - return t.getTypeArguments().get( 0 ); + return typeArguments.get( 0 ); } } } @@ -460,10 +471,11 @@ public final class TypeUtils { final Object accessType = getAnnotationValue( mirror, DEFAULT_ANNOTATION_PARAMETER_NAME ); if ( accessType instanceof VariableElement) { final VariableElement enumValue = (VariableElement) accessType; - if ( enumValue.getSimpleName().contentEquals( AccessType.PROPERTY.toString() ) ) { + final Name enumValueName = enumValue.getSimpleName(); + if ( enumValueName.contentEquals(PROPERTY) ) { return AccessType.PROPERTY; } - else if ( enumValue.getSimpleName().contentEquals( AccessType.FIELD.toString() ) ) { + else if ( enumValueName.contentEquals(FIELD) ) { return AccessType.FIELD; } } @@ -479,7 +491,7 @@ public final class TypeUtils { final List typeArguments = type.getTypeArguments(); if ( typeArguments.isEmpty() ) { context.logMessage( Diagnostic.Kind.ERROR, "Unable to determine type argument for " + type ); - return "java.lang.Object"; + return JAVA_OBJECT; } else { return extractClosestRealTypeAsString( typeArguments.get( 0 ), context ); @@ -493,6 +505,29 @@ public final class TypeUtils { return kind.isClass() && kind != ElementKind.ENUM; } + public static boolean primitiveClassMatchesKind(Class itemType, TypeKind kind) { + switch (kind) { + case SHORT: + return itemType.equals(Short.class); + case INT: + return itemType.equals(Integer.class); + case LONG: + return itemType.equals(Long.class); + case BOOLEAN: + return itemType.equals(Boolean.class); + case FLOAT: + return itemType.equals(Float.class); + case DOUBLE: + return itemType.equals(Double.class); + case CHAR: + return itemType.equals(Character.class); + case BYTE: + return itemType.equals(Byte.class); + default: + return false; + } + } + static class EmbeddedAttributeVisitor extends SimpleTypeVisitor8<@Nullable String, Element> { private final Context context; @@ -510,11 +545,11 @@ public final class TypeUtils { } @Override - public @Nullable String visitExecutable(ExecutableType t, Element p) { - if ( p.getKind().equals( ElementKind.METHOD ) ) { - String string = p.getSimpleName().toString(); - return isProperty( string, toTypeString( t.getReturnType() ) ) - ? t.getReturnType().accept(this, p) + public @Nullable String visitExecutable(ExecutableType executable, Element element) { + if ( element.getKind().equals( ElementKind.METHOD ) ) { + final String string = element.getSimpleName().toString(); + return isProperty( string, toTypeString( executable.getReturnType() ) ) + ? executable.getReturnType().accept(this, element) : null; } else { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/validation/ProcessorSessionFactory.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/validation/ProcessorSessionFactory.java index c89e4aead0..cf1d55feaa 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/validation/ProcessorSessionFactory.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/validation/ProcessorSessionFactory.java @@ -51,6 +51,7 @@ import static org.hibernate.internal.util.StringHelper.qualify; import static org.hibernate.internal.util.StringHelper.root; import static org.hibernate.internal.util.StringHelper.split; import static org.hibernate.internal.util.StringHelper.unroot; +import static org.hibernate.jpamodelgen.util.Constants.JAVA_OBJECT; /** * Implementation of the {@code Mock} objects based on standard @@ -696,7 +697,7 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory { List typeArguments = declaredType.getTypeArguments(); TypeMirror elementType = typeArguments.get(typeArguments.size()-1); return elementType==null - ? elementUtil.getTypeElement("java.lang.Object").asType() + ? elementUtil.getTypeElement(JAVA_OBJECT).asType() : elementType; }