added improved support for custom literal types

added improved support for interface based entity types
This commit is contained in:
Timo Westkämper 2009-10-20 09:10:46 +00:00
parent 74270a7faf
commit 453a2e8dbb
12 changed files with 203 additions and 92 deletions

View File

@ -12,6 +12,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
@ -39,6 +40,8 @@ import com.mysema.query.util.TypeUtil;
*/
public class APTModelFactory implements TypeVisitor<TypeModel,Elements> {
private final ProcessingEnvironment env;
private final TypeModelFactory factory;
private final TypeModel defaultValue;
@ -47,10 +50,15 @@ public class APTModelFactory implements TypeVisitor<TypeModel,Elements> {
private final List<Class<? extends Annotation>> entityAnnotations;
public APTModelFactory(TypeModelFactory factory, List<Class<? extends Annotation>> annotations){
private final TypeElement numberType, comparableType;
public APTModelFactory(ProcessingEnvironment env, TypeModelFactory factory, List<Class<? extends Annotation>> annotations){
this.env = env;
this.factory = factory;
this.defaultValue = factory.create(Object.class);
this.entityAnnotations = annotations;
this.numberType = env.getElementUtils().getTypeElement(Number.class.getName());
this.comparableType = env.getElementUtils().getTypeElement(Comparable.class.getName());
}
public TypeModel create(TypeMirror type, Elements el){
@ -95,6 +103,13 @@ public class APTModelFactory implements TypeVisitor<TypeModel,Elements> {
}
private TypeModel createInterfaceType(DeclaredType t, TypeElement typeElement, Elements p) {
// entity type
for (Class<? extends Annotation> entityAnn : entityAnnotations){
if (typeElement.getAnnotation(entityAnn) != null){
return create(typeElement, TypeCategory.ENTITY, p);
}
}
String name = typeElement.getQualifiedName().toString();
String simpleName = typeElement.getSimpleName().toString();
Iterator<? extends TypeMirror> i = t.getTypeArguments().iterator();
@ -136,16 +151,30 @@ public class APTModelFactory implements TypeVisitor<TypeModel,Elements> {
// other
String name = typeElement.getQualifiedName().toString();
TypeCategory typeCategory = TypeCategory.get(name);
if (!typeCategory.isSubCategoryOf(TypeCategory.COMPARABLE)){
for(TypeMirror iface : typeElement.getInterfaces()){
if (iface.toString().contains("java.lang.Comparable")){
typeCategory = TypeCategory.COMPARABLE;
}
}
if (typeCategory != TypeCategory.NUMERIC
&& isAssignable(typeElement, comparableType)
&& isSubType(typeElement, numberType)){
typeCategory = TypeCategory.NUMERIC;
}else if (!typeCategory.isSubCategoryOf(TypeCategory.COMPARABLE)
&& isAssignable(typeElement, comparableType)){
typeCategory = TypeCategory.COMPARABLE;
}
return create(typeElement, typeCategory, p);
}
private boolean isSubType(TypeElement type1, TypeElement type2) {
return env.getTypeUtils().isSubtype(type1.asType(), type2.asType());
}
private boolean isAssignable(TypeElement type1, TypeElement type2) {
TypeMirror t1 = type1.asType();
TypeMirror t2 = env.getTypeUtils().erasure(type2.asType());
return env.getTypeUtils().isAssignable(t1, t2);
}
private TypeModel create(TypeElement typeElement, TypeCategory category, Elements p) {
String name = typeElement.getQualifiedName().toString();
String simpleName = typeElement.getSimpleName().toString();

View File

@ -22,6 +22,8 @@ import com.mysema.commons.lang.Assert;
*/
public class Configuration {
private String namePrefix = "Q";
protected final Class<? extends Annotation> entityAnn, superTypeAnn, embeddableAnn, dtoAnn, skipAnn;
private boolean useFields = true, useGetters = true;
@ -97,4 +99,12 @@ public class Configuration {
this.useFields = b;
}
public String getNamePrefix() {
return namePrefix;
}
public void setNamePrefix(String namePrefix) {
this.namePrefix = namePrefix;
}
}

View File

@ -34,16 +34,13 @@ public final class DTOElementVisitor extends SimpleElementVisitor6<BeanModel, Vo
private final ProcessingEnvironment env;
private final String namePrefix;
private final APTModelFactory typeFactory;
private final Configuration configuration;
DTOElementVisitor(ProcessingEnvironment env, Configuration configuration, String namePrefix, APTModelFactory typeFactory){
DTOElementVisitor(ProcessingEnvironment env, Configuration configuration, APTModelFactory typeFactory){
this.env = env;
this.configuration = configuration;
this.namePrefix = namePrefix;
this.typeFactory = typeFactory;
}
@ -52,7 +49,7 @@ public final class DTOElementVisitor extends SimpleElementVisitor6<BeanModel, Vo
Elements elementUtils = env.getElementUtils();
TypeModel c = typeFactory.create(e.asType(), elementUtils);
BeanModel classModel = new BeanModel(
namePrefix,
configuration.getNamePrefix(),
c.getPackageName(), c.getName(), c.getSimpleName(), Collections.<String>emptySet());
List<? extends Element> elements = e.getEnclosedElements();

View File

@ -37,8 +37,6 @@ import com.mysema.query.codegen.PropertyModel;
import com.mysema.query.codegen.TypeCategory;
import com.mysema.query.codegen.TypeModel;
import javax.lang.model.type.TypeMirror;
/**
* @author tiwe
*
@ -48,16 +46,13 @@ public final class EntityElementVisitor extends SimpleElementVisitor6<BeanModel,
private final ProcessingEnvironment env;
private final String namePrefix;
private final APTModelFactory typeFactory;
private final Configuration configuration;
EntityElementVisitor(ProcessingEnvironment env, Configuration conf, String namePrefix, APTModelFactory typeFactory){
EntityElementVisitor(ProcessingEnvironment env, Configuration conf, APTModelFactory typeFactory){
this.env = env;
this.configuration = conf;
this.namePrefix = namePrefix;
this.typeFactory = typeFactory;
}
@ -77,7 +72,7 @@ public final class EntityElementVisitor extends SimpleElementVisitor6<BeanModel,
}
}
TypeModel c = typeFactory.create(e.asType(), elementUtils);
BeanModel classModel = new BeanModel(namePrefix,
BeanModel classModel = new BeanModel(configuration.getNamePrefix(),
c.getPackageName(), c.getName(), c.getSimpleName(),
superTypes);
List<? extends Element> elements = e.getEnclosedElements();

View File

@ -11,6 +11,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
@ -41,8 +42,6 @@ public class Processor {
private final APTModelFactory typeFactory;
private final String namePrefix = "Q";
private final Configuration conf;
private final BeanModelFactory classModelFactory;
@ -58,7 +57,7 @@ public class Processor {
}
this.env = Assert.notNull(env);
TypeModelFactory factory = new TypeModelFactory(anns);
this.typeFactory = new APTModelFactory(factory, anns);
this.typeFactory = new APTModelFactory(env, factory, anns);
if (conf.getSkipAnn() != null){
this.classModelFactory = new BeanModelFactory(factory, conf.getSkipAnn());
}else{
@ -71,7 +70,7 @@ public class Processor {
public void process(RoundEnvironment roundEnv) {
Map<String, BeanModel> superTypes = new HashMap<String, BeanModel>();
EntityElementVisitor entityVisitor = new EntityElementVisitor(env, conf, namePrefix, typeFactory);
EntityElementVisitor entityVisitor = new EntityElementVisitor(env, conf, typeFactory);
// populate super type mappings
if (conf.getSuperTypeAnn() != null) {
@ -131,7 +130,7 @@ public class Processor {
// DTOS (optional)
if (conf.getDtoAnn() != null){
DTOElementVisitor dtoVisitor = new DTOElementVisitor(env, conf, namePrefix, typeFactory);
DTOElementVisitor dtoVisitor = new DTOElementVisitor(env, conf, typeFactory);
Map<String, BeanModel> dtos = new HashMap<String, BeanModel>();
for (Element element : roundEnv.getElementsAnnotatedWith(conf.getDtoAnn())) {
BeanModel model = element.accept(dtoVisitor, null);
@ -151,31 +150,29 @@ public class Processor {
// iterate over supertypes
for (Map<String,BeanModel> stypes : superTypes){
if (stypes.containsKey(stype)) {
while (true) {
BeanModel sdecl;
if (stypes.containsKey(stype)) {
sdecl = stypes.get(stype);
} else {
break;
Stack<String> stypeStack = new Stack<String>();
stypeStack.push(stype);
while (!stypeStack.isEmpty()){
String top = stypeStack.pop();
if (stypes.containsKey(top)){
BeanModel sdecl = stypes.get(top);
if (singleSuperType && model.getSuperTypes().contains(top)){
model.setSuperModel(sdecl);
}
if (sdecl.isEntityModel()){
model.include(sdecl);
}
for (String type : sdecl.getSuperTypes()){
stypeStack.push(type);
}
}
if (singleSuperType && model.getSuperTypes().contains(stype)){
model.setSuperModel(sdecl);
}
if (sdecl.isEntityModel()){
model.include(sdecl);
}
if (sdecl.getSuperTypes().isEmpty()){
stype = null;
}else{
stype = sdecl.getSuperTypes().iterator().next();
}
}
}
}
}
}
// create super class model via reflection
if (model.getSuperModel() == null && model.getSuperTypes().size() == 1){
if (model.getSuperModel() == null && singleSuperType){
String stype = model.getSuperTypes().iterator().next();
Class<?> superClass = safeClassForName(stype);
if (superClass != null && !superClass.equals(Object.class)) {
@ -183,7 +180,7 @@ public class Processor {
if((conf.getSuperTypeAnn() == null
|| superClass.getAnnotation(conf.getSuperTypeAnn()) != null)
|| superClass.getAnnotation(conf.getEntityAnn()) != null){
BeanModel type = classModelFactory.create(superClass, namePrefix);
BeanModel type = classModelFactory.create(superClass, conf.getNamePrefix());
// include fields of supertype
model.include(type);
}
@ -205,7 +202,7 @@ public class Processor {
msg.printMessage(Kind.NOTE, type.getName() + " is processed");
try {
String packageName = type.getPackageName();
String className = packageName + "." + namePrefix + type.getSimpleName();
String className = packageName + "." + conf.getNamePrefix() + type.getSimpleName();
JavaFileObject fileObject = env.getFiler().createSourceFile(className);
Writer writer = fileObject.openWriter();
try {

View File

@ -41,7 +41,7 @@ public class EntityTest {
@SuppressWarnings("unchecked")
@Test
public void test(){
public void inheritance(){
assertTrue(QEntity2.entity2 instanceof QSupertype);
assertTrue(QEntity3.entity3 instanceof QSupertype);
}

View File

@ -1,10 +1,14 @@
package com.mysema.query.domain;
import static org.junit.Assert.assertEquals;
import java.util.List;
import org.junit.Test;
import com.mysema.query.annotations.QueryEntity;
import com.mysema.query.types.path.PEntityList;
import com.mysema.query.types.path.PNumber;
public class InterfaceTypeTest {
@ -36,22 +40,57 @@ public class InterfaceTypeTest {
}
@Test
public void test() throws SecurityException, NoSuchFieldException{
Class<?> cl = QInterfaceType.class;
cl.getField("relation");
cl.getField("relation2");
cl.getField("relation3");
cl.getField("relation4");
@QueryEntity
public interface InterfaceType4{
public String getProp4();
}
@QueryEntity
public interface InterfaceType5 extends InterfaceType3, InterfaceType4{
public String getProp5();
}
@Test
public void test2() throws SecurityException, NoSuchFieldException{
public void QInterfaceType_reation() throws SecurityException, NoSuchFieldException{
assertEquals(QInterfaceType.class, QInterfaceType.class.getField("relation").getType());
}
@Test
public void QInterfaceType_reation2() throws SecurityException, NoSuchFieldException{
assertEquals(PEntityList.class, QInterfaceType.class.getField("relation2").getType());
}
@Test
public void QInterfaceType_reation3() throws SecurityException, NoSuchFieldException{
assertEquals(PEntityList.class, QInterfaceType.class.getField("relation3").getType());
}
@Test
public void QInterfaceType_reation4() throws SecurityException, NoSuchFieldException{
assertEquals(PNumber.class, QInterfaceType.class.getField("relation4").getType());
}
@Test
public void testQInterfaceType3() throws SecurityException, NoSuchFieldException{
Class<?> cl = QInterfaceType3.class;
cl.getField("prop");
cl.getField("prop2");
cl.getField("prop3");
}
@Test
public void testQInterfaceType5() throws SecurityException, NoSuchFieldException{
Class<?> cl = QInterfaceType5.class;
cl.getField("prop");
cl.getField("prop2");
cl.getField("prop3");
cl.getField("prop4");
cl.getField("prop5");
}
}

View File

@ -71,7 +71,7 @@ public class RelationTest {
@Test
public void test(){
// TODO
}
}

View File

@ -56,8 +56,18 @@ public class ReservedNamesTest {
}
@Test
public void test(){
// TODO
public void test() throws SecurityException, NoSuchFieldException{
Class<?> cl = QReservedNames.class;
cl.getField("new_");
cl.getField("package_");
cl.getField("protected_");
cl.getField("if_");
cl.getField("else_");
cl.getField("try_");
cl.getField("catch_");
cl.getField("while_");
cl.getField("for_");
cl.getField("extends_");
}
}

View File

@ -1,5 +1,7 @@
package com.mysema.query.domain;
import static org.junit.Assert.assertEquals;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@ -9,6 +11,9 @@ import org.junit.Test;
import com.mysema.query.annotations.QueryEntity;
import com.mysema.query.annotations.QueryTransient;
import com.mysema.query.types.path.PComparable;
import com.mysema.query.types.path.PNumber;
import com.mysema.query.types.path.PSimple;
public class SimpleTypesTest {
@ -16,7 +21,42 @@ public class SimpleTypesTest {
}
public class CustomComparableLiteral implements Comparable<CustomComparableLiteral> {
@SuppressWarnings("serial")
public static class CustomNumber extends Number{
@Override
public double doubleValue() {
return 0;
}
@Override
public float floatValue() {
return 0;
}
@Override
public int intValue() {
return 0;
}
@Override
public long longValue() {
return 0;
}
}
@SuppressWarnings("serial")
public static class CustomComparableNumber extends CustomNumber implements Comparable<CustomComparableNumber>{
@Override
public int compareTo(CustomComparableNumber o) {
return 0;
}
}
public static class CustomComparableLiteral implements Comparable<CustomComparableLiteral> {
@Override
public int compareTo(CustomComparableLiteral o) {
@ -27,69 +67,62 @@ public class SimpleTypesTest {
@QueryEntity
public static class SimpleTypes {
transient int test;
long id;
BigDecimal bigDecimal;
Byte bbyte;
byte bbyte2;
Character cchar;
char cchar2;
Double ddouble;
double ddouble2;
Float ffloat;
float ffloat2;
Integer iint;
int iint2;
Locale llocale;
Long llong;
long llong2;
String sstring;
Date date;
java.sql.Time time;
java.sql.Timestamp timestamp;
Serializable serializable;
Object object;
Class<?> clazz;
Package packageAsLiteral;
CustomLiteral literal;
CustomComparableLiteral literal2;
CustomLiteral customLiteral;
CustomComparableLiteral customComparableLiteral;
CustomNumber customNumber;
CustomComparableNumber customComparableNumber;
java.sql.Clob clob;
java.sql.Blob blob;
@QueryTransient
String skipMe;
}
@Test
public void customLiteral() throws SecurityException, NoSuchFieldException{
assertEquals(PSimple.class, QSimpleTypes.class.getField("customLiteral").getType());
}
@Test
public void customComparableLiteral() throws SecurityException, NoSuchFieldException{
assertEquals(PComparable.class, QSimpleTypes.class.getField("customComparableLiteral").getType());
}
@Test
public void customNumber() throws SecurityException, NoSuchFieldException{
assertEquals(PSimple.class, QSimpleTypes.class.getField("customNumber").getType());
}
@Test
public void customComparableNumber() throws SecurityException, NoSuchFieldException{
assertEquals(PNumber.class, QSimpleTypes.class.getField("customComparableNumber").getType());
}
@Test(expected=NoSuchFieldException.class)
public void test() throws SecurityException, NoSuchFieldException {
public void skippedFields() throws SecurityException, NoSuchFieldException {
QSimpleTypes.class.getField("skipMe");
}

View File

@ -10,8 +10,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.commons.collections15.Factory;
import org.apache.commons.collections15.MapUtils;
import org.apache.commons.lang.StringUtils;

View File

@ -81,6 +81,9 @@ public class TypeModelFactory {
TypeModel valueInfo = create(TypeUtil.getTypeParameter(genericType, 0));
value = createCollectionType(valueInfo);
}else if (Number.class.isAssignableFrom(cl) && Comparable.class.isAssignableFrom(cl)){
value = new ClassTypeModel(TypeCategory.NUMERIC, cl);
} else {
TypeCategory typeCategory = TypeCategory.get(cl.getName());
if (!typeCategory.isSubCategoryOf(TypeCategory.COMPARABLE) && Comparable.class.isAssignableFrom(cl)){