worked on improving Querydsl APT

This commit is contained in:
Timo Westkämper 2011-11-05 18:50:12 +02:00
parent d2927174d3
commit f13a653d52
5 changed files with 334 additions and 466 deletions

View File

@ -46,7 +46,6 @@ import com.mysema.query.codegen.EntityType;
import com.mysema.query.codegen.QueryTypeFactory;
import com.mysema.query.codegen.Supertype;
import com.mysema.query.codegen.TypeMappings;
import com.mysema.util.ClassPathUtils;
/**
* ExtendedTypeFactory is a factory for APT inspection based Type creation
@ -66,7 +65,7 @@ public final class ExtendedTypeFactory {
private final ProcessingEnvironment env;
private final TypeElement numberType, comparableType;
private final TypeMirror numberType, comparableType, collectionType, setType, listType, mapType;
private final TypeMappings typeMappings;
@ -78,17 +77,7 @@ public final class ExtendedTypeFactory {
@Override
public Type visitPrimitive(PrimitiveType primitiveType, Boolean p) {
switch (primitiveType.getKind()) {
case BOOLEAN: return Types.BOOLEAN;
case BYTE: return Types.BYTE;
case CHAR: return Types.CHARACTER;
case DOUBLE: return Types.DOUBLE;
case FLOAT: return Types.FLOAT;
case INT: return Types.INTEGER;
case LONG: return Types.LONG;
case SHORT: return Types.SHORT;
}
return null;
return visit(env.getTypeUtils().boxedClass(primitiveType).asType(), p);
}
@Override
@ -179,18 +168,7 @@ public final class ExtendedTypeFactory {
@Override
public List<String> visitPrimitive(PrimitiveType t, Boolean p) {
// TODO : optimize
switch (t.getKind()) {
case BOOLEAN: return Collections.singletonList("Boolean");
case BYTE: return Collections.singletonList("Byte");
case CHAR: return Collections.singletonList("Character");
case DOUBLE: return Collections.singletonList("Double");
case FLOAT: return Collections.singletonList("Float");
case INT: return Collections.singletonList("Integer");
case LONG: return Collections.singletonList("Long");
case SHORT: return Collections.singletonList("Short");
}
return null;
return visit(env.getTypeUtils().boxedClass(t).asType(), p);
}
@Override
@ -256,10 +234,9 @@ public final class ExtendedTypeFactory {
public List<String> visitNoType(NoType t, Boolean p) {
return Collections.singletonList("Object");
}
};
public ExtendedTypeFactory(
ProcessingEnvironment env,
Configuration configuration,
@ -269,14 +246,20 @@ public final class ExtendedTypeFactory {
this.env = env;
this.defaultType = Types.OBJECT;
this.entityAnnotations = annotations;
this.numberType = env.getElementUtils().getTypeElement(Number.class.getName());
this.comparableType = env.getElementUtils().getTypeElement(Comparable.class.getName());
this.numberType = getErasedType(Number.class);
this.comparableType = getErasedType(Comparable.class);
this.collectionType = getErasedType(Collection.class);
this.listType = getErasedType(List.class);
this.setType = getErasedType(Set.class);
this.mapType = getErasedType(Map.class);
this.typeMappings = typeMappings;
this.queryTypeFactory = queryTypeFactory;
}
private TypeMirror getErasedType(Class<?> clazz) {
return env.getTypeUtils().erasure(env.getElementUtils().getTypeElement(clazz.getName()).asType());
}
private Type createType(TypeElement typeElement, TypeCategory category, List<? extends TypeMirror> typeArgs, boolean deep) {
String name = typeElement.getQualifiedName().toString();
String simpleName = typeElement.getSimpleName().toString();
@ -324,10 +307,10 @@ public final class ExtendedTypeFactory {
String name = typeElement.getQualifiedName().toString();
TypeCategory typeCategory = TypeCategory.get(name);
if (typeCategory != TypeCategory.NUMERIC && isImplemented(typeElement, comparableType) && isSubType(typeElement, numberType)) {
if (typeCategory != TypeCategory.NUMERIC && isAssignable(typeElement.asType(), comparableType) && isSubType(typeElement.asType(), numberType)) {
typeCategory = TypeCategory.NUMERIC;
} else if (!typeCategory.isSubCategoryOf(TypeCategory.COMPARABLE) && isImplemented(typeElement, comparableType)) {
} else if (!typeCategory.isSubCategoryOf(TypeCategory.COMPARABLE) && isAssignable(typeElement.asType(), comparableType)) {
typeCategory = TypeCategory.COMPARABLE;
} if (typeCategory == TypeCategory.SIMPLE) {
@ -401,18 +384,6 @@ public final class ExtendedTypeFactory {
return new SimpleType(Types.MAP, keyType, valueType);
}
private Type createCollectionType(String simpleName, Iterator<? extends TypeMirror> typeMirrors, boolean deep) {
return createCollectionType(Types.COLLECTION, simpleName, typeMirrors, deep);
}
private Type createListType(String simpleName, Iterator<? extends TypeMirror> typeMirrors, boolean deep) {
return createCollectionType(Types.LIST, simpleName, typeMirrors, deep);
}
private Type createSetType(String simpleName, Iterator<? extends TypeMirror> typeMirrors, boolean deep) {
return createCollectionType(Types.SET, simpleName, typeMirrors, deep);
}
private Type createCollectionType(Type baseType, String simpleName, Iterator<? extends TypeMirror> typeMirrors, boolean deep) {
if (!typeMirrors.hasNext()){
return new SimpleType(baseType, defaultType);
@ -510,28 +481,24 @@ public final class ExtendedTypeFactory {
return createType(typeElement, TypeCategory.ENTITY, declaredType.getTypeArguments(), deep);
}
}
String name = typeElement.getQualifiedName().toString();
String simpleName = typeElement.getSimpleName().toString();
Iterator<? extends TypeMirror> i = declaredType.getTypeArguments().iterator();
Class<?> cl = ClassPathUtils.safeClassForName(name);
if (cl == null) { // class not available
return createType(typeElement, TypeCategory.get(name), declaredType.getTypeArguments(), deep);
} else if (Map.class.isAssignableFrom(cl)) {
if (isAssignable(declaredType, mapType)) {
return createMapType(simpleName, i, deep);
} else if (List.class.isAssignableFrom(cl)) {
return createListType(simpleName, i, deep);
} else if (isAssignable(declaredType, listType)) {
return createCollectionType(Types.LIST, simpleName, i, deep);
} else if (Set.class.isAssignableFrom(cl)) {
return createSetType(simpleName, i, deep);
} else if (isAssignable(declaredType, setType)) {
return createCollectionType(Types.SET, simpleName, i, deep);
} else if (Collection.class.isAssignableFrom(cl)) {
return createCollectionType(simpleName, i, deep);
} else if (isAssignable(declaredType, collectionType)) {
return createCollectionType(Types.COLLECTION, simpleName, i, deep);
} else {
String name = typeElement.getQualifiedName().toString();
return createType(typeElement, TypeCategory.get(name), declaredType.getTypeArguments(), deep);
}
}
@ -578,38 +545,13 @@ public final class ExtendedTypeFactory {
doubleIndexEntities = doubleIndex;
return superTypes;
}
// TODO : simplify this
private boolean isImplemented(TypeElement type, TypeElement iface) {
for (TypeMirror t : type.getInterfaces()) {
String name = t.toString();
if (name.contains("<")) {
name = name.substring(0, name.indexOf('<'));
}
// interface is directly implemented
if (name.equals(iface.getQualifiedName().toString())) {
return true;
}
}
if (type.getSuperclass() != null) {
TypeElement superType = (TypeElement) env.getTypeUtils().asElement(type.getSuperclass());
if (superType != null) {
return isImplemented(superType, iface);
}
superType = env.getElementUtils().getTypeElement(type.getSuperclass().toString());
if (superType != null) {
return isImplemented(superType, iface);
} else {
return false;
}
} else {
return false;
}
private boolean isAssignable(TypeMirror type, TypeMirror iface) {
return env.getTypeUtils().isAssignable(type, iface);
}
private boolean isSubType(TypeElement type1, TypeElement type2) {
return env.getTypeUtils().isSubtype(type1.asType(), type2.asType());
private boolean isSubType(TypeMirror type1, TypeMirror type2) {
return env.getTypeUtils().isSubtype(type1, type2);
}
private TypeMirror normalize(TypeMirror type) {

View File

@ -9,7 +9,16 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import javax.annotation.processing.Filer;
@ -29,10 +38,10 @@ import javax.lang.model.type.NoType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import javax.tools.Diagnostic.Kind;
import com.mysema.codegen.JavaWriter;
import com.mysema.codegen.model.Parameter;
@ -41,7 +50,6 @@ import com.mysema.codegen.model.Type;
import com.mysema.codegen.model.TypeCategory;
import com.mysema.commons.lang.Assert;
import com.mysema.query.annotations.QueryDelegate;
import com.mysema.query.annotations.QueryEntities;
import com.mysema.query.annotations.QueryExclude;
import com.mysema.query.annotations.QueryProjection;
import com.mysema.query.annotations.Variables;
@ -53,7 +61,6 @@ import com.mysema.query.codegen.Serializer;
import com.mysema.query.codegen.SerializerConfig;
import com.mysema.query.codegen.Supertype;
import com.mysema.query.codegen.TypeMappings;
import com.mysema.util.BeanUtils;
/**
* Processor handles the actual work in the Querydsl APT module
@ -84,7 +91,7 @@ public class Processor {
private final Map<String, EntityType> projectionTypes = new HashMap<String, EntityType>();
private final ElementHandler elementHandler;
private final TypeElementHandler elementHandler;
private final Map<String, EntityType> embeddables = new HashMap<String,EntityType>();
@ -98,6 +105,8 @@ public class Processor {
private final ExtendedTypeFactory typeFactory;
private final TypeExtractor typeExtractor = new TypeExtractor(true);
/**
* Create a new Processor instance
*
@ -121,7 +130,7 @@ public class Processor {
TypeMappings typeMappings = configuration.getTypeMappings();
QueryTypeFactory queryTypeFactory = configuration.getQueryTypeFactory();
this.typeFactory = new ExtendedTypeFactory(env, configuration, entityAnnotations, typeMappings, queryTypeFactory);
this.elementHandler = new ElementHandler(configuration, typeFactory, typeMappings, queryTypeFactory);
this.elementHandler = new TypeElementHandler(configuration, typeFactory, typeMappings, queryTypeFactory);
}
public void process() {
@ -134,6 +143,7 @@ public class Processor {
}
for (String key : entityTypes.keySet()) {
actualSupertypes.remove(key);
extensionTypes.remove(key);
embeddables.remove(key);
}
@ -153,8 +163,10 @@ public class Processor {
processFromProperties();
}
boolean hasEmbeddableAnnotation = configuration.getEmbeddableAnnotation() != null;
if (configuration.getSuperTypeAnnotation() != null) {
processSupertypes();
process(configuration.getSuperTypeAnnotation(), hasEmbeddableAnnotation, actualSupertypes);
}
if (configuration.getEmbeddedAnnotation() != null) {
@ -162,76 +174,154 @@ public class Processor {
}
if (configuration.getEmbeddableAnnotation() != null) {
processEmbeddables();
process(configuration.getEmbeddableAnnotation(), false, embeddables);
}
if (configuration.getEntitiesAnnotation() != null) {
processEntitiesFromPackage();
}
processEntities();
process(configuration.getEntityAnnotation(), hasEmbeddableAnnotation, entityTypes);
processProjectionTypes();
}
/**
* Get the elements with the given annotation type
*
* @param a
* @return
*/
private Set<? extends Element> getElements(Class<? extends Annotation> a) {
return roundEnv.getElementsAnnotatedWith(a);
}
private void processExclusions() {
for (Element element : roundEnv.getElementsAnnotatedWith(QueryExclude.class)) {
for (Element element : getElements(QueryExclude.class)) {
if (element instanceof PackageElement) {
configuration.addExcludedPackage(((PackageElement)element).getQualifiedName().toString());
} else {
} else if (element instanceof TypeElement) {
configuration.addExcludedClass(((TypeElement)element).getQualifiedName().toString());
} else {
throw new IllegalArgumentException(element.toString());
}
}
}
private void process(Class<? extends Annotation> annotation, boolean skipEmbeddables, Map<String, EntityType> types) {
process(getElements(annotation), skipEmbeddables, types);
}
@SuppressWarnings("unchecked")
private void process(Set<? extends Element> elements, boolean skipEmbeddables, Map<String, EntityType> types) {
Deque<Type> superTypes = new ArrayDeque<Type>();
List<TypeElement> allElements = new ArrayList<TypeElement>();
List<TypeMirror> typeMirrors = new ArrayList<TypeMirror>();
List<TypeMirror> superTypeMirrors = new ArrayList<TypeMirror>();
for (TypeElement element : (Set<TypeElement>)elements) {
if (skipEmbeddables && element.getAnnotation(configuration.getEmbeddableAnnotation()) != null) {
continue;
}
typeFactory.getEntityType(element.asType(), false);
typeMirrors.add(element.asType());
allElements.add(element);
addAnnotationlessSupertypes(superTypeMirrors, allElements, element);
}
// super type handling
for (TypeMirror typeMirror : superTypeMirrors) {
typeFactory.getEntityType(typeMirror, true);
}
for (TypeMirror typeMirror : typeMirrors) {
typeFactory.getEntityType(typeMirror, true);
}
// get annotated types
for (TypeElement element : allElements) {
EntityType model = elementHandler.handleEntityType(element);
registerTypeElement(model.getFullName(), element);
types.put(model.getFullName(), model);
if (model.getSuperType() != null) {
superTypes.push(model.getSuperType().getType());
}
}
mergeTypes(types, superTypes);
}
private void processEmbedded() {
Set<Element> elements = new HashSet<Element>();
// only creation
for (Element element : getElements(configuration.getEmbeddedAnnotation())) {
TypeMirror type = element.asType();
if (element.getKind() == ElementKind.METHOD){
type = ((ExecutableElement)element).getReturnType();
}
String typeName = type.toString();
if (typeName.startsWith(Collection.class.getName())
|| typeName.startsWith(List.class.getName())
|| typeName.startsWith(Set.class.getName())) {
type = ((DeclaredType)type).getTypeArguments().get(0);
} else if (typeName.startsWith(Map.class.getName())){
type = ((DeclaredType)type).getTypeArguments().get(1);
}
TypeElement typeElement = typeExtractor.visit(type);
if (typeElement != null && typeElement.getAnnotation(configuration.getEntityAnnotation()) == null) {
elements.add(typeElement);
}
}
process(elements, false, embeddables);
}
@SuppressWarnings("unchecked")
private void processEntitiesFromPackage() {
Class<? extends Annotation> annotation = configuration.getEntitiesAnnotation();
Set<Element> elements = new HashSet<Element>();
// only creation
for (Element element : getElements(annotation)) {
for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
if (mirror.getAnnotationType().asElement().getSimpleName().toString().equals(annotation.getSimpleName())) {
for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> entry : mirror.getElementValues().entrySet()) {
if (entry.getKey().getSimpleName().toString().equals("value")) {
List<AnnotationValue> values = (List<AnnotationValue>) entry.getValue().getValue();
for (AnnotationValue value : values) {
DeclaredType type = (DeclaredType) value.getValue();
elements.add(type.asElement());
}
}
}
}
}
}
process(elements, false, entityTypes);
}
private void processFromProperties() {
Set<Element> elements = new HashSet<Element>();
for (Class<? extends Annotation> annotation : entityAnnotations) {
elements.addAll(roundEnv.getElementsAnnotatedWith(annotation));
elements.addAll(getElements(annotation));
}
TypeExtractor typeExtractor = new TypeExtractor(true, true);
Set<TypeElement> types = new HashSet<TypeElement>();
// classes
for (Element element : elements) {
if (element instanceof TypeElement) {
TypeElement type = (TypeElement)element;
List<? extends Element> children = type.getEnclosedElements();
VisitorConfig config = configuration.getConfig(type, children);
// fields
if (config.visitFieldProperties()) {
for (VariableElement field : ElementFilter.fieldsIn(children)) {
TypeElement typeElement = typeExtractor.handle(field.asType());
if (typeElement != null) {
types.add(typeElement);
}
}
}
// getters
if (config.visitMethodProperties()) {
for (ExecutableElement method : ElementFilter.methodsIn(children)) {
String name = method.getSimpleName().toString();
if (name.startsWith("get") && method.getParameters().isEmpty()) {
name = BeanUtils.uncapitalize(name.substring(3));
} else if (name.startsWith("is") && method.getParameters().isEmpty()) {
name = BeanUtils.uncapitalize(name.substring(2));
} else {
continue;
}
TypeElement typeElement = typeExtractor.handle(method.getReturnType());
if (typeElement != null) {
types.add(typeElement);
}
}
}
processFromProperties((TypeElement)element, types);
}
}
List<TypeMirror> typeMirrors = new ArrayList<TypeMirror>();
List<TypeMirror> typeMirrors = new ArrayList<TypeMirror>(types.size());
for (TypeElement type : types) {
// skip internal types
@ -274,53 +364,35 @@ public class Processor {
}
}
}
private void serializeTypes() {
if (!actualSupertypes.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Supertypes");
serialize(configuration.getSupertypeSerializer(), actualSupertypes.values());
}
if (!entityTypes.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Entity types");
serialize(configuration.getEntitySerializer(), entityTypes.values());
}
if (!extensionTypes.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Extension types");
serialize(configuration.getEmbeddableSerializer(), extensionTypes.values());
}
if (!embeddables.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Embeddable types");
serialize(configuration.getEmbeddableSerializer(), embeddables.values());
}
if (!projectionTypes.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Projection types");
serialize(configuration.getDTOSerializer(), projectionTypes.values());
}
}
private void serializeVariableClasses() {
for (Element element : roundEnv.getElementsAnnotatedWith(Variables.class)) {
if (element instanceof PackageElement) {
Variables vars = element.getAnnotation(Variables.class);
PackageElement packageElement = (PackageElement)element;
List<EntityType> models = new ArrayList<EntityType>();
for (EntityType model : entityTypes.values()) {
if (model.getPackageName().equals(packageElement.getQualifiedName().toString())) {
models.add(model);
}
private void processFromProperties(TypeElement type, Set<TypeElement> types) {
List<? extends Element> children = type.getEnclosedElements();
VisitorConfig config = configuration.getConfig(type, children);
// fields
if (config.visitFieldProperties()) {
for (VariableElement field : ElementFilter.fieldsIn(children)) {
TypeElement typeElement = typeExtractor.visit(field.asType());
if (typeElement != null) {
types.add(typeElement);
}
serializeVariableList(packageElement.getQualifiedName().toString(), vars, models);
}
}
// getters
if (config.visitMethodProperties()) {
for (ExecutableElement method : ElementFilter.methodsIn(children)) {
String name = method.getSimpleName().toString();
if ((name.startsWith("get") || name.startsWith("is")) && method.getParameters().isEmpty()) {
TypeElement typeElement = typeExtractor.visit(method.getReturnType());
if (typeElement != null) {
types.add(typeElement);
}
}
}
}
}
private void addSupertypeFields(EntityType model, Map<String, EntityType> superTypes, Set<EntityType> handled) {
if (handled.add(model)) {
for (Supertype supertype : model.getSuperTypes()) {
@ -336,7 +408,7 @@ public class Processor {
@SuppressWarnings("unchecked")
private Set<Element> getElementsAndCache(Class<? extends Annotation> annotationType) {
Set<Element> elements = (Set<Element>)roundEnv.getElementsAnnotatedWith(annotationType);
Set<Element> elements = (Set<Element>)getElements(annotationType);
if (!elements.isEmpty()) {
Set<Element> cached = elementCache.get(annotationType);
if (cached == null) {
@ -378,28 +450,7 @@ public class Processor {
return Collections.emptySet();
}
}
@Nullable
private FileObject getSourceFile(String fullName) throws IOException {
Elements elementUtils = env.getElementUtils();
TypeElement sourceElement = elementUtils.getTypeElement(fullName);
if (sourceElement == null) {
return null;
} else {
if (sourceElement.getNestingKind().isNested()) {
sourceElement = (TypeElement) sourceElement.getEnclosingElement();
}
PackageElement packageElement = elementUtils.getPackageOf(sourceElement);
try {
return env.getFiler().getResource(StandardLocation.SOURCE_PATH,
packageElement.getQualifiedName(),
sourceElement.getSimpleName() + ".java");
} catch(Exception e) {
return null;
}
}
}
private void mergeTypes(Map<String, EntityType> types, Deque<Type> superTypes) {
// get external supertypes
while (!superTypes.isEmpty()) {
@ -426,63 +477,19 @@ public class Processor {
}
}
private void process(Class<? extends Annotation> annotation, Map<String,EntityType> types) {
Deque<Type> superTypes = new ArrayDeque<Type>();
List<Element> elements = new ArrayList<Element>();
// only creation
List<TypeMirror> typeMirrors = new ArrayList<TypeMirror>();
List<TypeMirror> superTypeMirrors = new ArrayList<TypeMirror>();
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
if (configuration.getEmbeddableAnnotation() == null
|| element.getAnnotation(configuration.getEmbeddableAnnotation()) == null) {
typeFactory.getEntityType(element.asType(), false);
typeMirrors.add(element.asType());
elements.add(element);
addAnnotationlessSupertypes(superTypeMirrors, elements, element);
}
}
for (TypeMirror typeMirror : superTypeMirrors) {
typeFactory.getEntityType(typeMirror, true);
}
// super type handling
for (TypeMirror typeMirror : typeMirrors) {
typeFactory.getEntityType(typeMirror, true);
}
// get annotated types
for (Element element : elements) {
EntityType model = elementHandler.handleEntityType((TypeElement) element);
registerTypeElement(model.getFullName(), (TypeElement)element);
types.put(model.getFullName(), model);
if (model.getSuperType() != null) {
superTypes.push(model.getSuperType().getType());
}
}
mergeTypes(types, superTypes);
}
private boolean hasKnownAnnotation(Element element) {
if (configuration.getEmbeddableAnnotation() != null && element.getAnnotation(configuration.getEmbeddableAnnotation()) != null) {
return true;
}
if (configuration.getSuperTypeAnnotation() != null && element.getAnnotation(configuration.getSuperTypeAnnotation()) != null) {
} else if (configuration.getSuperTypeAnnotation() != null && element.getAnnotation(configuration.getSuperTypeAnnotation()) != null) {
return true;
}
if (element.getAnnotation(configuration.getEntityAnnotation()) != null) {
} else if (element.getAnnotation(configuration.getEntityAnnotation()) != null) {
return true;
}
return false;
} else {
return false;
}
}
private void processDelegateMethod(Element delegateMethod, boolean cached) {
ExecutableElement method = (ExecutableElement)delegateMethod;
Element element = delegateMethod.getEnclosingElement();
@ -517,12 +524,12 @@ public class Processor {
}
private void processDelegateMethods() {
// 1 : get elements from cache
// get elements from cache
for (Element delegateMethod : getElementsFromCache(QueryDelegate.class)) {
processDelegateMethod(delegateMethod, true);
}
// 2 : get elements from roundEnv
// get elements from roundEnv
for (Element delegateMethod : getElementsAndCache(QueryDelegate.class)) {
processDelegateMethod(delegateMethod, false);
}
@ -530,7 +537,7 @@ public class Processor {
private void processProjectionTypes() {
Set<Element> visitedDTOTypes = new HashSet<Element>();
for (Element element : roundEnv.getElementsAnnotatedWith(QueryProjection.class)) {
for (Element element : getElements(QueryProjection.class)) {
Element parent = element.getEnclosingElement();
if (parent.getAnnotation(configuration.getEntityAnnotation()) == null
&& parent.getAnnotation(configuration.getEmbeddableAnnotation()) == null
@ -542,58 +549,20 @@ public class Processor {
}
}
}
private void processEmbeddables() {
List<TypeMirror> typeMirrors = new ArrayList<TypeMirror>();
List<TypeMirror> superTypeMirrors = new ArrayList<TypeMirror>();
List<Element> elements = new ArrayList<Element>();
// only creation
for (Element element : roundEnv.getElementsAnnotatedWith(configuration.getEmbeddableAnnotation())) {
// TODO: Why is this needed if there's no assignment? Just for cache?
typeFactory.getEntityType(element.asType(), false);
typeMirrors.add(element.asType());
elements.add(element);
addAnnotationlessSupertypes(superTypeMirrors, elements, element);
}
for (TypeMirror typeMirror : superTypeMirrors) {
typeFactory.getEntityType(typeMirror, true);
}
// supertype handling
for (TypeMirror typeMirror : typeMirrors) {
typeFactory.getEntityType(typeMirror, true);
}
for (Element element : elements) {
EntityType model = elementHandler.handleEntityType((TypeElement) element);
registerTypeElement(model.getFullName(), (TypeElement)element);
embeddables.put(model.getFullName(), model);
}
allSupertypes.putAll(embeddables);
// add super type fields
Set<EntityType> handled = new HashSet<EntityType>();
for (EntityType embeddable : embeddables.values()) {
addSupertypeFields(embeddable, allSupertypes, handled);
}
}
private void addAnnotationlessSupertypes(List<TypeMirror> superTypeMirrors,
List<Element> elements, Element element) {
List<TypeElement> elements, TypeElement element) {
// add annotationless supertype
TypeMirror superTypeMirror = ((TypeElement)element).getSuperclass();
TypeMirror superTypeMirror = element.getSuperclass();
while (superTypeMirror != null){
Element superTypeElement = env.getTypeUtils().asElement(superTypeMirror);
TypeElement superTypeElement = (TypeElement) env.getTypeUtils().asElement(superTypeMirror);
if (superTypeElement != null
&& !superTypeElement.toString().startsWith("java.lang.")
&& !hasKnownAnnotation(superTypeElement)) {
typeFactory.getEntityType(superTypeMirror, false);
superTypeMirrors.add(superTypeMirror);
elements.add(superTypeElement);
superTypeMirror = ((TypeElement)superTypeElement).getSuperclass();
superTypeMirror = superTypeElement.getSuperclass();
if (superTypeMirror instanceof NoType) {
superTypeMirror = null;
}
@ -601,112 +570,7 @@ public class Processor {
superTypeMirror = null;
}
}
}
private void processEmbedded() {
List<TypeMirror> typeMirrors = new ArrayList<TypeMirror>();
// only creation
for (Element element : roundEnv.getElementsAnnotatedWith(configuration.getEmbeddedAnnotation())) {
TypeMirror type = element.asType();
if (element.getKind() == ElementKind.METHOD){
type = ((ExecutableElement)element).getReturnType();
}
String typeName = type.toString();
if (typeName.startsWith(Collection.class.getName())
|| typeName.startsWith(List.class.getName())
|| typeName.startsWith(Set.class.getName())) {
type = ((DeclaredType)type).getTypeArguments().get(0);
} else if (typeName.startsWith(Map.class.getName())){
type = ((DeclaredType)type).getTypeArguments().get(1);
}
typeFactory.getEntityType(type, false);
typeMirrors.add(type);
}
// supertype handling
for (TypeMirror typeMirror : typeMirrors) {
typeFactory.getEntityType(typeMirror, true);
}
// deep
for (TypeMirror type : typeMirrors) {
// remove generic signature of type for TypeElement lookup
String typeName = type.toString();
if (typeName.contains("<")) {
typeName = typeName.substring(0, typeName.indexOf('<'));
}
TypeElement typeElement = env.getElementUtils().getTypeElement(typeName);
if (typeElement == null) {
continue;
} else if (typeElement.getAnnotation(configuration.getEntityAnnotation()) != null){
// skip Entity types here
continue;
}
EntityType model = elementHandler.handleEntityType(typeElement);
registerTypeElement(model.getFullName(), typeElement);
embeddables.put(model.getFullName(), model);
}
allSupertypes.putAll(embeddables);
// add super type fields
Set<EntityType> handled = new HashSet<EntityType>();
for (EntityType embeddable : embeddables.values()) {
addSupertypeFields(embeddable, allSupertypes, handled);
}
}
private void processEntities() {
process(configuration.getEntityAnnotation(), entityTypes);
}
@SuppressWarnings("unchecked")
private void processEntitiesFromPackage() {
Class<? extends Annotation> annotation = configuration.getEntitiesAnnotation();
List<TypeMirror> typeMirrors = new ArrayList<TypeMirror>();
// only creation
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
if (mirror.getAnnotationType().asElement().getSimpleName().toString().equals(QueryEntities.class.getSimpleName())) {
for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> entry : mirror.getElementValues().entrySet()) {
if (entry.getKey().getSimpleName().toString().equals("value")) {
List<AnnotationValue> values = (List<AnnotationValue>) entry.getValue().getValue();
for (AnnotationValue value : values) {
TypeMirror type = (TypeMirror) value.getValue();
typeFactory.getEntityType(type, false);
typeMirrors.add(type);
}
}
}
}
}
}
Map<String,EntityType> types = entityTypes;
Deque<Type> superTypes = new ArrayDeque<Type>();
// get annotated types
for (TypeMirror mirror : typeMirrors) {
typeFactory.getEntityType(mirror, true);
TypeElement element = (TypeElement) env.getTypeUtils().asElement(mirror);
EntityType model = elementHandler.handleEntityType(element);
registerTypeElement(model.getFullName(), element);
types.put(model.getFullName(), model);
if (model.getSuperType() != null) {
superTypes.push(model.getSuperType().getType());
}
}
mergeTypes(types, superTypes);
}
private void processSupertypes() {
process(configuration.getSuperTypeAnnotation(), actualSupertypes);
}
}
private void registerTypeElement(String entityName, TypeElement element) {
Set<TypeElement> elements = typeElements.get(entityName);
@ -716,6 +580,73 @@ public class Processor {
}
elements.add(element);
}
// SERIALIZATION
private void serializeTypes() {
if (!actualSupertypes.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Supertypes");
serialize(configuration.getSupertypeSerializer(), actualSupertypes.values());
}
if (!entityTypes.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Entity types");
serialize(configuration.getEntitySerializer(), entityTypes.values());
}
if (!extensionTypes.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Extension types");
serialize(configuration.getEmbeddableSerializer(), extensionTypes.values());
}
if (!embeddables.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Embeddable types");
serialize(configuration.getEmbeddableSerializer(), embeddables.values());
}
if (!projectionTypes.isEmpty()) {
env.getMessager().printMessage(Kind.NOTE, "Serializing Projection types");
serialize(configuration.getDTOSerializer(), projectionTypes.values());
}
}
private void serializeVariableClasses() {
for (Element element : getElements(Variables.class)) {
if (element instanceof PackageElement) {
Variables vars = element.getAnnotation(Variables.class);
PackageElement packageElement = (PackageElement)element;
List<EntityType> models = new ArrayList<EntityType>();
for (EntityType model : entityTypes.values()) {
if (model.getPackageName().equals(packageElement.getQualifiedName().toString())) {
models.add(model);
}
}
serializeVariableList(packageElement.getQualifiedName().toString(), vars, models);
}
}
}
@Nullable
private FileObject getSourceFile(String fullName) throws IOException {
Elements elementUtils = env.getElementUtils();
TypeElement sourceElement = elementUtils.getTypeElement(fullName);
if (sourceElement == null) {
return null;
} else {
if (sourceElement.getNestingKind().isNested()) {
sourceElement = (TypeElement) sourceElement.getEnclosingElement();
}
PackageElement packageElement = elementUtils.getPackageOf(sourceElement);
try {
return env.getFiler().getResource(StandardLocation.SOURCE_PATH,
packageElement.getQualifiedName(),
sourceElement.getSimpleName() + ".java");
} catch(Exception e) {
return null;
}
}
}
private void serialize(Serializer serializer, Collection<EntityType> models) {
Messager msg = env.getMessager();

View File

@ -34,14 +34,13 @@ import com.mysema.query.codegen.TypeMappings;
import com.mysema.util.BeanUtils;
/**
* ElementHandler is a an APT visitor for entity types
* TypeElementHandler is a an APT visitor for entity types
*
* @author tiwe
*
*/
@Immutable
// TODO : rename
public final class ElementHandler{
public final class TypeElementHandler {
private final TypeMappings typeMappings;
@ -51,7 +50,7 @@ public final class ElementHandler{
private final ExtendedTypeFactory typeFactory;
public ElementHandler(Configuration configuration, ExtendedTypeFactory typeFactory,
public TypeElementHandler(Configuration configuration, ExtendedTypeFactory typeFactory,
TypeMappings typeMappings, QueryTypeFactory queryTypeFactory) {
this.configuration = configuration;
this.typeFactory = typeFactory;

View File

@ -1,49 +1,52 @@
package com.mysema.query.apt;
import javax.annotation.Nullable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ErrorType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.NoType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.NullType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.AbstractTypeVisitor6;
public class TypeExtractor {
/**
* @author tiwe
*
*/
public class TypeExtractor extends AbstractTypeVisitor6<TypeElement, Void> {
private final boolean skipPrimitive, skipEnum;
private final boolean skipEnum;
public TypeExtractor(boolean skipPrimitive, boolean skipEnum) {
this.skipPrimitive = skipPrimitive;
public TypeExtractor(boolean skipEnum) {
this.skipEnum = skipEnum;
}
@Nullable
public TypeElement handle(TypeMirror typeMirror) {
if (typeMirror instanceof DeclaredType) {
return handleDeclaredType((DeclaredType)typeMirror);
} else if (typeMirror instanceof TypeVariable) {
return handleTypeVariable((TypeVariable)typeMirror);
} else if (typeMirror instanceof WildcardType) {
return handleWildcard((WildcardType)typeMirror);
} else if (typeMirror instanceof ArrayType) {
ArrayType t = (ArrayType)typeMirror;
return handle(t.getComponentType());
} else if (typeMirror instanceof NoType) {
return null;
} else {
return null;
}
@Override
public TypeElement visitPrimitive(PrimitiveType t, Void p) {
return null;
}
@Nullable
private TypeElement handleDeclaredType(DeclaredType typeMirror) {
if (typeMirror.asElement() instanceof TypeElement) {
TypeElement typeElement = (TypeElement)typeMirror.asElement();
@Override
public TypeElement visitNull(NullType t, Void p) {
return null;
}
@Override
public TypeElement visitArray(ArrayType t, Void p) {
return visit(t.getComponentType());
}
@Override
public TypeElement visitDeclared(DeclaredType t, Void p) {
if (t.asElement() instanceof TypeElement) {
TypeElement typeElement = (TypeElement)t.asElement();
switch (typeElement.getKind()) {
case ENUM: return handleEnumType(typeMirror, typeElement);
case CLASS: return handleClassType(typeMirror, typeElement);
case INTERFACE: return handleInterfaceType(typeMirror, typeElement);
case ENUM: return skipEnum ? null : typeElement;
case CLASS: return typeElement;
case INTERFACE: return visit(t.getTypeArguments().get(t.getTypeArguments().size()-1));
default: throw new IllegalArgumentException("Illegal type " + typeElement);
}
} else {
@ -51,41 +54,34 @@ public class TypeExtractor {
}
}
@Nullable
private TypeElement handleWildcard(WildcardType typeMirror) {
return handle(typeMirror.getExtendsBound());
@Override
public TypeElement visitError(ErrorType t, Void p) {
return visitDeclared(t, p);
}
@Nullable
private TypeElement handleTypeVariable(TypeVariable typeMirror) {
if (typeMirror.getUpperBound() != null) {
return handle(typeMirror.getUpperBound());
@Override
public TypeElement visitTypeVariable(TypeVariable t, Void p) {
if (t.getUpperBound() != null) {
return visit(t.getUpperBound());
} else {
return handle(typeMirror.getLowerBound());
return visit(t.getLowerBound());
}
}
@Nullable
private TypeElement handleInterfaceType(DeclaredType typeMirror, TypeElement typeElement) {
return handle(typeMirror.getTypeArguments().get(typeMirror.getTypeArguments().size()-1));
@Override
public TypeElement visitWildcard(WildcardType t, Void p) {
return visit(t.getExtendsBound());
}
@Nullable
private TypeElement handleClassType(DeclaredType typeMirror, TypeElement typeElement) {
if (skipPrimitive && typeMirror.getKind().isPrimitive()) {
return null;
} else {
return typeElement;
}
@Override
public TypeElement visitExecutable(ExecutableType t, Void p) {
return null;
}
@Nullable
private TypeElement handleEnumType(DeclaredType typeMirror, TypeElement typeElement) {
if (skipEnum) {
return null;
} else {
return typeElement;
}
@Override
public TypeElement visitNoType(NoType t, Void p) {
return null;
}
}

View File

@ -15,33 +15,33 @@ public enum VisitorConfig {
/**
* visit both fields and getters
*/
ALL(true,true),
ALL(true, true, true),
/**
* visit fields only
*/
FIELDS_ONLY(true,false),
FIELDS_ONLY(true, false, true),
/**
* visit methods only
*/
METHODS_ONLY(false,true),
METHODS_ONLY(false, true, true),
/**
* visit none
*/
NONE(false,false);
NONE(false, false, false);
private final boolean visitFieldProperties, visitMethodProperties;
private final boolean visitFieldProperties, visitMethodProperties, visitConstructors;
VisitorConfig(boolean fields, boolean methods) {
VisitorConfig(boolean fields, boolean methods, boolean constructors) {
this.visitFieldProperties = fields;
this.visitMethodProperties = methods;
this.visitConstructors = constructors;
}
public boolean visitConstructors() {
// TODO : parametrize!
return true;
return visitConstructors;
}
public boolean visitFieldProperties() {