some cleanup in static metamodel code

This commit is contained in:
Gavin King 2024-02-24 09:34:01 +01:00
parent 862a967a17
commit 43905c657f
8 changed files with 251 additions and 215 deletions

View File

@ -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();

View File

@ -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);
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<Boolean, Element> {
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 );
}
}

View File

@ -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<? extends AnnotationMirror> 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<Boolean, Element> {
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;
}
}

View File

@ -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();

View File

@ -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 );

View File

@ -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<TypeKind, String> PRIMITIVE_WRAPPERS = new HashMap<>();
private static final Map<TypeKind, String> 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<TypeVariable> 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<? extends TypeMirror> typeArguments = t.getTypeArguments();
if ( typeArguments.size() == 0 ) {
final List<? extends TypeMirror> 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<? extends TypeMirror> 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 {

View File

@ -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<? extends TypeMirror> 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;
}