METAGEN-16 Code makes use of getAnnotation() instead of getAnnotationMirrors()

This commit is contained in:
Hardy Ferentschik 2010-01-26 02:58:26 +00:00 committed by Strong Liu
parent bc1e9f1492
commit 3088900b2a
6 changed files with 254 additions and 171 deletions

View File

@ -27,6 +27,7 @@ import javax.persistence.AccessType;
import javax.tools.Diagnostic;
import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity;
import org.hibernate.jpamodelgen.util.TypeUtils;
/**
* @author Max Andersen

View File

@ -29,10 +29,12 @@ import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import javax.tools.Diagnostic;
import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity;
import org.hibernate.jpamodelgen.util.TypeUtils;
import org.hibernate.jpamodelgen.xml.XmlParser;
import static javax.lang.model.SourceVersion.RELEASE_6;
@ -48,11 +50,7 @@ import static javax.lang.model.SourceVersion.RELEASE_6;
@SupportedSourceVersion(RELEASE_6)
public class JPAMetaModelEntityProcessor extends AbstractProcessor {
private static final Boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = Boolean.FALSE;
private static final String ENTITY_ANN = javax.persistence.Entity.class.getName();
private static final String MAPPED_SUPERCLASS_ANN = MappedSuperclass.class.getName();
private static final String EMBEDDABLE_ANN = Embeddable.class.getName();
private boolean xmlProcessed = false;
private Context context;
@ -115,14 +113,13 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
private boolean hostJPAAnnotations(Set<? extends TypeElement> annotations) {
for ( TypeElement type : annotations ) {
final String typeName = type.getQualifiedName().toString();
if ( typeName.equals( ENTITY_ANN ) ) {
if ( TypeUtils.isTypeElementOfType( type, Entity.class ) ) {
return true;
}
else if ( typeName.equals( EMBEDDABLE_ANN ) ) {
else if ( TypeUtils.isTypeElementOfType( type, Embeddable.class ) ) {
return true;
}
else if ( typeName.equals( MAPPED_SUPERCLASS_ANN ) ) {
else if ( TypeUtils.isTypeElementOfType( type, MappedSuperclass.class ) ) {
return true;
}
}
@ -131,20 +128,17 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
private void handleRootElementAnnotationMirrors(final Element element) {
List<? extends AnnotationMirror> annotationMirrors = element
.getAnnotationMirrors();
List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
for ( AnnotationMirror mirror : annotationMirrors ) {
final String annotationType = mirror.getAnnotationType().toString();
if ( element.getKind() == ElementKind.CLASS ) {
if ( annotationType.equals( ENTITY_ANN ) ) {
if ( TypeUtils.isAnnotationMirrorOfType( mirror, Entity.class ) ) {
AnnotationMetaEntity metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context );
// TODO instead of just adding the entity we have to do some merging.
context.getMetaEntitiesToProcess().put( metaEntity.getQualifiedName(), metaEntity );
}
else if ( annotationType.equals( MAPPED_SUPERCLASS_ANN )
|| annotationType.equals( EMBEDDABLE_ANN ) ) {
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, MappedSuperclass.class )
|| TypeUtils.isAnnotationMirrorOfType( mirror, Embeddable.class ) ) {
AnnotationMetaEntity metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context );
// TODO instead of just adding the entity we have to do some merging.

View File

@ -1,96 +0,0 @@
// $Id$
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hibernate.jpamodelgen;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.Element;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.Types;
/**
* Utility class.
*
* @author Max Andersen
* @author Hardy Ferentschik
* @author Emmanuel Bernard
*/
public class TypeUtils {
private static final Map<String, String> PRIMITIVES = new HashMap<String, String>();
static {
PRIMITIVES.put( "char", "Character" );
PRIMITIVES.put( "byte", "Byte" );
PRIMITIVES.put( "short", "Short" );
PRIMITIVES.put( "int", "Integer" );
PRIMITIVES.put( "long", "Long" );
PRIMITIVES.put( "boolean", "Boolean" );
PRIMITIVES.put( "float", "Float" );
PRIMITIVES.put( "double", "Double" );
}
static public String toTypeString(TypeMirror type) {
if(type.getKind().isPrimitive()) {
return PRIMITIVES.get(type.toString());
}
return type.toString();
}
static public TypeElement getSuperclass(TypeElement element) {
final TypeMirror superClass = element.getSuperclass();
//superclass of Object is of NoType which returns some other kind
String superclassDeclaration = "";
if (superClass.getKind() == TypeKind.DECLARED ) {
//F..king Ch...t Have those people used their horrible APIs even once?
final Element superClassElement = ( ( DeclaredType ) superClass ).asElement();
return ( TypeElement ) superClassElement;
}
else {
return null;
}
}
public static String extractClosestRealTypeAsString(TypeMirror type, Context context) {
if ( type instanceof TypeVariable ) {
final TypeMirror compositeUpperBound = ( ( TypeVariable ) type ).getUpperBound();
final Types types = context.getProcessingEnvironment().getTypeUtils();
final List<? extends TypeMirror> upperBounds = types.directSupertypes( compositeUpperBound );
if (upperBounds.size() == 0) {
return compositeUpperBound.toString();
}
else {
//take the first one
return extractClosestRealTypeAsString( upperBounds.get( 0 ), context );
}
}
else {
return type.toString();
}
}
}

View File

@ -58,7 +58,7 @@ import org.hibernate.jpamodelgen.ImportContext;
import org.hibernate.jpamodelgen.ImportContextImpl;
import org.hibernate.jpamodelgen.MetaAttribute;
import org.hibernate.jpamodelgen.MetaEntity;
import org.hibernate.jpamodelgen.TypeUtils;
import org.hibernate.jpamodelgen.util.TypeUtils;
/**
* @author Max Andersen
@ -67,6 +67,7 @@ import org.hibernate.jpamodelgen.TypeUtils;
*/
public class AnnotationMetaEntity implements MetaEntity {
private static final String DEFAULT_ANNOTATION_PARAMETER_NAME = "value";
static Map<String, String> COLLECTIONS = new HashMap<String, String>();
static {
@ -122,14 +123,14 @@ public class AnnotationMetaEntity implements MetaEntity {
addPersistentMembers( membersFound, elementAccessType, methodsOfClass, AccessType.PROPERTY );
//process superclasses
for ( TypeElement superclass = TypeUtils.getSuperclass( element );
for ( TypeElement superclass = TypeUtils.getSuperclassTypeElement( element );
superclass != null;
superclass = TypeUtils.getSuperclass( superclass ) ) {
if ( superclass.getAnnotation( Entity.class ) != null ) {
superclass = TypeUtils.getSuperclassTypeElement( superclass ) ) {
if ( TypeUtils.containsAnnotation( superclass, Entity.class ) ) {
break; //will be handled or has been handled already
}
else if ( superclass.getAnnotation( MappedSuperclass.class ) != null ) {
//FIXME use the class defalut access type
else if ( TypeUtils.containsAnnotation( superclass, MappedSuperclass.class ) ) {
//FIXME use the class default access type
context.processElement( superclass, defaultAccessTypeForHierarchy );
}
}
@ -175,10 +176,9 @@ public class AnnotationMetaEntity implements MetaEntity {
//FIXME is it really true if only the superclass is changed
TypeElement superClass = element;
do {
superClass = TypeUtils.getSuperclass( superClass );
superClass = TypeUtils.getSuperclassTypeElement( superClass );
if ( superClass != null ) {
if ( superClass.getAnnotation( Entity.class ) != null
|| superClass.getAnnotation( MappedSuperclass.class ) != null ) {
if ( TypeUtils.containsAnnotation( superClass, Entity.class, MappedSuperclass.class ) ) {
//FIXME make it work for XML
AccessType superClassAccessType = getAccessTypeForClass( superClass );
//we've reach the root entity and resolved Ids
@ -221,8 +221,7 @@ public class AnnotationMetaEntity implements MetaEntity {
* when forcing access type, we can only override the defaultAccessTypeForHierarchy
* if we are the entity root (identified by having @Id or @EmbeddedId
*/
final Access accessAnn = searchedElement.getAnnotation( Access.class );
AccessType forcedAccessType = accessAnn != null ? accessAnn.value() : null;
AccessType forcedAccessType = determineAnnotationSpecifiedAccessType( searchedElement );
if ( forcedAccessType != null ) {
context.logMessage( Diagnostic.Kind.OTHER, "access type " + searchedElement + ":" + forcedAccessType );
context.addAccessType( searchedElement, forcedAccessType );
@ -239,11 +238,9 @@ public class AnnotationMetaEntity implements MetaEntity {
for ( Object entityAnnotation : entityAnnotations ) {
AnnotationMirror annotationMirror = ( AnnotationMirror ) entityAnnotation;
final String annotationType = annotationMirror.getAnnotationType().toString();
//FIXME consider XML
if ( annotationType.equals( Id.class.getName() )
|| annotationType.equals( EmbeddedId.class.getName() ) ) {
if ( TypeUtils.isAnnotationMirrorOfType( annotationMirror, Id.class )
|| TypeUtils.isAnnotationMirrorOfType( annotationMirror, EmbeddedId.class ) ) {
context.logMessage( Diagnostic.Kind.OTHER, "Found id on" + searchedElement );
final ElementKind kind = subElement.getKind();
if ( kind == ElementKind.FIELD || kind == ElementKind.METHOD ) {
@ -279,6 +276,30 @@ public class AnnotationMetaEntity implements MetaEntity {
return forcedAccessType;
}
private AccessType determineAnnotationSpecifiedAccessType(Element element) {
final AnnotationMirror accessAnnotationMirror = TypeUtils.getAnnotationMirror( element, Access.class );
AccessType forcedAccessType = null;
if ( accessAnnotationMirror != null ) {
Element accessElement = ( Element ) TypeUtils.getAnnotationValue(
accessAnnotationMirror,
DEFAULT_ANNOTATION_PARAMETER_NAME
);
if ( accessElement.getKind().equals( ElementKind.ENUM_CONSTANT ) ) {
if ( accessElement.getSimpleName().toString().equals( AccessType.PROPERTY.toString() ) ) {
forcedAccessType = AccessType.PROPERTY;
}
else if ( accessElement.getSimpleName().toString().equals( AccessType.FIELD.toString() ) ) {
forcedAccessType = AccessType.FIELD;
}
else {
context.logMessage( Diagnostic.Kind.ERROR, "Unexpected type for access type" );
}
}
}
return forcedAccessType;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
@ -332,13 +353,13 @@ public class AnnotationMetaEntity implements MetaEntity {
correctAccessType = true;
}
else {
final Access accessAnn = element.getAnnotation( Access.class );
if ( accessAnn != null && explicitAccessType.equals( accessAnn.value() ) ) {
AccessType annotationAccessType = determineAnnotationSpecifiedAccessType( element );
if ( explicitAccessType.equals( annotationAccessType ) ) {
correctAccessType = true;
}
}
return correctAccessType
&& element.getAnnotation( Transient.class ) == null
&& !TypeUtils.containsAnnotation( element, Transient.class )
&& !element.getModifiers().contains( Modifier.TRANSIENT )
&& !element.getModifiers().contains( Modifier.STATIC );
@ -354,10 +375,9 @@ public class AnnotationMetaEntity implements MetaEntity {
String fqElementName = returnedElement.getQualifiedName()
.toString(); // WARNING: .toString() is necessary here since Name equals does not compare to String
String collection = COLLECTIONS.get( fqElementName );
final List<? extends AnnotationMirror> annotations = element.getAnnotationMirrors();
String targetEntity = getTargetEntity( annotations );
String targetEntity = getTargetEntity( element.getAnnotationMirrors() );
if ( collection != null ) {
if ( containsAnnotation( annotations, ElementCollection.class ) ) {
if ( TypeUtils.containsAnnotation( element, ElementCollection.class ) ) {
//FIXME I don't understand why this code is different between Elementcollection and a regular collection but it needs to take targetClass into account
TypeMirror collectionElementType = getCollectionElementType( t, fqElementName );
final TypeElement collectionElement = ( TypeElement ) context.getProcessingEnvironment()
@ -375,13 +395,14 @@ public class AnnotationMetaEntity implements MetaEntity {
);
}
else {
return new AnnotationMetaCollection( parent, element, collection, getElementType( t, targetEntity ) );
return new AnnotationMetaCollection(
parent, element, collection, getElementType( t, targetEntity )
);
}
}
else {
//FIXME Consider XML
if ( element.getAnnotation( Embedded.class ) != null
|| returnedElement.getAnnotation( Embeddable.class ) != null ) {
if ( TypeUtils.containsAnnotation( returnedElement, Embedded.class, Embeddable.class ) ) {
this.parent.context.processElement(
returnedElement,
this.parent.defaultAccessTypeForElement
@ -424,43 +445,22 @@ public class AnnotationMetaEntity implements MetaEntity {
}
}
private boolean containsAnnotation(List<? extends AnnotationMirror> annotations, Class<?> annotation) {
String annString = annotation.getName();
for ( AnnotationMirror mirror : annotations ) {
if ( annString.equals( mirror.getAnnotationType().toString() ) ) {
return true;
}
}
return false;
}
/**
* Returns targetEntity or null if no targetEntity is here or if equals to void
* @return target entity class name as string or {@code null} if no targetEntity is here or if equals to void
*/
private String getTargetEntity(List<? extends AnnotationMirror> annotations) {
final String elementCollection = ElementCollection.class.getName();
for ( AnnotationMirror mirror : annotations ) {
final String annotation = mirror.getAnnotationType().toString();
if ( elementCollection.equals( annotation ) ) {
if ( TypeUtils.isAnnotationMirrorOfType( mirror, ElementCollection.class )
|| TypeUtils.isAnnotationMirrorOfType( mirror, OneToMany.class )
|| TypeUtils.isAnnotationMirrorOfType( mirror, ManyToMany.class )
|| TypeUtils.isAnnotationMirrorOfType( mirror, ManyToOne.class )
|| TypeUtils.isAnnotationMirrorOfType( mirror, OneToOne.class ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
if ( targetEntity != null ) {
return targetEntity;
}
else if ( OneToMany.class.getName().equals( annotation ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
}
else if ( ManyToMany.class.getName().equals( annotation ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
}
else if ( ManyToOne.class.getName().equals( annotation ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
}
else if ( OneToOne.class.getName().equals( annotation ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
}
}
return null;
@ -506,7 +506,9 @@ public class AnnotationMetaEntity implements MetaEntity {
}
private String getElementType(DeclaredType declaredType, String targetEntity) {
if (targetEntity != null) return targetEntity;
if ( targetEntity != null ) {
return targetEntity;
}
final List<? extends TypeMirror> mirrors = declaredType.getTypeArguments();
if ( mirrors.size() == 1 ) {
final TypeMirror type = mirrors.get( 0 );
@ -518,12 +520,10 @@ public class AnnotationMetaEntity implements MetaEntity {
else {
//for 0 or many
//0 is expected, many is not
if ( mirrors.size() > 2) {
if ( mirrors.size() > 2 ) {
context.logMessage( Diagnostic.Kind.WARNING, "Unable to find the closest solid type" + declaredType );
}
return "?";
}
}
}

View File

@ -0,0 +1,184 @@
// $Id$
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hibernate.jpamodelgen.util;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.Types;
import org.hibernate.jpamodelgen.Context;
/**
* Utility class.
*
* @author Max Andersen
* @author Hardy Ferentschik
* @author Emmanuel Bernard
*/
public class TypeUtils {
private static final Map<String, String> PRIMITIVES = new HashMap<String, String>();
static {
PRIMITIVES.put( "char", "Character" );
PRIMITIVES.put( "byte", "Byte" );
PRIMITIVES.put( "short", "Short" );
PRIMITIVES.put( "int", "Integer" );
PRIMITIVES.put( "long", "Long" );
PRIMITIVES.put( "boolean", "Boolean" );
PRIMITIVES.put( "float", "Float" );
PRIMITIVES.put( "double", "Double" );
}
static public String toTypeString(TypeMirror type) {
if ( type.getKind().isPrimitive() ) {
return PRIMITIVES.get( type.toString() );
}
return type.toString();
}
static public TypeElement getSuperclassTypeElement(TypeElement element) {
final TypeMirror superClass = element.getSuperclass();
//superclass of Object is of NoType which returns some other kind
if ( superClass.getKind() == TypeKind.DECLARED ) {
//F..king Ch...t Have those people used their horrible APIs even once?
final Element superClassElement = ( ( DeclaredType ) superClass ).asElement();
return ( TypeElement ) superClassElement;
}
else {
return null;
}
}
public static String extractClosestRealTypeAsString(TypeMirror type, Context context) {
if ( type instanceof TypeVariable ) {
final TypeMirror compositeUpperBound = ( ( TypeVariable ) type ).getUpperBound();
final Types types = context.getProcessingEnvironment().getTypeUtils();
final List<? extends TypeMirror> upperBounds = types.directSupertypes( compositeUpperBound );
if ( upperBounds.size() == 0 ) {
return compositeUpperBound.toString();
}
else {
//take the first one
return extractClosestRealTypeAsString( upperBounds.get( 0 ), context );
}
}
else {
return type.toString();
}
}
public static boolean containsAnnotation(Element element, Class<?>... annotations) {
assert element != null;
assert annotations != null;
List<String> annotationClassNames = new ArrayList<String>();
for ( Class<?> clazz : annotations ) {
annotationClassNames.add( clazz.getName() );
}
List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
for ( AnnotationMirror mirror : annotationMirrors ) {
if ( annotationClassNames.contains( mirror.getAnnotationType().toString() ) ) {
return true;
}
}
return false;
}
/**
* Returns {@code true} if the provided annotation type is of the same type as the provided class, {@code false} otherwise.
* This method uses the string class names for comparison. See also {@link http://www.retep.org/2009/02/getting-class-values-from-annotations.html}.
*
* @param annotationMirror The annotation mirror
* @param clazz the class name to check again
*
* @return {@code true} if the provided annotation type is of the same type as the provided class, {@code false} otherwise.
*/
public static boolean isAnnotationMirrorOfType(AnnotationMirror annotationMirror, Class<? extends Annotation> clazz) {
assert annotationMirror != null;
assert clazz != null;
String annotationClassName = annotationMirror.getAnnotationType().toString();
String className = clazz.getName();
return annotationClassName.equals( className );
}
public static boolean isTypeElementOfType(TypeElement element, Class<?> clazz) {
assert element != null;
assert clazz != null;
String elementClassName = element.getQualifiedName().toString();
String className = clazz.getName();
return elementClassName.equals( className );
}
/**
* Returns the annotation mirror for the specified annotation class from the {@code Element}.
*
* @param element the element to check for the hosted annotation
* @param clazz the annotation class to check for
*
* @return the annotation mirror for the specified annotation class from the {@code Element} or {@code null} in case
* the {@code TypeElement} does not host the specified annotation.
*/
public static AnnotationMirror getAnnotationMirror(Element element, Class<? extends Annotation> clazz) {
assert element != null;
assert clazz != null;
AnnotationMirror mirror = null;
for ( AnnotationMirror am : element.getAnnotationMirrors() ) {
if ( isAnnotationMirrorOfType( am, clazz ) ) {
mirror = am;
break;
}
}
return mirror;
}
public static Object getAnnotationValue(AnnotationMirror annotationMirror, String parameterValue) {
assert annotationMirror != null;
assert parameterValue != null;
Object returnValue = null;
for ( Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : annotationMirror.getElementValues()
.entrySet() ) {
if ( parameterValue.equals( entry.getKey().getSimpleName().toString() ) ) {
returnValue = entry.getValue().getValue();
break;
}
}
return returnValue;
}
}

View File

@ -31,7 +31,7 @@ import org.hibernate.jpamodelgen.MetaAttribute;
import org.hibernate.jpamodelgen.ImportContextImpl;
import org.hibernate.jpamodelgen.MetaEntity;
import org.hibernate.jpamodelgen.ImportContext;
import org.hibernate.jpamodelgen.TypeUtils;
import org.hibernate.jpamodelgen.util.TypeUtils;
import org.hibernate.jpamodelgen.xml.jaxb.Attributes;
import org.hibernate.jpamodelgen.xml.jaxb.Basic;
import org.hibernate.jpamodelgen.xml.jaxb.ElementCollection;