diff --git a/querydsl-core/src/main/java/com/mysema/query/codegen/Type.java b/querydsl-core/src/main/java/com/mysema/query/codegen/ClassModel.java similarity index 60% rename from querydsl-core/src/main/java/com/mysema/query/codegen/Type.java rename to querydsl-core/src/main/java/com/mysema/query/codegen/ClassModel.java index 5af1e6c8b..28e686eb3 100644 --- a/querydsl-core/src/main/java/com/mysema/query/codegen/Type.java +++ b/querydsl-core/src/main/java/com/mysema/query/codegen/ClassModel.java @@ -1,4 +1,7 @@ /* + + * + * * Copyright (c) 2009 Mysema Ltd. * All rights reserved. * @@ -18,41 +21,41 @@ import org.apache.commons.lang.StringUtils; * @author tiwe * @version $Id$ */ -public class Type implements Comparable { +public class ClassModel implements Comparable { - private Set booleanFields = new TreeSet(); + private Set booleanFields = new TreeSet(); - private Set comparableFields = new TreeSet(); + private Set comparableFields = new TreeSet(); - private Set constructors = new HashSet(); + private Set constructors = new HashSet(); - private Set entityCollections = new TreeSet(); + private Set entityCollections = new TreeSet(); - private Set entityFields = new TreeSet(); + private Set entityFields = new TreeSet(); - private Set entityLists = new TreeSet(); + private Set entityLists = new TreeSet(); - private Set entityMaps = new TreeSet(); + private Set entityMaps = new TreeSet(); - private Set numericFields = new TreeSet(); + private Set numericFields = new TreeSet(); - private Set simpleCollections = new TreeSet(); + private Set simpleCollections = new TreeSet(); - private Set simpleFields = new TreeSet(); + private Set simpleFields = new TreeSet(); - private Set simpleLists = new TreeSet(); + private Set simpleLists = new TreeSet(); - private Set simpleMaps = new TreeSet(); + private Set simpleMaps = new TreeSet(); private String simpleName, uncapSimpleName, name, packageName; private int escapeSuffix = 1; - private Set stringFields = new TreeSet(); + private Set stringFields = new TreeSet(); private String superType; - public Type(String superType, String packageName, String name, + public ClassModel(String superType, String packageName, String name, String simpleName) { this.superType = superType; this.packageName = packageName; @@ -61,11 +64,11 @@ public class Type implements Comparable { this.uncapSimpleName = StringUtils.uncapitalize(simpleName); } - public void addConstructor(Constructor co) { + public void addConstructor(ConstructorModel co) { constructors.add(co); } - public void addField(Field fieldDecl) { + public void addField(FieldModel fieldDecl) { validateField(fieldDecl); switch (fieldDecl.getFieldType()) { case BOOLEAN: @@ -107,47 +110,46 @@ public class Type implements Comparable { } } - private Field validateField(Field field) { + private FieldModel validateField(FieldModel field) { if (field.getName().equals(this.uncapSimpleName)) { - uncapSimpleName = StringUtils.uncapitalize(simpleName) - + (escapeSuffix++); + uncapSimpleName = StringUtils.uncapitalize(simpleName)+ (escapeSuffix++); } return field; } - public int compareTo(Type o) { + public int compareTo(ClassModel o) { return simpleName.compareTo(o.simpleName); } public boolean equals(Object o) { - return o instanceof Type && simpleName.equals(((Type) o).simpleName); + return o instanceof ClassModel && simpleName.equals(((ClassModel) o).simpleName); } - public Collection getBooleanFields() { + public Collection getBooleanFields() { return booleanFields; } - public Collection getComparableFields() { + public Collection getComparableFields() { return comparableFields; } - public Collection getConstructors() { + public Collection getConstructors() { return constructors; } - public Collection getEntityCollections() { + public Collection getEntityCollections() { return entityCollections; } - public Collection getEntityFields() { + public Collection getEntityFields() { return entityFields; } - public Collection getEntityLists() { + public Collection getEntityLists() { return entityLists; } - public Collection getEntityMaps() { + public Collection getEntityMaps() { return entityMaps; } @@ -155,7 +157,7 @@ public class Type implements Comparable { return name; } - public Collection getNumericFields() { + public Collection getNumericFields() { return numericFields; } @@ -163,19 +165,19 @@ public class Type implements Comparable { return packageName; } - public Collection getSimpleCollections() { + public Collection getSimpleCollections() { return simpleCollections; } - public Collection getSimpleFields() { + public Collection getSimpleFields() { return simpleFields; } - public Collection getSimpleLists() { + public Collection getSimpleLists() { return simpleLists; } - public Collection getSimpleMaps() { + public Collection getSimpleMaps() { return simpleMaps; } @@ -187,7 +189,7 @@ public class Type implements Comparable { return uncapSimpleName; } - public Collection getStringFields() { + public Collection getStringFields() { return stringFields; } @@ -199,7 +201,7 @@ public class Type implements Comparable { return name.hashCode(); } - public void include(Type decl) { + public void include(ClassModel decl) { addAll(booleanFields, decl.booleanFields); addAll(entityCollections, decl.entityCollections); addAll(entityFields, decl.entityFields); @@ -214,8 +216,8 @@ public class Type implements Comparable { addAll(stringFields, decl.stringFields); } - private void addAll(Set target, Set source) { - for (Field field : source) { + private void addAll(Set target, Set source) { + for (FieldModel field : source) { target.add(validateField(field)); } } diff --git a/querydsl-core/src/main/java/com/mysema/query/codegen/ClassModelFactory.java b/querydsl-core/src/main/java/com/mysema/query/codegen/ClassModelFactory.java new file mode 100644 index 000000000..81109cb38 --- /dev/null +++ b/querydsl-core/src/main/java/com/mysema/query/codegen/ClassModelFactory.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.codegen; + +import java.lang.reflect.Type; +import java.util.Locale; + +import org.apache.commons.lang.ClassUtils; + +import com.mysema.query.annotations.Literal; +import com.mysema.query.util.TypeUtil; + +/** + * + * @author tiwe + * + */ +public class ClassModelFactory { + + private FieldType fieldType; + + private String simpleName, fullName, packageName = "", keyTypeName; + + public ClassModelFactory(Class cl) { + this(cl, cl); + } + + public static ClassModel createType(Class clazz) { + ClassModel type = new ClassModel(clazz.getSuperclass().getName(), clazz + .getPackage().getName(), clazz.getName(), clazz.getSimpleName()); + for (java.lang.reflect.Field f : clazz.getDeclaredFields()) { + ClassModelFactory typeHelper = new ClassModelFactory(f.getType(), f.getGenericType()); + FieldModel field = new FieldModel( + f.getName(), + typeHelper.getKeyTypeName(), typeHelper.getPackageName(), + typeHelper.getFullName(), typeHelper.getSimpleName(), + typeHelper.getFieldType()); + type.addField(field); + } + return type; + } + + + public ClassModelFactory(Class cl, java.lang.reflect.Type genericType) { + if (cl == null) { + throw new IllegalArgumentException("cl was null"); + } else if (cl.isArray()) { + visitArrayType(cl); + } else if (cl.isEnum()) { + visitEnumType(cl); + } else if (cl.isPrimitive()) { + visitPrimitiveType(cl); + } else if (cl.isInterface()) { + visitInterfaceType(cl, genericType); + } else { + visitClassType(cl); + } + if (fullName == null) { + fullName = cl.getName(); + } + + setDefaults(); + } + + public FieldType getFieldType() { + return fieldType; + } + + public String getFullName() { + return fullName; + } + + public String getKeyTypeName() { + return keyTypeName; + } + + public String getPackageName() { + return packageName; + } + + public String getSimpleName() { + return simpleName; + } + + public String getValueTypeName() { + return fullName; + } + + private void handleCollectionInterface(Class type, Type genericType) { + ClassModelFactory valueInfo = new ClassModelFactory(TypeUtil.getTypeParameter(genericType, 0)); + handleCollection(valueInfo); + } + + private void handleCollection(ClassModelFactory valueInfo) { + fullName = valueInfo.getFullName(); + packageName = valueInfo.getPackageName(); + if (valueInfo.fieldType == FieldType.ENTITY) { + fieldType = FieldType.ENTITYCOLLECTION; + } else { + fieldType = FieldType.SIMPLECOLLECTION; + } + } + + private void handleList(ClassModelFactory valueInfo) { + fullName = valueInfo.getFullName(); + packageName = valueInfo.getPackageName(); + if (valueInfo.fieldType == FieldType.ENTITY) { + fieldType = FieldType.ENTITYLIST; + } else { + fieldType = FieldType.SIMPLELIST; + } + } + + private void handleListInterface(Class type, Type genericType) { + ClassModelFactory valueInfo = new ClassModelFactory(TypeUtil.getTypeParameter(genericType, 0)); + handleList(valueInfo); + } + + private void handleMapInterface(Class type, Type genericType) { + ClassModelFactory keyInfo = new ClassModelFactory(TypeUtil.getTypeParameter(genericType, 0)); + ClassModelFactory valueInfo = new ClassModelFactory(TypeUtil.getTypeParameter(genericType, 1)); + handleMapInterface(keyInfo, valueInfo); + } + + private void handleMapInterface(ClassModelFactory keyInfo, ClassModelFactory valueInfo) { + keyTypeName = keyInfo.getFullName(); + fullName = valueInfo.getFullName(); + packageName = valueInfo.getPackageName(); + if (valueInfo.fieldType == FieldType.ENTITY) { + fieldType = FieldType.ENTITYMAP; + } else { + fieldType = FieldType.SIMPLEMAP; + } + } + + private void setDefaults() { + if (fieldType == null) { + fieldType = FieldType.ENTITY; + } + if (simpleName == null) { + simpleName = fullName.substring(fullName.lastIndexOf('.') + 1); + } + } + + public String toString() { + return fullName; + } + + private void visitArrayComponentType(ClassModelFactory valueInfo) { + fullName = valueInfo.getFullName(); + packageName = valueInfo.getPackageName(); + if (valueInfo.fieldType == FieldType.ENTITY) { + fieldType = FieldType.ENTITYCOLLECTION; + } else { + fieldType = FieldType.SIMPLECOLLECTION; + } + } + + public void visitArrayType(Class clazz) { + ClassModelFactory valueInfo = new ClassModelFactory(clazz.getComponentType()); + visitArrayComponentType(valueInfo); + } + + public void visitClassType(Class type) { + fullName = type.getName(); + packageName = type.getPackage().getName(); + + if (type.equals(String.class)) { + fieldType = FieldType.STRING; + + } else if (type.equals(Boolean.class)) { + fieldType = FieldType.BOOLEAN; + + } else if (type.equals(Locale.class) || type.equals(Class.class) + || type.equals(Object.class)) { + fieldType = FieldType.SIMPLE; + + } else if (isNumericSupported(fullName) + && Number.class.isAssignableFrom(type)) { + fieldType = FieldType.NUMERIC; + + } else if (type.getAnnotation(Literal.class) != null) { + if (Comparable.class.isAssignableFrom(type)) { + fieldType = FieldType.COMPARABLE; + } else { + fieldType = FieldType.SIMPLE; + } + + } else if (isComparableSupported(fullName) + && Comparable.class.isAssignableFrom(type)) { + fieldType = FieldType.COMPARABLE; + + } else if (asSimpleType(fullName)) { + fieldType = FieldType.SIMPLE; + + } + } + + private boolean isNumericSupported(String fullName) { + return isComparableSupported(fullName); + } + + private boolean isComparableSupported(String fullName) { + return fullName.startsWith("java.") || fullName.startsWith("javax.") + || fullName.startsWith("org.joda.time"); + } + + private boolean asSimpleType(String fullName) { + return false; + } + + public void visitEnumType(Class type) { + fieldType = FieldType.SIMPLE; + } + + public void visitInterfaceType(Class type, Type genericType) { + if (java.util.Map.class.isAssignableFrom(type)) { + handleMapInterface(type, genericType); + + } else if (java.util.List.class.isAssignableFrom(type)) { + handleListInterface(type, genericType); + + } else if (java.util.Collection.class.isAssignableFrom(type)) { + handleCollectionInterface(type, genericType); + } + + } + + public void visitPrimitiveType(Class cl) { + visitPrimitiveWrapperType(ClassUtils.primitiveToWrapper(cl)); + } + + private void visitPrimitiveWrapperType(Class cl) { + if (cl.equals(Boolean.class)) { + fieldType = FieldType.BOOLEAN; + } else if (Number.class.isAssignableFrom(cl)) { + fieldType = FieldType.NUMERIC; + } else if (Comparable.class.isAssignableFrom(cl)) { + fieldType = FieldType.COMPARABLE; + } else { + fieldType = FieldType.SIMPLE; + } + fullName = cl.getName(); + simpleName = cl.getSimpleName(); + } + +} diff --git a/querydsl-core/src/main/java/com/mysema/query/codegen/Constructor.java b/querydsl-core/src/main/java/com/mysema/query/codegen/ConstructorModel.java similarity index 77% rename from querydsl-core/src/main/java/com/mysema/query/codegen/Constructor.java rename to querydsl-core/src/main/java/com/mysema/query/codegen/ConstructorModel.java index 34598e74e..ead54a4b2 100644 --- a/querydsl-core/src/main/java/com/mysema/query/codegen/Constructor.java +++ b/querydsl-core/src/main/java/com/mysema/query/codegen/ConstructorModel.java @@ -13,10 +13,10 @@ import java.util.Collection; * @author tiwe * @version $Id$ */ -public class Constructor { +public class ConstructorModel { private final Collection parameters; - public Constructor(Collection params) { + public ConstructorModel(Collection params) { parameters = params; } diff --git a/querydsl-core/src/main/java/com/mysema/query/codegen/Field.java b/querydsl-core/src/main/java/com/mysema/query/codegen/FieldModel.java similarity index 85% rename from querydsl-core/src/main/java/com/mysema/query/codegen/Field.java rename to querydsl-core/src/main/java/com/mysema/query/codegen/FieldModel.java index a984c59c8..2f1aac547 100644 --- a/querydsl-core/src/main/java/com/mysema/query/codegen/Field.java +++ b/querydsl-core/src/main/java/com/mysema/query/codegen/FieldModel.java @@ -11,7 +11,7 @@ package com.mysema.query.codegen; * @author tiwe * @version $Id$ */ -public class Field implements Comparable { +public class FieldModel implements Comparable { /** * The Enum Type. @@ -37,7 +37,7 @@ public class Field implements Comparable { * simple type name (local) * @param fieldType */ - public Field(String name, String keyTypeName, + public FieldModel(String name, String keyTypeName, String typePackage, String typeName, String simpleTypeName, FieldType fieldType) { this.name = name; @@ -48,12 +48,12 @@ public class Field implements Comparable { this.fieldType = fieldType; } - public int compareTo(Field o) { + public int compareTo(FieldModel o) { return name.compareTo(o.name); } public boolean equals(Object o) { - return o instanceof Field && name.equals(((Field) o).name); + return o instanceof FieldModel && name.equals(((FieldModel) o).name); } public FieldType getFieldType() { diff --git a/querydsl-core/src/main/java/com/mysema/query/codegen/FieldType.java b/querydsl-core/src/main/java/com/mysema/query/codegen/FieldType.java index 09ce6280e..f2e14a79d 100644 --- a/querydsl-core/src/main/java/com/mysema/query/codegen/FieldType.java +++ b/querydsl-core/src/main/java/com/mysema/query/codegen/FieldType.java @@ -5,6 +5,22 @@ */ package com.mysema.query.codegen; +/** + * + * @author tiwe + * + */ public enum FieldType { - BOOLEAN, COMPARABLE, ENTITY, ENTITYLIST, ENTITYCOLLECTION, ENTITYMAP, NUMERIC, SIMPLE, SIMPLELIST, SIMPLECOLLECTION, SIMPLEMAP, STRING + BOOLEAN, + COMPARABLE, + ENTITY, + ENTITYLIST, + ENTITYCOLLECTION, + ENTITYMAP, + NUMERIC, + SIMPLE, + SIMPLELIST, + SIMPLECOLLECTION, + SIMPLEMAP, + STRING } \ No newline at end of file diff --git a/querydsl-core/src/main/java/com/mysema/query/util/TypeUtil.java b/querydsl-core/src/main/java/com/mysema/query/util/TypeUtil.java new file mode 100644 index 000000000..5ee717bb2 --- /dev/null +++ b/querydsl-core/src/main/java/com/mysema/query/util/TypeUtil.java @@ -0,0 +1,31 @@ +package com.mysema.query.util; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; + +public class TypeUtil { + + public static Class getTypeParameter(java.lang.reflect.Type type, int index) { + if (type instanceof ParameterizedType) { + ParameterizedType ptype = (ParameterizedType) type; + java.lang.reflect.Type[] targs = ptype.getActualTypeArguments(); + if (targs[index] instanceof WildcardType) { + WildcardType wildcardType = (WildcardType) targs[index]; + return (Class) wildcardType.getUpperBounds()[0]; + } else if (targs[index] instanceof TypeVariable) { + return (Class) ((TypeVariable) targs[index]).getGenericDeclaration(); + } else if (targs[index] instanceof ParameterizedType) { + return (Class) ((ParameterizedType) targs[index]).getRawType(); + } else { + try { + return (Class) targs[index]; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return null; + } + +}