diff --git a/pom.xml b/pom.xml
index 021fdf328..db6dbcbf5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,17 @@
2.4
+
+ net.sourceforge.findbugs
+ jsr305
+ 1.3.2
+
+
+ net.sourceforge.findbugs
+ annotations
+ 1.3.2
+
+
junit
diff --git a/src/main/java/com/mysema/codegen/AbstractCodeWriter.java b/src/main/java/com/mysema/codegen/AbstractCodeWriter.java
new file mode 100644
index 000000000..ea4401e55
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/AbstractCodeWriter.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+import static com.mysema.codegen.Symbols.NEWLINE;
+import static com.mysema.codegen.Symbols.SEMICOLON;
+
+import java.io.IOException;
+
+
+
+/**
+ * @author tiwe
+ *
+ * @param
+ */
+public abstract class AbstractCodeWriter> implements Appendable, CodeWriter{
+
+ private static final int INDENT_SPACES = 4;
+
+ private final Appendable appendable;
+
+ private String indent = "";
+
+ @SuppressWarnings("unchecked")
+ private final T self = (T)this;
+
+ public AbstractCodeWriter(Appendable appendable){
+ if (appendable == null){
+ throw new IllegalArgumentException("appendable is null");
+ }
+ this.appendable = appendable;
+ }
+
+
+ @Override
+ public T append(char c) throws IOException {
+ appendable.append(c);
+ return self;
+ }
+
+ @Override
+ public T append(CharSequence csq) throws IOException {
+ appendable.append(csq);
+ return self;
+ }
+
+ @Override
+ public T append(CharSequence csq, int start, int end) throws IOException {
+ appendable.append(csq, start, end);
+ return self;
+ }
+
+ @Override
+ public T beginLine(String... segments) throws IOException {
+ append(indent);
+ for (String segment : segments){
+ append(segment);
+ }
+ return self;
+ }
+
+ protected T goIn(){
+ indent += " ";
+ return self;
+ }
+
+
+ protected T goOut(){
+ if (indent.length() >= INDENT_SPACES){
+ indent = indent.substring(0, indent.length() - INDENT_SPACES);
+ }
+ return self;
+ }
+
+ @Override
+ public T line(String... segments) throws IOException{
+ append(indent);
+ for (String segment : segments){
+ append(segment);
+ }
+ return nl();
+ }
+
+ @Override
+ public T nl() throws IOException {
+ return append(NEWLINE);
+ }
+
+
+ protected T stmt(String stmt) throws IOException{
+ return line(stmt + SEMICOLON);
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/ClassType.java b/src/main/java/com/mysema/codegen/ClassType.java
deleted file mode 100644
index 004a3ecd6..000000000
--- a/src/main/java/com/mysema/codegen/ClassType.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.mysema.codegen;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Type represents a generic type used in code generation
- *
- * @author tiwe
- *
- * @param
- */
-public class ClassType implements Type {
-
- private final Class javaClass;
-
- private final List> parameters;
-
- public ClassType(Class javaClass, List> parameters) {
- this.javaClass = javaClass;
- this.parameters = parameters;
- }
-
- public ClassType(Class clazz, Type>... parameters) {
- this(clazz, Arrays.asList(parameters));
- }
-
- @Override
- public boolean equals(Object o){
- if (o == this){
- return true;
- }else if (o instanceof ClassType>){
- ClassType> t = (ClassType>)o;
- return t.javaClass.equals(javaClass) && t.parameters.equals(parameters);
- }else{
- return false;
- }
- }
-
- @Override
- public String getGenericName() {
- return getGenericName(Collections.emptySet(), Collections.emptySet());
- }
-
- @Override
- public String getGenericName(Set packages, Set classes) {
- if (parameters.isEmpty()){
- return ClassUtils.getName(javaClass, packages, classes);
- }else{
- StringBuilder builder = new StringBuilder();
- builder.append(ClassUtils.getName(javaClass, packages, classes));
- builder.append("<");
- boolean first = true;
- for (Type> parameter : parameters){
- builder.append(parameter.getGenericName(packages, classes));
- if (!first){
- builder.append(",");
- }
- first = false;
- }
- builder.append(">");
- return builder.toString();
- }
- }
-
- @Override
- public String getName() {
- return javaClass.getName();
- }
-
- @Override
- public String getPackageName() {
- return javaClass.getPackage().getName();
- }
-
- @Override
- public List> getParameters() {
- return parameters;
- }
-
- @Override
- public String getSimpleName() {
- return javaClass.getSimpleName();
- }
-
- @Override
- public int hashCode(){
- return javaClass.hashCode();
- }
-
-}
diff --git a/src/main/java/com/mysema/codegen/CodeWriter.java b/src/main/java/com/mysema/codegen/CodeWriter.java
index b6198e7e7..d8a4e8b27 100644
--- a/src/main/java/com/mysema/codegen/CodeWriter.java
+++ b/src/main/java/com/mysema/codegen/CodeWriter.java
@@ -33,7 +33,7 @@ public interface CodeWriter extends Appendable{
CodeWriter beginInterface(String simpleName, String... interfaces) throws IOException;
- JavaWriter beginLine(String... segments) throws IOException;
+ CodeWriter beginLine(String... segments) throws IOException;
CodeWriter beginPublicMethod(String returnType, String methodName, Collection parameters, Transformer transformer) throws IOException;
diff --git a/src/main/java/com/mysema/codegen/EvaluatorFactory.java b/src/main/java/com/mysema/codegen/EvaluatorFactory.java
index ad968adfd..3d658a6dd 100644
--- a/src/main/java/com/mysema/codegen/EvaluatorFactory.java
+++ b/src/main/java/com/mysema/codegen/EvaluatorFactory.java
@@ -23,6 +23,12 @@ import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
+import com.mysema.codegen.model.ClassType;
+import com.mysema.codegen.model.Type;
+import com.mysema.codegen.model.TypeCategory;
+import com.mysema.codegen.support.ClassUtils;
+
+
/**
* EvaluatorFactory is a factory implementation for creating Evaluator instances
@@ -54,15 +60,15 @@ public class EvaluatorFactory {
this.compilationOptions = Arrays.asList("-classpath", classpath, "-g:none");
}
- private void compile(String source, Class> projectionType,
- String[] names, Type>[] types, String id, Map constants) throws IOException {
+ private void compile(String source, Type projectionType,
+ String[] names, Type[] types, String id, Map constants) throws IOException {
// create source
StringWriter writer = new StringWriter();
JavaWriter javaw = new JavaWriter(writer);
javaw.beginClass(id, null);
String[] params = new String[names.length];
for (int i = 0; i < params.length; i++) {
- params[i] = types[i].getGenericName() + " " + names[i];
+ params[i] = types[i].getGenericName(true) + " " + names[i];
}
for (Map.Entry entry : constants.entrySet()){
@@ -71,9 +77,9 @@ public class EvaluatorFactory {
}
if (constants.isEmpty()){
- javaw.beginStaticMethod(ClassUtils.getName(projectionType), "eval", params);
+ javaw.beginStaticMethod(projectionType.getGenericName(false), "eval", params);
}else{
- javaw.beginPublicMethod(ClassUtils.getName(projectionType), "eval", params);
+ javaw.beginPublicMethod(projectionType.getGenericName(false), "eval", params);
}
javaw.append(source);
javaw.end();
@@ -103,11 +109,11 @@ public class EvaluatorFactory {
String[] names,
Class>[] classes,
Map constants) {
- Type>[] types = new Type[classes.length];
+ Type[] types = new Type[classes.length];
for (int i = 0; i < types.length; i++){
- types[i] = new ClassType(classes[i]);
+ types[i] = new ClassType(TypeCategory.SIMPLE,classes[i]);
}
- return createEvaluator(source, projectionType, names, types, classes, constants);
+ return createEvaluator(source, new ClassType(TypeCategory.SIMPLE,projectionType), names, types, classes, constants);
}
/**
@@ -123,13 +129,13 @@ public class EvaluatorFactory {
*/
public Evaluator createEvaluator(
String source,
- Class extends T> projection,
+ ClassType extends T> projection,
String[] names,
- Type>[] types,
+ Type[] types,
Class>[] classes,
Map constants) {
try {
- String id = toId(source, projection, types);
+ String id = toId(source, projection.getJavaClass(), types);
Class> clazz;
try{
clazz = loader.loadClass(id);
@@ -147,7 +153,7 @@ public class EvaluatorFactory {
}
Method method = clazz.getMethod("eval", classes);
- return new MethodEvaluator(method, object, projection);
+ return new MethodEvaluator(method, object, projection.getJavaClass());
} catch (ClassNotFoundException e) {
throw new CodegenException(e);
} catch (SecurityException e) {
@@ -168,12 +174,12 @@ public class EvaluatorFactory {
}
- protected String toId(String source, Class> returnType, Type>... types) {
+ protected String toId(String source, Class> returnType, Type... types) {
StringBuilder b = new StringBuilder("Q");
b.append("_").append(source.hashCode());
b.append("_").append(returnType.getName().hashCode());
- for (Type> type : types) {
- b.append("_").append(type.getName().hashCode());
+ for (Type type : types) {
+ b.append("_").append(type.getFullName().hashCode());
}
return b.toString().replace('-', '0');
}
diff --git a/src/main/java/com/mysema/codegen/JavaWriter.java b/src/main/java/com/mysema/codegen/JavaWriter.java
index 8fa048d54..3e2185d9c 100644
--- a/src/main/java/com/mysema/codegen/JavaWriter.java
+++ b/src/main/java/com/mysema/codegen/JavaWriter.java
@@ -8,7 +8,6 @@ package com.mysema.codegen;
import static com.mysema.codegen.Symbols.ASSIGN;
import static com.mysema.codegen.Symbols.COMMA;
import static com.mysema.codegen.Symbols.DOT;
-import static com.mysema.codegen.Symbols.NEWLINE;
import static com.mysema.codegen.Symbols.QUOTE;
import static com.mysema.codegen.Symbols.SEMICOLON;
import static com.mysema.codegen.Symbols.SPACE;
@@ -25,15 +24,14 @@ import org.apache.commons.collections15.Transformer;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
+
/**
* JavaWriter is the default implementation of the CodeWriter interface
*
* @author tiwe
*
*/
-public final class JavaWriter implements Appendable, CodeWriter{
-
- private static final int INDENT_SPACES = 4;
+public final class JavaWriter extends AbstractCodeWriter{
private static final String EXTENDS = " extends ";
@@ -65,27 +63,20 @@ public final class JavaWriter implements Appendable, CodeWriter{
private static final String PUBLIC_STATIC_FINAL = "public static final ";
- private final Appendable appendable;
-
private final Set importedClasses = new HashSet();
private final Set importedPackages = new HashSet();
- private String indent = "";
-
private String type;
public JavaWriter(Appendable appendable){
- if (appendable == null){
- throw new IllegalArgumentException("appendable is null");
- }
- this.appendable = appendable;
+ super(appendable);
this.importedPackages.add("java.lang");
}
@Override
public JavaWriter annotation(Annotation annotation) throws IOException {
- append(indent).append("@").appendType(annotation.annotationType());
+ beginLine().append("@").appendType(annotation.annotationType());
Method[] methods = annotation.annotationType().getDeclaredMethods();
if (methods.length == 1 && methods[0].getName().equals("value")){
try {
@@ -133,7 +124,7 @@ public final class JavaWriter implements Appendable, CodeWriter{
@Override
public JavaWriter annotation(Class extends Annotation> annotation) throws IOException{
- return append(indent).append("@").appendType(annotation).nl();
+ return beginLine().append("@").appendType(annotation).nl();
}
@SuppressWarnings("unchecked")
@@ -152,25 +143,6 @@ public final class JavaWriter implements Appendable, CodeWriter{
}
}
-
- @Override
- public JavaWriter append(char c) throws IOException {
- appendable.append(c);
- return this;
- }
-
- @Override
- public JavaWriter append(CharSequence csq) throws IOException {
- appendable.append(csq);
- return this;
- }
-
- @Override
- public JavaWriter append(CharSequence csq, int start, int end) throws IOException {
- appendable.append(csq, start, end);
- return this;
- }
-
private JavaWriter appendType(Class> type) throws IOException{
if (importedClasses.contains(type.getName()) || importedPackages.contains(type.getPackage().getName())){
append(type.getSimpleName());
@@ -186,7 +158,7 @@ public final class JavaWriter implements Appendable, CodeWriter{
@Override
public JavaWriter beginClass(String simpleName, String superClass, String... interfaces) throws IOException{
- append(indent + PUBLIC_CLASS + simpleName);
+ beginLine(PUBLIC_CLASS + simpleName);
if (superClass != null){
append(EXTENDS + superClass);
}
@@ -206,19 +178,19 @@ public final class JavaWriter implements Appendable, CodeWriter{
@Override
public JavaWriter beginConstructor(Collection parameters, Transformer transformer) throws IOException {
- append(indent + PUBLIC + type).params(parameters, transformer).append(" {").nl();
+ beginLine(PUBLIC + type).params(parameters, transformer).append(" {").nl();
return goIn();
}
@Override
public JavaWriter beginConstructor(String... parameters) throws IOException{
- append(indent + PUBLIC + type).params(parameters).append(" {").nl();
+ beginLine(PUBLIC + type).params(parameters).append(" {").nl();
return goIn();
}
@Override
public JavaWriter beginInterface(String simpleName, String... interfaces) throws IOException {
- append(indent + PUBLIC_INTERFACE + simpleName);
+ beginLine(PUBLIC_INTERFACE + simpleName);
if (interfaces.length > 0){
append(EXTENDS);
append(StringUtils.join(interfaces, COMMA));
@@ -234,17 +206,10 @@ public final class JavaWriter implements Appendable, CodeWriter{
}
- @Override
- public JavaWriter beginLine(String... segments) throws IOException {
- append(indent);
- for (String segment : segments){
- append(segment);
- }
- return this;
- }
+
private JavaWriter beginMethod(String modifiers, String returnType, String methodName, String... args) throws IOException{
- append(indent + modifiers + returnType + SPACE + methodName).params(args).append(" {").nl();
+ beginLine(modifiers + returnType + SPACE + methodName).params(args).append(" {").nl();
return goIn();
}
@@ -287,18 +252,6 @@ public final class JavaWriter implements Appendable, CodeWriter{
return stmt(modifier + type + SPACE + name + ASSIGN + value).nl();
}
- private JavaWriter goIn(){
- indent += " ";
- return this;
- }
-
- private JavaWriter goOut(){
- if (indent.length() >= INDENT_SPACES){
- indent = indent.substring(0, indent.length() - INDENT_SPACES);
- }
- return this;
- }
-
@Override
public JavaWriter imports(Class>... imports) throws IOException{
for (Class> cl : imports){
@@ -347,20 +300,6 @@ public final class JavaWriter implements Appendable, CodeWriter{
}
return line(" */");
}
-
- @Override
- public JavaWriter line(String... segments) throws IOException{
- append(indent);
- for (String segment : segments){
- append(segment);
- }
- return nl();
- }
-
- @Override
- public JavaWriter nl() throws IOException {
- return append(NEWLINE);
- }
@Override
public JavaWriter packageDecl(String packageName) throws IOException{
@@ -451,10 +390,6 @@ public final class JavaWriter implements Appendable, CodeWriter{
}
return this;
}
-
- private JavaWriter stmt(String stmt) throws IOException{
- return line(stmt + SEMICOLON);
- }
@Override
public JavaWriter suppressWarnings(String type) throws IOException{
diff --git a/src/main/java/com/mysema/codegen/Type.java b/src/main/java/com/mysema/codegen/Type.java
deleted file mode 100644
index 1986d678c..000000000
--- a/src/main/java/com/mysema/codegen/Type.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.mysema.codegen;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * @author tiwe
- *
- * @param
- */
-public interface Type {
-
- String getGenericName();
-
- String getGenericName(Set packages, Set classes);
-
- String getName();
-
- String getPackageName();
-
- List> getParameters();
-
- String getSimpleName();
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/mysema/codegen/model/ClassType.java b/src/main/java/com/mysema/codegen/model/ClassType.java
new file mode 100644
index 000000000..4a2a42f59
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/ClassType.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import com.mysema.codegen.support.ClassUtils;
+
+/**
+ * @author tiwe
+ *
+ * @param
+ */
+public class ClassType implements Type {
+
+ private final TypeCategory category;
+
+ private final Class javaClass;
+
+ private final List parameters;
+
+ private final Class> primitiveClass;
+
+ public ClassType(TypeCategory category, Class javaClass, Class> primitiveClass) {
+ this(category, javaClass, primitiveClass, Collections.emptyList());
+ }
+
+ public ClassType(TypeCategory category, Class javaClass, Class> primitiveClass, List parameters) {
+ this.category = category;
+ this.javaClass = javaClass;
+ this.primitiveClass = primitiveClass;
+ this.parameters = parameters;
+ }
+
+ public ClassType(TypeCategory category, Class javaClass, List parameters) {
+ this(category, javaClass, null, parameters);
+ }
+
+ public ClassType(TypeCategory category, Class clazz, Type... parameters) {
+ this(category, clazz, null, Arrays.asList(parameters));
+ }
+
+ @Override
+ public Type as(TypeCategory c) {
+ if (category == c){
+ return this;
+ }else{
+ return new ClassType(c, javaClass);
+ }
+ }
+
+ @Override
+ public Type asArrayType() {
+ String fullName = javaClass.getName()+"[]";
+ String simpleName = javaClass.getSimpleName()+"[]";
+ return new SimpleType(TypeCategory.ARRAY, fullName, getPackageName(), simpleName, false, false);
+ }
+
+
+ @Override
+ public boolean equals(Object o){
+ if (o == this){
+ return true;
+ }else if (o instanceof Type){
+ Type t = (Type)o;
+ return t.getFullName().equals(javaClass.getName()) && t.getParameters().equals(parameters);
+ }else{
+ return false;
+ }
+ }
+
+ public TypeCategory getCategory() {
+ return category;
+ }
+
+ @Override
+ public String getFullName() {
+ return javaClass.getName();
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType) {
+ return getGenericName(asArgType, Collections.emptySet(), Collections.emptySet());
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType, Set packages, Set classes) {
+ if (parameters.isEmpty()){
+ return ClassUtils.getName(javaClass, packages, classes);
+ }else{
+ StringBuilder builder = new StringBuilder();
+ builder.append(ClassUtils.getName(javaClass, packages, classes));
+ builder.append("<");
+ boolean first = true;
+ for (Type parameter : parameters){
+ if (!first){
+ builder.append(",");
+ }
+ if (parameter == null || parameter.equals(this)){
+ builder.append("?");
+ }else{
+ builder.append(parameter.getGenericName(true, packages, classes));
+ }
+ first = false;
+ }
+ builder.append(">");
+ return builder.toString();
+ }
+ }
+
+ public Class getJavaClass() {
+ return javaClass;
+ }
+
+ @Override
+ public String getPackageName() {
+ return javaClass.getPackage().getName();
+ }
+
+ @Override
+ public List getParameters() {
+ return parameters;
+ }
+
+ @Override
+ public String getPrimitiveName() {
+ return primitiveClass != null ? primitiveClass.getName() : null;
+ }
+
+ @Override
+ public String getRawName(Set packages, Set classes) {
+ return ClassUtils.getName(javaClass, packages, classes);
+ }
+
+ @Override
+ public String getSimpleName() {
+ return javaClass.getSimpleName();
+ }
+
+ @Override
+ public int hashCode(){
+ return javaClass.getName().hashCode();
+ }
+
+ @Override
+ public boolean isFinal() {
+ return Modifier.isFinal(javaClass.getModifiers());
+ }
+
+ @Override
+ public boolean isPrimitive() {
+// return javaClass.isPrimitive();
+ return primitiveClass != null;
+ }
+
+ public String toString(){
+ return getGenericName(true);
+ }
+
+
+}
diff --git a/src/main/java/com/mysema/codegen/model/Constructor.java b/src/main/java/com/mysema/codegen/model/Constructor.java
new file mode 100644
index 000000000..b4a3ba9c6
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/Constructor.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+import java.util.Collection;
+
+public final class Constructor {
+
+ private final Collection parameters;
+
+ public Constructor(Collection params) {
+ parameters = params;
+ }
+
+ @Override
+ public boolean equals(Object o){
+ if (o == this){
+ return true;
+ }else if (o instanceof Constructor){
+ return ((Constructor)o).parameters.equals(parameters);
+ }else{
+ return false;
+ }
+ }
+
+ public Collection getParameters() {
+ return parameters;
+ }
+
+ @Override
+ public int hashCode(){
+ return parameters.hashCode();
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/model/Parameter.java b/src/main/java/com/mysema/codegen/model/Parameter.java
new file mode 100644
index 000000000..975dabd64
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/Parameter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+/**
+ * Parameter represents a parameter in a Constructor
+ *
+ * @author tiwe
+ * @version $Id$
+ */
+public final class Parameter {
+
+ private final String name;
+
+ private final Type type;
+
+ public Parameter(String name, Type type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this){
+ return true;
+ }else if (o instanceof Parameter){
+ return type.equals(((Parameter) o).type);
+ }else{
+ return false;
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Type getType(){
+ return type;
+ }
+
+ @Override
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/model/SimpleType.java b/src/main/java/com/mysema/codegen/model/SimpleType.java
new file mode 100644
index 000000000..9c2f5e1e7
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/SimpleType.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * @author tiwe
+ *
+ * @param
+ */
+public class SimpleType implements Type {
+
+ private final TypeCategory category;
+
+ private final String fullName, packageName, simpleName, localName;
+
+ private final List parameters;
+
+ private final boolean primitiveClass, finalClass;
+
+ public SimpleType(Type type, Type... parameters) {
+ this(type.getCategory(), type.getFullName(), type.getPackageName(), type.getSimpleName(),
+ type.isPrimitive(), type.isFinal(), Arrays.asList(parameters));
+ }
+
+ public SimpleType(TypeCategory category, String fullName, String packageName, String simpleName,
+ boolean primitiveClass, boolean finalClass,
+ List parameters) {
+ this.category = category;
+ this.fullName = fullName;
+ this.packageName = packageName;
+ this.simpleName = simpleName;
+ if (packageName.length() > 0){
+ this.localName = fullName.substring(packageName.length()+1);
+ }else{
+ this.localName = fullName;
+ }
+ this.primitiveClass = primitiveClass;
+ this.finalClass = finalClass;
+ this.parameters = parameters;
+ }
+
+ public SimpleType(TypeCategory typeCategory, String fullName, String packageName, String simpleName,
+ boolean p, boolean f, Type... parameters) {
+ this(typeCategory, fullName, packageName, simpleName, p, f, Arrays
+ .asList(parameters));
+ }
+
+ @Override
+ public Type as(TypeCategory c) {
+ if (category != c){
+ return new SimpleType(c, fullName, packageName, simpleName, primitiveClass, finalClass, parameters);
+ }else{
+ return this;
+ }
+ }
+
+ @Override
+ public Type asArrayType() {
+ String fullName = getFullName()+"[]";
+ String simpleName = getSimpleName()+"[]";
+ return new SimpleType(TypeCategory.ARRAY, fullName, getPackageName(), simpleName, false, false);
+ }
+
+
+ @Override
+ public boolean equals(Object o){
+ if (o == this){
+ return true;
+ }else if (o instanceof Type){
+ Type t = (Type)o;
+ return t.getFullName().equals(fullName) && t.getParameters().equals(parameters);
+ }else{
+ return false;
+ }
+ }
+
+ public TypeCategory getCategory() {
+ return category;
+ }
+
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType) {
+ return getGenericName(asArgType, Collections.emptySet(), Collections.emptySet());
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType, Set packages, Set classes) {
+ if (parameters.isEmpty()){
+ return getRawName(packages, classes);
+ }else{
+ StringBuilder builder = new StringBuilder();
+ builder.append(getRawName(packages, classes));
+ builder.append("<");
+ boolean first = true;
+ for (Type parameter : parameters){
+ if (!first){
+ builder.append(",");
+ }
+ if (parameter == null || parameter.equals(this)){
+ builder.append("?");
+ }else{
+ builder.append(parameter.getGenericName(true, packages, classes));
+ }
+ first = false;
+ }
+ builder.append(">");
+ return builder.toString();
+ }
+ }
+
+ @Override
+ public String getPackageName() {
+ return packageName;
+ }
+
+ @Override
+ public List getParameters() {
+ return parameters;
+ }
+
+ @Override
+ public String getPrimitiveName() {
+ return null;
+ }
+
+ @Override
+ public String getRawName(Set packages, Set classes) {
+ if (packages.contains(packageName) || classes.contains(fullName)){
+ return localName;
+ }else{
+ return fullName;
+ }
+ }
+
+ @Override
+ public String getSimpleName() {
+ return simpleName;
+ }
+
+ @Override
+ public int hashCode(){
+ return fullName.hashCode();
+ }
+
+ @Override
+ public boolean isFinal() {
+ return finalClass;
+ }
+
+ @Override
+ public boolean isPrimitive() {
+ return primitiveClass;
+ }
+
+ public String toString(){
+ return getGenericName(true);
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/model/Type.java b/src/main/java/com/mysema/codegen/model/Type.java
new file mode 100644
index 000000000..0ca4f37b5
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/Type.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author tiwe
+ *
+ * @param
+ */
+public interface Type {
+
+ Type as(TypeCategory category);
+
+ Type asArrayType();
+
+ TypeCategory getCategory();
+
+ String getFullName();
+
+ String getGenericName(boolean asArgType);
+
+ String getGenericName(boolean asArgType, Set packages, Set classes);
+
+ String getPackageName();
+
+ List getParameters();
+
+ String getPrimitiveName();
+
+ String getRawName(Set packages, Set classes);
+
+ String getSimpleName();
+
+ boolean isFinal();
+
+ boolean isPrimitive();
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/mysema/codegen/model/TypeAdapter.java b/src/main/java/com/mysema/codegen/model/TypeAdapter.java
new file mode 100644
index 000000000..b11be2437
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/TypeAdapter.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * TypeAdapter is a basic adapter implementation for the Type interface
+ *
+ * @author tiwe
+ *
+ */
+public class TypeAdapter implements Type{
+
+ private final Type type;
+
+ public TypeAdapter(Type type){
+ this.type = type;
+ }
+
+ @Override
+ public Type as(TypeCategory category) {
+ return type.as(category);
+ }
+
+ @Override
+ public Type asArrayType() {
+ return type.asArrayType();
+ }
+
+ @Override
+ public boolean equals(Object o){
+ return type.equals(o);
+ }
+
+ @Override
+ public TypeCategory getCategory() {
+ return type.getCategory();
+ }
+
+ @Override
+ public String getFullName() {
+ return type.getFullName();
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType) {
+ return type.getGenericName(asArgType);
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType, Set packages, Set classes) {
+ return type.getGenericName(asArgType, packages, classes);
+ }
+
+ @Override
+ public String getPackageName() {
+ return type.getPackageName();
+ }
+
+ @Override
+ public List getParameters() {
+ return type.getParameters();
+ }
+
+ @Override
+ public String getPrimitiveName() {
+ return type.getPrimitiveName();
+ }
+
+ @Override
+ public String getRawName(Set packages, Set classes) {
+ return type.getRawName(packages, classes);
+ }
+
+ @Override
+ public String getSimpleName() {
+ return type.getSimpleName();
+ }
+
+ protected Type getType(){
+ return type;
+ }
+
+ @Override
+ public int hashCode(){
+ return type.hashCode();
+ }
+
+ @Override
+ public boolean isFinal() {
+ return type.isFinal();
+ }
+
+ @Override
+ public boolean isPrimitive() {
+ return type.isPrimitive();
+ }
+
+ @Override
+ public String toString() {
+ return type.toString();
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/model/TypeCategory.java b/src/main/java/com/mysema/codegen/model/TypeCategory.java
new file mode 100644
index 000000000..720bb0630
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/TypeCategory.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * TypeCategory defines the expression type used for a Field
+ *
+ * @author tiwe
+ *
+ */
+public enum TypeCategory {
+ /**
+ *
+ */
+ SIMPLE(null),
+ /**
+ *
+ */
+ MAP(null),
+ /**
+ *
+ */
+ COLLECTION(null),
+ /**
+ *
+ */
+ LIST(COLLECTION),
+ /**
+ *
+ */
+ SET(COLLECTION),
+ /**
+ *
+ */
+ ARRAY(null),
+ /**
+ *
+ */
+ COMPARABLE(SIMPLE),
+ /**
+ *
+ */
+ BOOLEAN(COMPARABLE, Boolean.class.getName()),
+ /**
+ *
+ */
+ DATE(COMPARABLE, java.sql.Date.class.getName(), "org.joda.time.LocalDate"),
+ /**
+ *
+ */
+ DATETIME(COMPARABLE,
+ java.util.Calendar.class.getName(),
+ java.util.Date.class.getName(),
+ java.sql.Timestamp.class.getName(),
+ "org.joda.time.LocalDateTime",
+ "org.joda.time.Instant",
+ "org.joda.time.DateTime",
+ "org.joda.time.DateMidnight"),
+ /**
+ *
+ */
+ CUSTOM(null),
+
+ /**
+ *
+ */
+ ENTITY(null),
+
+ /**
+ *
+ */
+ NUMERIC(COMPARABLE),
+ /**
+ *
+ */
+ STRING(COMPARABLE, String.class.getName()),
+ /**
+ *
+ */
+ TIME(COMPARABLE, java.sql.Time.class.getName(), "org.joda.time.LocalTime");
+
+ private final TypeCategory superType;
+
+ private final Set types;
+
+ TypeCategory(TypeCategory superType, String... types){
+ this.superType = superType;
+ this.types = new HashSet(types.length);
+ for (String type : types){
+ this.types.add(type);
+ }
+ }
+
+ public TypeCategory getSuperType() {
+ return superType;
+ }
+
+ public boolean supports(Class> cl){
+ return supports(cl.getName());
+ }
+
+ public boolean supports(String className){
+ return types.contains(className);
+ }
+
+ /**
+ * transitive and reflexive subCategoryOf check
+ *
+ * @param ancestor
+ * @return
+ */
+ public boolean isSubCategoryOf(TypeCategory ancestor){
+ if (this == ancestor){
+ return true;
+ }else if (superType == null){
+ return false;
+ }else{
+ return superType == ancestor || superType.isSubCategoryOf(ancestor);
+ }
+ }
+
+ public static TypeCategory get(String className){
+ for (TypeCategory category : values()){
+ if (category.supports(className)){
+ return category;
+ }
+ }
+ return SIMPLE;
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/model/TypeExtends.java b/src/main/java/com/mysema/codegen/model/TypeExtends.java
new file mode 100644
index 000000000..65403ee13
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/TypeExtends.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+import java.util.Set;
+
+/**
+ * @author tiwe
+ *
+ */
+public class TypeExtends extends TypeAdapter{
+
+ private final String varName;
+
+ public TypeExtends(String varName, Type type) {
+ super(type);
+ this.varName = varName;
+ }
+
+ public TypeExtends(Type type) {
+ super(type);
+ varName = null;
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType){
+ if (!asArgType){
+ return "? extends " + super.getGenericName(true);
+ }else{
+ return super.getGenericName(asArgType);
+ }
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType, Set packages, Set classes){
+ if (!asArgType){
+ return "? extends " + super.getGenericName(true, packages, classes);
+ }else{
+ return super.getGenericName(asArgType, packages, classes);
+ }
+ }
+
+ public String getVarName(){
+ return varName;
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/model/TypeSuper.java b/src/main/java/com/mysema/codegen/model/TypeSuper.java
new file mode 100644
index 000000000..7845b4de7
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/TypeSuper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+import java.util.Set;
+
+
+/**
+ * TypeSuper is a Type for type variables and wildcard types
+ *
+ * @author tiwe
+ *
+ */
+public class TypeSuper extends TypeAdapter{
+
+ private final Type superType;
+
+ private final String varName;
+
+ public TypeSuper(String varName, Type type) {
+ super(Types.OBJECT);
+ this.superType = type;
+ this.varName = varName;
+ }
+
+ public TypeSuper(Type type) {
+ super(Types.OBJECT);
+ this.superType = type;
+ this.varName = null;
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType){
+ if (!asArgType){
+ return "? super " + superType.getGenericName(true);
+ }else{
+ return super.getGenericName(asArgType);
+ }
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType, Set packages, Set classes){
+ if (!asArgType){
+ return "? super " + superType.getGenericName(true, packages, classes);
+ }else{
+ return super.getGenericName(asArgType, packages, classes);
+ }
+ }
+
+ public String getVarName(){
+ return varName;
+ }
+}
diff --git a/src/main/java/com/mysema/codegen/model/Types.java b/src/main/java/com/mysema/codegen/model/Types.java
new file mode 100644
index 000000000..2b3b8434d
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/model/Types.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen.model;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author tiwe
+ *
+ */
+public final class Types {
+
+ public static final ClassType