com.mysema.query.apt.Processor Maven / Gradle / Ivy
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.apt;
import java.io.IOException;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
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.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
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.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.tools.JavaFileObject;
import javax.tools.Diagnostic.Kind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mysema.codegen.JavaWriter;
import com.mysema.codegen.model.Parameter;
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.QueryExtensions;
import com.mysema.query.annotations.QueryMethod;
import com.mysema.query.annotations.QueryProjection;
import com.mysema.query.annotations.QuerydslVariables;
import com.mysema.query.codegen.Delegate;
import com.mysema.query.codegen.EntityType;
import com.mysema.query.codegen.Method;
import com.mysema.query.codegen.Serializer;
import com.mysema.query.codegen.SerializerConfig;
import com.mysema.query.codegen.Supertype;
import com.mysema.query.codegen.TypeFactory;
import com.mysema.query.codegen.TypeMappings;
/**
* Processor handles the actual work in the Querydsl APT module
*
* @author tiwe
*
*/
public class Processor {
private static final Logger logger = LoggerFactory.getLogger(Processor.class);
private final Map actualSupertypes = new HashMap();
private final Map allSupertypes = new HashMap();
private final Configuration configuration;
private final Map dtos = new HashMap();
private final ElementHandler elementHandler;
private final Map embeddables = new HashMap();
private final Map entityTypes = new HashMap();
private final ProcessingEnvironment env;
private final Map extensionTypes = new HashMap();
private final RoundEnvironment roundEnv;
private final APTTypeFactory typeModelFactory;
public Processor(ProcessingEnvironment env, RoundEnvironment roundEnv, Configuration configuration) {
this.env = Assert.notNull(env,"env");
this.roundEnv = Assert.notNull(roundEnv,"roundEnv");
this.configuration = Assert.notNull(configuration,"configuration");
List> anns = new ArrayList>();
anns.add(configuration.getEntityAnn());
if (configuration.getSuperTypeAnn() != null){
anns.add(configuration.getSuperTypeAnn());
}
if (configuration.getEmbeddableAnn() != null){
anns.add(configuration.getEmbeddableAnn());
}
TypeFactory factory = new TypeFactory(anns);
this.typeModelFactory = new APTTypeFactory(env, configuration, factory, anns);
this.elementHandler = new ElementHandler(configuration, typeModelFactory);
}
private void addSupertypeFields(EntityType model, Map superTypes, Set handled) {
if (handled.add(model)){
for (Supertype supertype : model.getSuperTypes()){
EntityType entityType = superTypes.get(supertype.getType().getFullName());
if (entityType != null){
addSupertypeFields(entityType, superTypes, handled);
supertype.setEntityType(entityType);
model.include(supertype);
}
}
}
}
private void handleExtensionType(TypeMirror type, Element element) {
EntityType entityModel = typeModelFactory.createEntityType(type);
// handle methods
Set queryMethods = new HashSet();
for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())){
if (method.getAnnotation(QueryMethod.class) != null){
elementHandler.handleQueryMethod(entityModel, method, queryMethods);
}
}
for (Method method : queryMethods){
entityModel.addMethod(method);
}
extensionTypes.put(entityModel.getFullName(), entityModel);
}
public void process() {
// process delegate methods
processDelegateMethods();
// process types
processCustomTypes();
processExtensions();
if (configuration.getSuperTypeAnn() != null) {
processSupertypes();
}
processEntities();
if (configuration.getEmbeddableAnn() != null){
processEmbeddables();
}
processDTOs();
// remove entity types from extensionTypes
for (String key : entityTypes.keySet()){
extensionTypes.remove(key);
}
// serialize models
Messager msg = env.getMessager();
if (!actualSupertypes.isEmpty()){
msg.printMessage(Kind.NOTE, "Serializing Supertypes");
serialize(configuration.getSupertypeSerializer(), actualSupertypes.values());
}
if (!entityTypes.isEmpty()){
msg.printMessage(Kind.NOTE, "Serializing Entity types");
serialize(configuration.getEntitySerializer(), entityTypes.values());
}
if (!extensionTypes.isEmpty()){
msg.printMessage(Kind.NOTE, "Serializing Extension types");
serialize(configuration.getEmbeddableSerializer(), extensionTypes.values());
}
if (!embeddables.isEmpty()){
msg.printMessage(Kind.NOTE, "Serializing Embeddable types");
serialize(configuration.getEmbeddableSerializer(), embeddables.values());
}
if (!dtos.isEmpty()){
msg.printMessage(Kind.NOTE, "Serializing DTO types");
serialize(configuration.getDTOSerializer(), dtos.values());
}
// serialize variable classes
for (Element element : roundEnv.getElementsAnnotatedWith(QuerydslVariables.class)){
if (element instanceof PackageElement){
QuerydslVariables vars = element.getAnnotation(QuerydslVariables.class);
PackageElement packageElement = (PackageElement)element;
List models = new ArrayList();
for (EntityType model : entityTypes.values()){
if (model.getPackageName().equals(packageElement.getQualifiedName().toString())){
models.add(model);
}
}
serializeVariableList(packageElement.getQualifiedName().toString(), vars, models);
}
}
}
private void process(Class extends Annotation> annotation, Map types){
Deque superTypes = new ArrayDeque();
// FIXME
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
if (configuration.getEmbeddableAnn() == null
|| element.getAnnotation(configuration.getEmbeddableAnn()) == null){
typeModelFactory.createEntityType(element.asType());
}
}
// get annotated types
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
if (configuration.getEmbeddableAnn() == null
|| element.getAnnotation(configuration.getEmbeddableAnn()) == null){
EntityType model = elementHandler.handleNormalType((TypeElement) element);
types.put(model.getFullName(), model);
if (model.getSuperType() != null){
superTypes.push(model.getSuperType().getType());
}
}
}
// get external supertypes
while (!superTypes.isEmpty()){
Type superType = superTypes.pop();
if (!types.containsKey(superType.getFullName()) && !allSupertypes.containsKey(superType.getFullName())){
TypeElement typeElement = env.getElementUtils().getTypeElement(superType.getFullName());
EntityType entityType = elementHandler.handleNormalType(typeElement);
if (entityType.getSuperType() != null){
superTypes.push(entityType.getSuperType().getType());
}
types.put(superType.getFullName(), entityType);
}
}
allSupertypes.putAll(types);
// add supertype fields
Set handled = new HashSet();
for (EntityType type : types.values()) {
addSupertypeFields(type, allSupertypes, handled);
}
}
private void processCustomTypes() {
for (Element queryMethod : roundEnv.getElementsAnnotatedWith(QueryMethod.class)){
Element element = queryMethod.getEnclosingElement();
if (element.getAnnotation(QueryExtensions.class) != null){
continue;
}else if (element.getAnnotation(configuration.getEntityAnn()) != null){
continue;
}else if (configuration.getSuperTypeAnn() != null && element.getAnnotation(configuration.getSuperTypeAnn()) != null){
continue;
}else if (configuration.getEmbeddableAnn() != null && element.getAnnotation(configuration.getEmbeddableAnn()) != null){
continue;
}
handleExtensionType(element.asType(), element);
}
}
private void processDelegateMethods(){
Set types = new HashSet();
for (Element delegateMethod : roundEnv.getElementsAnnotatedWith(QueryDelegate.class)){
ExecutableElement method = (ExecutableElement)delegateMethod;
Element element = delegateMethod.getEnclosingElement();
String name = method.getSimpleName().toString();
Type delegateType = typeModelFactory.create(element.asType());
Type returnType = typeModelFactory.create(method.getReturnType());
List parameters = elementHandler.transformParams(method.getParameters());
// remove first element
parameters = parameters.subList(1, parameters.size());
EntityType entityType = null;
for (AnnotationMirror annotation : delegateMethod.getAnnotationMirrors()){
if (annotation.getAnnotationType().asElement().getSimpleName().toString().equals(QueryDelegate.class.getSimpleName())){
for (Map.Entry extends ExecutableElement,? extends AnnotationValue> entry : annotation.getElementValues().entrySet()){
if (entry.getKey().getSimpleName().toString().equals("value")){
if (entry.getValue().getValue() instanceof TypeMirror){
TypeMirror type = (TypeMirror)entry.getValue().getValue();
entityType = typeModelFactory.createEntityType(type);
}
}
}
}
}
if (entityType != null){
entityType.addDelegate(new Delegate(entityType, delegateType, name, parameters, returnType));
types.add(entityType);
}
}
for (EntityType type : types){
if (type.getOriginalCategory() != TypeCategory.SIMPLE){
extensionTypes.put(type.getFullName(), type);
}
}
}
private void processDTOs() {
Set visitedDTOTypes = new HashSet();
for (Element element : roundEnv.getElementsAnnotatedWith(QueryProjection.class)) {
Element parent = element.getEnclosingElement();
if (parent.getAnnotation(configuration.getEntityAnn()) == null
&& parent.getAnnotation(configuration.getEmbeddableAnn()) == null
&& !visitedDTOTypes.contains(parent)){
EntityType model = elementHandler.handleProjectionType((TypeElement)parent);
dtos.put(model.getFullName(), model);
visitedDTOTypes.add(parent);
}
}
}
private void processEmbeddables() {
// FIXME
for (Element element : roundEnv.getElementsAnnotatedWith(configuration.getEmbeddableAnn())) {
typeModelFactory.create(element.asType());
}
for (Element element : roundEnv.getElementsAnnotatedWith(configuration.getEmbeddableAnn())) {
EntityType model = elementHandler.handleNormalType((TypeElement) element);
embeddables.put(model.getFullName(), model);
}
allSupertypes.putAll(embeddables);
// add super type fields
Set handled = new HashSet();
for (EntityType embeddable : embeddables.values()) {
addSupertypeFields(embeddable, allSupertypes, handled);
}
}
private void processEntities() {
process(configuration.getEntityAnn(), entityTypes);
}
private void processExtensions() {
for (Element element : roundEnv.getElementsAnnotatedWith(QueryExtensions.class)){
for (AnnotationMirror annotation : element.getAnnotationMirrors()){
if (annotation.getAnnotationType().asElement().getSimpleName().toString().equals(QueryExtensions.class.getSimpleName())){
for (Map.Entry extends ExecutableElement,? extends AnnotationValue> entry : annotation.getElementValues().entrySet()){
if (entry.getKey().getSimpleName().toString().equals("value")){
if (entry.getValue().getValue() instanceof TypeMirror){
TypeMirror type = (TypeMirror)entry.getValue().getValue();
handleExtensionType(type, element);
}
}
}
}
}
}
}
private void processSupertypes() {
process(configuration.getSuperTypeAnn(), actualSupertypes);
}
private void serialize(Serializer serializer, Collection models) {
Messager msg = env.getMessager();
for (EntityType model : models) {
msg.printMessage(Kind.NOTE, model.getFullName() + " is processed");
try {
String packageName = model.getPackageName();
String localName = configuration.getTypeMappings().getPathType(model, model, true);
String className = packageName.length() > 0 ? (packageName + "." + localName) : localName;
if (env.getElementUtils().getTypeElement(className) == null){
JavaFileObject fileObject = env.getFiler().createSourceFile(className);
Writer writer = fileObject.openWriter();
try {
SerializerConfig serializerConfig = configuration.getSerializerConfig(model);
serializer.serialize(model, serializerConfig, new JavaWriter(writer));
}finally{
if (writer != null) {
writer.close();
}
}
}else{
msg.printMessage(Kind.NOTE, className + " already available");
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
msg.printMessage(Kind.ERROR, e.getMessage());
}
}
}
private void serializeVariableList(String packageName, QuerydslVariables vars, List models){
String className = packageName + "." + vars.value();
TypeMappings typeMappings = configuration.getTypeMappings();
try{
JavaFileObject fileObject = env.getFiler().createSourceFile(className);
Writer w = fileObject.openWriter();
try{
JavaWriter writer = new JavaWriter(w);
writer.packageDecl(packageName);
if (vars.asInterface()){
writer.beginInterface(vars.value());
}else{
writer.beginClass(vars.value(), null);
}
for (EntityType model : models){
String queryType = typeMappings.getPathType(model, model, true);
String simpleName = model.getUncapSimpleName();
String alias = simpleName;
if (configuration.getKeywords().contains(simpleName.toUpperCase())){
alias += "1";
}
writer.publicStaticFinal(queryType, simpleName, "new " + queryType + "(\"" + alias + "\")");
}
writer.end();
}finally{
w.close();
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
env.getMessager().printMessage(Kind.ERROR, e.getMessage());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy