This commit is contained in:
Timo Westkämper 2009-09-10 06:36:27 +00:00
parent 6e3598cca4
commit fb23ef572a
9 changed files with 312 additions and 127 deletions

View File

@ -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<? extends Annotation> entityAnn, superTypeAnn, embeddableAnn, dtoAnn, skipAnn;
private boolean useFields = true, useGetters = true;
public Configuration(
Class<? extends Annotation> entityAnn,
Class<? extends Annotation> superTypeAnn,
Class<? extends Annotation> embeddableAnn,
Class<? extends Annotation> dtoAnn,
Class<? extends Annotation> skipAnn) {
this.entityAnn = Assert.notNull(entityAnn);
this.superTypeAnn = superTypeAnn;
this.embeddableAnn = embeddableAnn;
this.dtoAnn = dtoAnn;
this.skipAnn = skipAnn;
}
public VisitorConfig getConfig(TypeElement e, List<? extends Element> 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<? extends Annotation> getEntityAnn() {
return entityAnn;
}
public Class<? extends Annotation> getSuperTypeAnn() {
return superTypeAnn;
}
public Class<? extends Annotation> getEmbeddableAnn() {
return embeddableAnn;
}
public Class<? extends Annotation> getDtoAnn() {
return dtoAnn;
}
public Class<? extends Annotation> 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;
}
}

View File

@ -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<ClassModel, Void>{
@Immutable
public final class DTOElementVisitor extends SimpleElementVisitor6<ClassModel, Void>{
private final ProcessingEnvironment env;
@ -30,10 +33,13 @@ public abstract class DTOElementVisitor extends SimpleElementVisitor6<ClassModel
private final APTModelFactory typeFactory;
private ClassModelFactory classModelFactory;
private final ClassModelFactory classModelFactory;
DTOElementVisitor(ProcessingEnvironment env, String namePrefix, ClassModelFactory classModelFactory, APTModelFactory typeFactory){
private final Configuration configuration;
DTOElementVisitor(ProcessingEnvironment env, Configuration configuration, String namePrefix, ClassModelFactory classModelFactory, APTModelFactory typeFactory){
this.env = env;
this.configuration = configuration;
this.namePrefix = namePrefix;
this.classModelFactory = classModelFactory;
this.typeFactory = typeFactory;
@ -48,7 +54,7 @@ public abstract class DTOElementVisitor extends SimpleElementVisitor6<ClassModel
// CONSTRUCTOR
for (ExecutableElement constructor : ElementFilter.constructorsIn(elements)){
if (isValidConstructor(constructor)){
if (configuration.isValidConstructor(constructor)){
List<ParameterModel> parameters = new ArrayList<ParameterModel>(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<ClassModel
}
return classModel;
}
protected abstract boolean isValidConstructor(ExecutableElement constructor);
}

View File

@ -11,6 +11,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 org.apache.commons.lang.StringUtils;
import com.mysema.query.codegen.ClassModel;
@ -22,7 +24,8 @@ import com.mysema.query.codegen.TypeModel;
* @author tiwe
*
*/
public abstract class EntityElementVisitor extends SimpleElementVisitor6<ClassModel, Void>{
@Immutable
public final class EntityElementVisitor extends SimpleElementVisitor6<ClassModel, Void>{
private final ProcessingEnvironment env;
@ -30,10 +33,13 @@ public abstract class EntityElementVisitor extends SimpleElementVisitor6<ClassMo
private final APTModelFactory typeFactory;
private ClassModelFactory classModelFactory;
private final ClassModelFactory classModelFactory;
EntityElementVisitor(ProcessingEnvironment env, String namePrefix, ClassModelFactory classModelFactory, APTModelFactory typeFactory){
private final Configuration configuration;
EntityElementVisitor(ProcessingEnvironment env, Configuration conf, String namePrefix, ClassModelFactory classModelFactory, APTModelFactory typeFactory){
this.env = env;
this.configuration = conf;
this.namePrefix = namePrefix;
this.classModelFactory = classModelFactory;
this.typeFactory = typeFactory;
@ -46,47 +52,62 @@ public abstract class EntityElementVisitor extends SimpleElementVisitor6<ClassMo
TypeModel c = typeFactory.create(e.asType(), elementUtils);
ClassModel classModel = new ClassModel(classModelFactory, namePrefix, sc.getName(), c.getPackageName(), c.getName(), c.getSimpleName());
List<? extends Element> 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);
}

View File

@ -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<? extends Annotation> 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<? extends Annotation> entityAnn,
Class<? extends Annotation> superTypeAnn,
Class<? extends Annotation> embeddableAnn,
Class<? extends Annotation> dtoAnn,
Class<? extends Annotation> 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<? extends Annotation>[] 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<String, ClassModel> superTypes = new HashMap<String, ClassModel>();
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<String, ClassModel> entityTypes = new HashMap<String, ClassModel>();
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<String, ClassModel> embeddables = new HashMap<String, ClassModel>();
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<String, ClassModel> dtos = new HashMap<String, ClassModel>();
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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Class<? extends Annotation>> annotations;
@SuppressWarnings("unchecked")
public JPAConfiguration(Class<? extends Annotation> entityAnn,
Class<? extends Annotation> superTypeAnn,
Class<? extends Annotation> embeddableAnn,
Class<? extends Annotation> dtoAnn,
Class<? extends Annotation> skipAnn) throws ClassNotFoundException {
super(entityAnn, superTypeAnn, embeddableAnn, dtoAnn, skipAnn);
this.annotations = new ArrayList<Class<? extends Annotation>>();
for (String simpleName : Arrays.asList(
"Column",
"Embedded",
"EmbeddedId",
"GeneratedValue",
"Id",
"JoinColumn",
"ManyToOne",
"OneToMany",
"PrimaryKeyJoinColumn")){
annotations.add((Class<? extends Annotation>) Class.forName("javax.persistence."+simpleName));
}
}
@Override
public VisitorConfig getConfig(TypeElement e, List<? extends Element> 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<? extends Annotation> annotation : annotations){
if (element.getAnnotation(annotation) != null){
return true;
}
}
return false;
}
}