diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/Configuration.java b/querydsl-apt/src/main/java/com/mysema/query/apt/Configuration.java new file mode 100644 index 000000000..d7a34e54f --- /dev/null +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/Configuration.java @@ -0,0 +1,95 @@ +package com.mysema.query.apt; + +import java.lang.annotation.Annotation; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + +import com.mysema.commons.lang.Assert; + +/** + * @author tiwe + * + */ +public class Configuration { + + protected final Class entityAnn, superTypeAnn, embeddableAnn, dtoAnn, skipAnn; + + private boolean useFields = true, useGetters = true; + + public Configuration( + Class entityAnn, + Class superTypeAnn, + Class embeddableAnn, + Class dtoAnn, + Class skipAnn) { + this.entityAnn = Assert.notNull(entityAnn); + this.superTypeAnn = superTypeAnn; + this.embeddableAnn = embeddableAnn; + this.dtoAnn = dtoAnn; + this.skipAnn = skipAnn; + } + + public VisitorConfig getConfig(TypeElement e, List elements){ + return VisitorConfig.ALL; + } + + public boolean isValidConstructor(ExecutableElement constructor) { + return constructor.getModifiers().contains(Modifier.PUBLIC); + } + + public boolean isValidField(VariableElement field) { + return useFields + && field.getAnnotation(skipAnn) == null + && !field.getModifiers().contains(Modifier.TRANSIENT) + && !field.getModifiers().contains(Modifier.STATIC); + } + + public boolean isValidGetter(ExecutableElement getter){ + return useGetters + && getter.getAnnotation(skipAnn) == null + && !getter.getModifiers().contains(Modifier.STATIC); + } + + public Class getEntityAnn() { + return entityAnn; + } + + public Class getSuperTypeAnn() { + return superTypeAnn; + } + + public Class getEmbeddableAnn() { + return embeddableAnn; + } + + public Class getDtoAnn() { + return dtoAnn; + } + + public Class getSkipAnn() { + return skipAnn; + } + + public boolean isUseFields() { + return useFields; + } + + public boolean isUseGetters() { + return useGetters; + } + + public void setUseGetters(boolean b) { + this.useGetters = b; + } + + public void setUseFields(boolean b){ + this.useFields = b; + } + + +} diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/DTOElementVisitor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/DTOElementVisitor.java index 960063dfc..c8ac2408c 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/DTOElementVisitor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/DTOElementVisitor.java @@ -12,6 +12,8 @@ import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.lang.model.util.SimpleElementVisitor6; +import net.jcip.annotations.Immutable; + import com.mysema.query.codegen.ClassModel; import com.mysema.query.codegen.ClassModelFactory; import com.mysema.query.codegen.ConstructorModel; @@ -22,7 +24,8 @@ import com.mysema.query.codegen.TypeModel; * @author tiwe * */ -public abstract class DTOElementVisitor extends SimpleElementVisitor6{ +@Immutable +public final class DTOElementVisitor extends SimpleElementVisitor6{ private final ProcessingEnvironment env; @@ -30,10 +33,13 @@ public abstract class DTOElementVisitor extends SimpleElementVisitor6 parameters = new ArrayList(constructor.getParameters().size()); for (VariableElement var : constructor.getParameters()){ TypeModel varType = typeFactory.create(var.asType(), elementUtils); @@ -59,7 +65,5 @@ public abstract class DTOElementVisitor extends SimpleElementVisitor6{ +@Immutable +public final class EntityElementVisitor extends SimpleElementVisitor6{ private final ProcessingEnvironment env; @@ -30,10 +33,13 @@ public abstract class EntityElementVisitor extends SimpleElementVisitor6 elements = e.getEnclosedElements(); + + VisitorConfig config = configuration.getConfig(e, elements); - // GETTERS - for (ExecutableElement method : ElementFilter.methodsIn(elements)){ - String name = method.getSimpleName().toString(); - if (name.startsWith("get") && method.getParameters().isEmpty()){ - name = StringUtils.uncapitalize(name.substring(3)); - }else if (name.startsWith("is") && method.getParameters().isEmpty()){ - name = StringUtils.uncapitalize(name.substring(2)); - }else{ - continue; - } - if (isValidGetter(method)){ - try{ - TypeModel typeModel = typeFactory.create(method.getReturnType(), elementUtils); - String docs = elementUtils.getDocComment(method); - classModel.addField(new FieldModel(classModel, name, typeModel, docs)); - - }catch(IllegalArgumentException ex){ - throw new RuntimeException("Caught exception for method " + c.getName()+"#"+method.getSimpleName(), ex); + if (config.isVisitMethods()){ + for (ExecutableElement method : ElementFilter.methodsIn(elements)){ + String name = method.getSimpleName().toString(); + if (name.startsWith("get") && method.getParameters().isEmpty()){ + name = StringUtils.uncapitalize(name.substring(3)); + }else if (name.startsWith("is") && method.getParameters().isEmpty()){ + name = StringUtils.uncapitalize(name.substring(2)); + }else{ + continue; } - } + if (configuration.isValidGetter(method)){ + try{ + TypeModel typeModel = typeFactory.create(method.getReturnType(), elementUtils); +// String docs = elementUtils.getDocComment(method); +// if (docs != null){ +// docs = replacePattern.matcher(docs).replaceAll(" "); +// } + classModel.addField(new FieldModel(classModel, name, typeModel, null)); + + }catch(IllegalArgumentException ex){ + StringBuilder builder = new StringBuilder(); + builder.append("Caught exception for method "); + builder.append(c.getName()).append("#").append(method.getSimpleName()); + throw new RuntimeException(builder.toString(), ex); + } + } + } + } + + + if (config.isVisitFields()){ + for (VariableElement field : ElementFilter.fieldsIn(elements)){ + if (configuration.isValidField(field)){ + try{ + TypeModel typeModel = typeFactory.create(field.asType(), elementUtils); + String name = field.getSimpleName().toString(); +// String docs = elementUtils.getDocComment(field); +// if (docs != null){ +// docs = replacePattern.matcher(docs).replaceAll(" "); +// } + classModel.addField(new FieldModel(classModel, name, typeModel, null)); + }catch(IllegalArgumentException ex){ + StringBuilder builder = new StringBuilder(); + builder.append("Caught exception for field "); + builder.append(c.getName()).append("#").append(field.getSimpleName()); + throw new RuntimeException(builder.toString(), ex); + } + + } + } } - // FIELDS - for (VariableElement field : ElementFilter.fieldsIn(elements)){ - if (isValidField(field)){ - try{ - TypeModel typeModel = typeFactory.create(field.asType(), elementUtils); - String name = field.getSimpleName().toString(); - String docs = elementUtils.getDocComment(field); - classModel.addField(new FieldModel(classModel, name, typeModel, docs)); - }catch(IllegalArgumentException ex){ - throw new RuntimeException("Caught exception for field " + c.getName()+"#"+field.getSimpleName(), ex); - } - - } - } return classModel; } - protected abstract boolean isValidGetter(ExecutableElement method); - - protected abstract boolean isValidField(VariableElement field); } diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/Processor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/Processor.java index 0b9b1a303..2815f41a1 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/Processor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/Processor.java @@ -15,12 +15,11 @@ import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.VariableElement; import javax.tools.JavaFileObject; import javax.tools.Diagnostic.Kind; +import net.jcip.annotations.Immutable; + import com.mysema.commons.lang.Assert; import com.mysema.query.codegen.ClassModel; import com.mysema.query.codegen.ClassModelFactory; @@ -33,10 +32,9 @@ import com.mysema.query.codegen.TypeModelFactory; * @author tiwe * */ +@Immutable public class Processor { - private final Class entityAnn, superTypeAnn, embeddableAnn, dtoAnn, skipAnn; - private final ProcessingEnvironment env; private final APTModelFactory typeFactory; @@ -45,69 +43,31 @@ public class Processor { private final String namePrefix = "Q"; - private boolean useFields = true, useGetters = true; + private final Configuration conf; @SuppressWarnings("unchecked") - public Processor(ProcessingEnvironment env, - Class entityAnn, - Class superTypeAnn, - Class embeddableAnn, - Class dtoAnn, - Class skipAnn) { - this.env = Assert.notNull(env); - this.entityAnn = Assert.notNull(entityAnn); - this.superTypeAnn = superTypeAnn; - this.embeddableAnn = embeddableAnn; - this.dtoAnn = dtoAnn; - this.skipAnn = skipAnn; + public Processor(ProcessingEnvironment env, Configuration configuration) { + this.conf = configuration; Class[] anns ; - if (embeddableAnn != null){ - anns = new Class[]{entityAnn, embeddableAnn}; + if (conf.getEmbeddableAnn() != null){ + anns = new Class[]{conf.getEntityAnn(), conf.getEmbeddableAnn()}; }else{ - anns = new Class[]{entityAnn}; + anns = new Class[]{conf.getEntityAnn()}; } + this.env = Assert.notNull(env); TypeModelFactory factory = new TypeModelFactory(anns); this.typeFactory = new APTModelFactory(factory, Arrays.asList(anns)); this.classModelFactory = new ClassModelFactory(factory); } - protected boolean isValidConstructor(ExecutableElement constructor) { - return constructor.getModifiers().contains(Modifier.PUBLIC); - } - - protected boolean isValidField(VariableElement field) { - return useFields - && field.getAnnotation(skipAnn) == null - && !field.getModifiers().contains(Modifier.TRANSIENT) - && !field.getModifiers().contains(Modifier.STATIC); - } - - protected boolean isValidGetter(ExecutableElement getter){ - return useGetters - && getter.getAnnotation(skipAnn) == null - && !getter.getModifiers().contains(Modifier.STATIC); - } - public void process(RoundEnvironment roundEnv) { Map superTypes = new HashMap(); - EntityElementVisitor entityVisitor = new EntityElementVisitor(env, namePrefix, classModelFactory, typeFactory){ - @Override - protected boolean isValidField(VariableElement field) { - return Processor.this.isValidField(field); - } - - @Override - protected boolean isValidGetter(ExecutableElement method) { - return Processor.this.isValidGetter(method); - } - - }; + EntityElementVisitor entityVisitor = new EntityElementVisitor(env, conf, namePrefix, classModelFactory, typeFactory); // populate super type mappings - if (superTypeAnn != null) { - for (Element element : roundEnv.getElementsAnnotatedWith(superTypeAnn)) { -// ClassModel model = getClassModel(element); + if (conf.getSuperTypeAnn() != null) { + for (Element element : roundEnv.getElementsAnnotatedWith(conf.getSuperTypeAnn())) { ClassModel model = element.accept(entityVisitor, null); superTypes.put(model.getName(), model); } @@ -117,7 +77,7 @@ public class Processor { // populate entity type mappings Map entityTypes = new HashMap(); - for (Element element : roundEnv.getElementsAnnotatedWith(entityAnn)) { + for (Element element : roundEnv.getElementsAnnotatedWith(conf.getEntityAnn())) { ClassModel model = element.accept(entityVisitor, null); entityTypes.put(model.getName(), model); } @@ -132,10 +92,10 @@ public class Processor { // EMBEDDABLES (optional) - if (embeddableAnn != null){ + if (conf.getEmbeddableAnn() != null){ // populate entity type mappings Map embeddables = new HashMap(); - for (Element element : roundEnv.getElementsAnnotatedWith(embeddableAnn)) { + for (Element element : roundEnv.getElementsAnnotatedWith(conf.getEmbeddableAnn())) { ClassModel model = element.accept(entityVisitor, null); embeddables.put(model.getName(), model); } @@ -151,16 +111,10 @@ public class Processor { // DTOS (optional) - if (dtoAnn != null){ - DTOElementVisitor dtoVisitor = new DTOElementVisitor(env, namePrefix, classModelFactory, typeFactory){ - @Override - protected boolean isValidConstructor(ExecutableElement constructor) { - return Processor.this.isValidConstructor(constructor); - } - - }; + if (conf.getDtoAnn() != null){ + DTOElementVisitor dtoVisitor = new DTOElementVisitor(env, conf, namePrefix, classModelFactory, typeFactory); Map dtos = new HashMap(); - for (Element element : roundEnv.getElementsAnnotatedWith(dtoAnn)) { + for (Element element : roundEnv.getElementsAnnotatedWith(conf.getDtoAnn())) { ClassModel model = element.accept(dtoVisitor, null); dtos.put(model.getName(), model); } @@ -192,14 +146,4 @@ public class Processor { } } - public Processor setUseFields(boolean useFields){ - this.useFields = useFields; - return this; - } - - public Processor setUseGetters(boolean useGetters) { - this.useGetters = useGetters; - return this; - } - } diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/QuerydslAnnotationProcessor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/QuerydslAnnotationProcessor.java index 1f7b588b7..2e442a7a1 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/QuerydslAnnotationProcessor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/QuerydslAnnotationProcessor.java @@ -41,8 +41,9 @@ public class QuerydslAnnotationProcessor extends AbstractProcessor{ dto = Projection.class; skip = Transient.class; - Processor p = new Processor(processingEnv, entity, superType, embeddable, dto, skip); - p.process(roundEnv); + Configuration configuration = new Configuration(entity, superType, embeddable, dto, skip); + Processor processor = new Processor(processingEnv, configuration); + processor.process(roundEnv); return true; } diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/VisitorConfig.java b/querydsl-apt/src/main/java/com/mysema/query/apt/VisitorConfig.java new file mode 100644 index 000000000..e6016bbbc --- /dev/null +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/VisitorConfig.java @@ -0,0 +1,37 @@ +package com.mysema.query.apt; + +/** + * @author tiwe + * + */ +public enum VisitorConfig { + /** + * + */ + ALL(true,true), + /** + * + */ + FIELDS_ONLY(true,false), + /** + * + */ + METHODS_ONLY(false,true); + + private final boolean fields, methods; + + VisitorConfig(boolean fields, boolean methods){ + this.fields = fields; + this.methods = methods; + } + + public boolean isVisitFields(){ + return fields; + } + + public boolean isVisitMethods(){ + return methods; + } + + +} diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/jdo/JDOAnnotationProcessor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/jdo/JDOAnnotationProcessor.java index 090b55628..b6feff2e7 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/jdo/JDOAnnotationProcessor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/jdo/JDOAnnotationProcessor.java @@ -12,6 +12,7 @@ import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import com.mysema.query.annotations.Projection; +import com.mysema.query.apt.Configuration; import com.mysema.query.apt.Processor; /** @@ -35,8 +36,10 @@ public class JDOAnnotationProcessor extends AbstractProcessor{ dto = Projection.class; skip = (Class)Class.forName("javax.jdo.annotations.NotPersistent"); - Processor p = new Processor(processingEnv, entity, superType, embeddable, dto, skip); - p.setUseGetters(false).process(roundEnv); + Configuration configuration = new Configuration(entity, superType, embeddable, dto, skip); + configuration.setUseGetters(false); + Processor processor = new Processor(processingEnv, configuration); + processor.process(roundEnv); return true; } catch (ClassNotFoundException e) { diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAAnnotationProcessor.java b/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAAnnotationProcessor.java index 8998e09e9..d0b1909e6 100644 --- a/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAAnnotationProcessor.java +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAAnnotationProcessor.java @@ -12,6 +12,7 @@ import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import com.mysema.query.annotations.Projection; +import com.mysema.query.apt.Configuration; import com.mysema.query.apt.Processor; /** @@ -35,8 +36,9 @@ public class JPAAnnotationProcessor extends AbstractProcessor{ dto = Projection.class; skip = (Class)Class.forName("javax.persistence.Transient"); - Processor p = new Processor(processingEnv, entity, superType, embeddable, dto, skip); - p.process(roundEnv); + Configuration configuration = new JPAConfiguration(entity, superType, embeddable, dto, skip); + Processor processor = new Processor(processingEnv, configuration); + processor.process(roundEnv); return true; } catch (ClassNotFoundException e) { diff --git a/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAConfiguration.java b/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAConfiguration.java new file mode 100644 index 000000000..400000c11 --- /dev/null +++ b/querydsl-apt/src/main/java/com/mysema/query/apt/jpa/JPAConfiguration.java @@ -0,0 +1,78 @@ +package com.mysema.query.apt.jpa; + +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; + +import com.mysema.query.apt.Configuration; +import com.mysema.query.apt.VisitorConfig; + +/** + * @author tiwe + * + */ +public class JPAConfiguration extends Configuration { + + private List> annotations; + + @SuppressWarnings("unchecked") + public JPAConfiguration(Class entityAnn, + Class superTypeAnn, + Class embeddableAnn, + Class dtoAnn, + Class skipAnn) throws ClassNotFoundException { + super(entityAnn, superTypeAnn, embeddableAnn, dtoAnn, skipAnn); + this.annotations = new ArrayList>(); + for (String simpleName : Arrays.asList( + "Column", + "Embedded", + "EmbeddedId", + "GeneratedValue", + "Id", + "JoinColumn", + "ManyToOne", + "OneToMany", + "PrimaryKeyJoinColumn")){ + annotations.add((Class) Class.forName("javax.persistence."+simpleName)); + } + } + + @Override + public VisitorConfig getConfig(TypeElement e, List elements){ + boolean fields = false, methods = false; + for (Element element : elements){ + if (element.getKind().equals(ElementKind.FIELD) ){ + if (!fields && hasJPAAnnotation(element)){ + fields = true; + } + }else if (element.getKind().equals(ElementKind.METHOD)){ + if (!methods && hasJPAAnnotation(element)){ + methods = true; + } + } + } + if (fields && !methods){ + return VisitorConfig.FIELDS_ONLY; + }else if (methods && !fields){ + return VisitorConfig.METHODS_ONLY; + }else{ + return VisitorConfig.ALL; + } + + } + + private boolean hasJPAAnnotation(Element element){ + for (Class annotation : annotations){ + if (element.getAnnotation(annotation) != null){ + return true; + } + } + return false; + } + +}