made CodeWriter signature more typesafe by using Type from the model package

This commit is contained in:
Timo Westkämper 2010-08-18 16:27:32 +00:00
parent 8b6bf0bee2
commit 8c8da3efdb
13 changed files with 167 additions and 106 deletions

View File

@ -13,6 +13,8 @@ import javax.annotation.Nullable;
import org.apache.commons.collections15.Transformer;
import com.mysema.codegen.model.Type;
/**
* CodeWriter defines an interface for serializing Java source code
*
@ -25,29 +27,29 @@ public interface CodeWriter extends Appendable{
CodeWriter annotation(Class<? extends Annotation> annotation) throws IOException;
CodeWriter beginClass(String simpleName) throws IOException;
CodeWriter beginClass(Type type) throws IOException;
CodeWriter beginClass(String simpleName, @Nullable String superClass, String... interfaces) throws IOException;
CodeWriter beginClass(Type type, @Nullable Type superClass, Type... interfaces) throws IOException;
<T> CodeWriter beginConstructor(Collection<T> params, Transformer<T, String> transformer) throws IOException;
CodeWriter beginConstructor(String... params) throws IOException;
CodeWriter beginInterface(String simpleName, String... interfaces) throws IOException;
CodeWriter beginInterface(Type type, Type... interfaces) throws IOException;
CodeWriter beginLine(String... segments) throws IOException;
<T> CodeWriter beginPublicMethod(String returnType, String methodName, Collection<T> parameters, Transformer<T, String> transformer) throws IOException;
<T> CodeWriter beginPublicMethod(Type returnType, String methodName, Collection<T> parameters, Transformer<T, String> transformer) throws IOException;
CodeWriter beginPublicMethod(String returnType, String methodName, String... args) throws IOException;
CodeWriter beginPublicMethod(Type returnType, String methodName, String... args) throws IOException;
<T> CodeWriter beginStaticMethod(String type, String name, Collection<T> params, Transformer<T, String> transformer) throws IOException;
<T> CodeWriter beginStaticMethod(Type type, String name, Collection<T> params, Transformer<T, String> transformer) throws IOException;
CodeWriter beginStaticMethod(String returnType, String methodName, String... args) throws IOException;
CodeWriter beginStaticMethod(Type returnType, String methodName, String... args) throws IOException;
CodeWriter end() throws IOException;
CodeWriter field(String type, String name) throws IOException;
CodeWriter field(Type type, String name) throws IOException;
CodeWriter imports(Class<?>... imports) throws IOException;
@ -65,27 +67,27 @@ public interface CodeWriter extends Appendable{
CodeWriter packageDecl(String packageName) throws IOException;
CodeWriter privateField(String type, String name) throws IOException;
CodeWriter privateField(Type type, String name) throws IOException;
CodeWriter privateFinal(String type, String name) throws IOException;
CodeWriter privateFinal(Type type, String name) throws IOException;
CodeWriter privateFinal(String type, String name, String value) throws IOException;
CodeWriter privateFinal(Type type, String name, String value) throws IOException;
CodeWriter privateStaticFinal(String type, String name, String value) throws IOException;
CodeWriter privateStaticFinal(Type type, String name, String value) throws IOException;
CodeWriter protectedField(String type, String name) throws IOException;
CodeWriter protectedField(Type type, String name) throws IOException;
CodeWriter protectedFinal(String type, String name) throws IOException;
CodeWriter protectedFinal(Type type, String name) throws IOException;
CodeWriter protectedFinal(String type, String name, String value) throws IOException;
CodeWriter protectedFinal(Type type, String name, String value) throws IOException;
CodeWriter publicField(String type, String name) throws IOException;
CodeWriter publicField(Type type, String name) throws IOException;
CodeWriter publicFinal(String type, String name) throws IOException;
CodeWriter publicFinal(Type type, String name) throws IOException;
CodeWriter publicFinal(String type, String name, String value) throws IOException;
CodeWriter publicFinal(Type type, String name, String value) throws IOException;
CodeWriter publicStaticFinal(String type, String name, String value) throws IOException;
CodeWriter publicStaticFinal(Type type, String name, String value) throws IOException;
CodeWriter staticimports(Class<?>... imports) throws IOException;

View File

@ -24,9 +24,9 @@ import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
import com.mysema.codegen.model.ClassType;
import com.mysema.codegen.model.SimpleType;
import com.mysema.codegen.model.Type;
import com.mysema.codegen.model.TypeCategory;
import com.mysema.codegen.support.ClassUtils;
@ -60,26 +60,29 @@ public class EvaluatorFactory {
this.compilationOptions = Arrays.asList("-classpath", classpath, "-g:none");
}
@SuppressWarnings("unchecked")
private void compile(String source, Type projectionType,
String[] names, Type[] types, String id, Map<String,Object> constants) throws IOException {
// create source
StringWriter writer = new StringWriter();
JavaWriter javaw = new JavaWriter(writer);
javaw.beginClass(id, null);
SimpleType idType = new SimpleType(id, "", id);
javaw.beginClass(idType, null);
String[] params = new String[names.length];
for (int i = 0; i < params.length; i++) {
params[i] = types[i].getGenericName(true) + " " + names[i];
}
for (Map.Entry<String,Object> entry : constants.entrySet()){
String className = ClassUtils.getName(ClassUtils.normalize(entry.getValue().getClass()));
javaw.publicField(className, entry.getKey());
// String className = ClassUtils.getName(ClassUtils.normalize(entry.getValue().getClass()));
Type type = new ClassType(TypeCategory.SIMPLE, entry.getValue().getClass());
javaw.publicField(type, entry.getKey());
}
if (constants.isEmpty()){
javaw.beginStaticMethod(projectionType.getGenericName(false), "eval", params);
javaw.beginStaticMethod(projectionType, "eval", params);
}else{
javaw.beginPublicMethod(projectionType.getGenericName(false), "eval", params);
javaw.beginPublicMethod(projectionType, "eval", params);
}
javaw.append(source);
javaw.end();

View File

@ -24,6 +24,8 @@ import org.apache.commons.collections15.Transformer;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import com.mysema.codegen.model.Type;
/**
* JavaWriter is the default implementation of the CodeWriter interface
@ -69,7 +71,7 @@ public final class JavaWriter extends AbstractCodeWriter<JavaWriter>{
private final Set<String> importedPackages = new HashSet<String>();
private String type;
private Type type;
public JavaWriter(Appendable appendable){
super(appendable);
@ -154,84 +156,86 @@ public final class JavaWriter extends AbstractCodeWriter<JavaWriter>{
return this;
}
public JavaWriter beginClass(String simpleName) throws IOException{
return beginClass(simpleName, null);
@Override
public JavaWriter beginClass(Type type) throws IOException{
return beginClass(type, null);
}
@Override
public JavaWriter beginClass(String simpleName, String superClass, String... interfaces) throws IOException{
beginLine(PUBLIC_CLASS + simpleName);
public JavaWriter beginClass(Type type, Type superClass, Type... interfaces) throws IOException{
importedPackages.add(type.getPackageName());
beginLine(PUBLIC_CLASS + type.getSimpleName());
if (superClass != null){
append(EXTENDS + superClass);
append(EXTENDS + superClass.getGenericName(false, importedPackages, importedClasses));
}
if (interfaces.length > 0){
append(IMPLEMENTS);//.join(COMMA, interfaces);
append(StringUtils.join(interfaces, COMMA));
append(IMPLEMENTS);
for (int i = 0; i < interfaces.length; i++){
if (i > 0){
append(COMMA);
}
append(interfaces[i].getGenericName(false, importedPackages, importedClasses));
}
}
append(" {").nl().nl();
goIn();
type = simpleName;
if (type.contains("<")){
type = type.substring(0, type.indexOf('<'));
}
this.type = type;
return this;
}
@Override
public <T> JavaWriter beginConstructor(Collection<T> parameters, Transformer<T,String> transformer) throws IOException {
beginLine(PUBLIC + type).params(parameters, transformer).append(" {").nl();
beginLine(PUBLIC + type.getSimpleName()).params(parameters, transformer).append(" {").nl();
return goIn();
}
@Override
public JavaWriter beginConstructor(String... parameters) throws IOException{
beginLine(PUBLIC + type).params(parameters).append(" {").nl();
beginLine(PUBLIC + type.getSimpleName()).params(parameters).append(" {").nl();
return goIn();
}
@Override
public JavaWriter beginInterface(String simpleName, String... interfaces) throws IOException {
beginLine(PUBLIC_INTERFACE + simpleName);
public JavaWriter beginInterface(Type type, Type... interfaces) throws IOException {
importedPackages.add(type.getPackageName());
beginLine(PUBLIC_INTERFACE + type.getGenericName(false, importedPackages, importedClasses));
if (interfaces.length > 0){
append(EXTENDS);
append(StringUtils.join(interfaces, COMMA));
for (int i = 0; i < interfaces.length; i++){
if (i > 0){
append(COMMA);
}
append(interfaces[i].getGenericName(false, importedPackages, importedClasses));
}
}
append(" {").nl().nl();
goIn();
type = simpleName;
if (type.contains("<")){
type = type.substring(0, type.indexOf('<'));
}
return this;
this.type = type;
return this;
}
private JavaWriter beginMethod(String modifiers, String returnType, String methodName, String... args) throws IOException{
private JavaWriter beginMethod(String modifiers, Type returnType, String methodName, String... args) throws IOException{
beginLine(modifiers + returnType + SPACE + methodName).params(args).append(" {").nl();
return goIn();
}
@Override
public <T> JavaWriter beginPublicMethod(String returnType, String methodName, Collection<T> parameters, Transformer<T, String> transformer) throws IOException {
public <T> JavaWriter beginPublicMethod(Type returnType, String methodName, Collection<T> parameters, Transformer<T, String> transformer) throws IOException {
return beginMethod(PUBLIC, returnType, methodName, transform(parameters, transformer));
}
@Override
public JavaWriter beginPublicMethod(String returnType, String methodName, String... args) throws IOException{
public JavaWriter beginPublicMethod(Type returnType, String methodName, String... args) throws IOException{
return beginMethod(PUBLIC, returnType, methodName, args);
}
@Override
public <T> JavaWriter beginStaticMethod(String returnType, String methodName, Collection<T> parameters, Transformer<T, String> transformer) throws IOException {
public <T> JavaWriter beginStaticMethod(Type returnType, String methodName, Collection<T> parameters, Transformer<T, String> transformer) throws IOException {
return beginMethod(PUBLIC_STATIC, returnType, methodName, transform(parameters, transformer));
}
@Override
public JavaWriter beginStaticMethod(String returnType, String methodName, String... args) throws IOException{
public JavaWriter beginStaticMethod(Type returnType, String methodName, String... args) throws IOException{
return beginMethod(PUBLIC_STATIC, returnType, methodName, args);
}
@ -242,15 +246,15 @@ public final class JavaWriter extends AbstractCodeWriter<JavaWriter>{
}
@Override
public JavaWriter field(String type, String name) throws IOException {
public JavaWriter field(Type type, String name) throws IOException {
return stmt(type + SPACE + name).nl();
}
private JavaWriter field(String modifier, String type, String name) throws IOException{
private JavaWriter field(String modifier, Type type, String name) throws IOException{
return stmt(modifier + type + SPACE + name).nl();
}
private JavaWriter field(String modifier, String type, String name, String value) throws IOException{
private JavaWriter field(String modifier, Type type, String name, String value) throws IOException{
return stmt(modifier + type + SPACE + name + ASSIGN + value).nl();
}
@ -331,57 +335,57 @@ public final class JavaWriter extends AbstractCodeWriter<JavaWriter>{
}
@Override
public JavaWriter privateField(String type, String name) throws IOException {
public JavaWriter privateField(Type type, String name) throws IOException {
return field(PRIVATE, type, name);
}
@Override
public JavaWriter privateFinal(String type, String name) throws IOException {
public JavaWriter privateFinal(Type type, String name) throws IOException {
return field(PRIVATE_FINAL, type, name);
}
@Override
public JavaWriter privateFinal(String type, String name, String value) throws IOException {
public JavaWriter privateFinal(Type type, String name, String value) throws IOException {
return field(PRIVATE_FINAL, type, name, value);
}
@Override
public JavaWriter privateStaticFinal(String type, String name, String value) throws IOException {
public JavaWriter privateStaticFinal(Type type, String name, String value) throws IOException {
return field(PRIVATE_STATIC_FINAL, type, name, value);
}
@Override
public JavaWriter protectedField(String type, String name) throws IOException {
public JavaWriter protectedField(Type type, String name) throws IOException {
return field(PROTECTED, type, name);
}
@Override
public JavaWriter protectedFinal(String type, String name) throws IOException {
public JavaWriter protectedFinal(Type type, String name) throws IOException {
return field(PROTECTED_FINAL, type, name);
}
@Override
public JavaWriter protectedFinal(String type, String name, String value) throws IOException {
public JavaWriter protectedFinal(Type type, String name, String value) throws IOException {
return field(PROTECTED_FINAL, type, name, value);
}
@Override
public JavaWriter publicField(String type, String name) throws IOException {
public JavaWriter publicField(Type type, String name) throws IOException {
return field(PUBLIC, type, name);
}
@Override
public JavaWriter publicFinal(String type, String name) throws IOException {
public JavaWriter publicFinal(Type type, String name) throws IOException {
return field(PUBLIC_FINAL, type, name);
}
@Override
public JavaWriter publicFinal(String type, String name, String value) throws IOException {
public JavaWriter publicFinal(Type type, String name, String value) throws IOException {
return field(PUBLIC_FINAL, type, name, value);
}
@Override
public JavaWriter publicStaticFinal(String type, String name, String value) throws IOException {
public JavaWriter publicStaticFinal(Type type, String name, String value) throws IOException {
return field(PUBLIC_STATIC_FINAL, type, name, value);
}

View File

@ -34,7 +34,7 @@ public class ClassType<T> implements Type {
@Nullable
private final Class<?> primitiveClass;
public ClassType(TypeCategory category, Class<T> javaClass, @Nullable Class<?> primitiveClass) {
public ClassType(TypeCategory category, Class<T> javaClass, Class<?> primitiveClass) {
this(category, javaClass, primitiveClass, Collections.<Type>emptyList());
}

View File

@ -0,0 +1,30 @@
package com.mysema.codegen.model;
import java.util.ArrayList;
import java.util.List;
public final class Factory {
@SuppressWarnings("unchecked")
public static <T> ClassType<T> type(Class<T> clazz, Class<?>... args){
List<Type> parameters = new ArrayList<Type>(args.length);
for (Class<?> arg : args){
parameters.add(new ClassType(TypeCategory.SIMPLE, arg));
}
return new ClassType<T>(TypeCategory.SIMPLE, clazz, parameters);
}
public static Parameter param(String name, Type type){
return new Parameter(name, type);
}
@SuppressWarnings("unchecked")
public static Parameter param(String name, Class<?> type){
return new Parameter(name, new ClassType(TypeCategory.SIMPLE, type));
}
private Factory(){}
}

View File

@ -49,4 +49,8 @@ public final class Parameter {
return type.hashCode();
}
@Override
public String toString(){
return type + " " + name;
}
}

View File

@ -32,6 +32,10 @@ public class SimpleType implements Type {
type.isPrimitive(), type.isFinal(), Arrays.asList(parameters));
}
public SimpleType(String fullName, String packageName, String simpleName) {
this(TypeCategory.SIMPLE, fullName, packageName, simpleName, false, false, Collections.<Type>emptyList());
}
public SimpleType(TypeCategory category, String fullName, String packageName, String simpleName,
boolean primitiveClass, boolean finalClass,
List<Type> parameters) {

View File

@ -20,7 +20,7 @@ import java.util.Set;
*/
@SuppressWarnings("unchecked")
public final class Types {
public static final ClassType<Object> OBJECT = new ClassType<Object>(TypeCategory.SIMPLE,Object.class);
public static final ClassType<Object[]> OBJECTS = new ClassType<Object[]>(TypeCategory.ARRAY,Object[].class);
@ -61,6 +61,8 @@ public final class Types {
public static final ClassType<URI> URI = new ClassType<URI>(TypeCategory.COMPARABLE,URI.class);
public static final ClassType<Void> VOID = new ClassType<Void>(TypeCategory.SIMPLE, void.class);
private Types(){}
}

View File

@ -17,8 +17,13 @@ import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;
public class JavaWriterTest {
import com.mysema.codegen.model.Factory;
import com.mysema.codegen.model.SimpleType;
import com.mysema.codegen.model.Type;
import com.mysema.codegen.model.Types;
public class JavaWriterTest {
private static final Transformer<String,String> transformer = new Transformer<String,String>(){
@Override
public String transform(String input) {
@ -29,6 +34,8 @@ public class JavaWriterTest {
private StringWriter w;
private CodeWriter writer;
private Type testType, testType2, testSuperType, testInterface1, testInterface2;
private static void match(String resource, String text) throws IOException{
// TODO : try to compile ?
@ -40,7 +47,12 @@ public class JavaWriterTest {
@Before
public void setUp(){
w = new StringWriter();
writer = new JavaWriter(w);
writer = new JavaWriter(w);
testType = Factory.type(JavaWriterTest.class);
testType2 = new SimpleType("com.mysema.codegen.Test","com.mysema.codegen","Test");
testSuperType = new SimpleType("com.mysema.codegen.Superclass","com.mysema.codegen","Superclass");
testInterface1 = new SimpleType("com.mysema.codegen.TestInterface1","com.mysema.codegen","TestInterface1");
testInterface2 = new SimpleType("com.mysema.codegen.TestInterface2","com.mysema.codegen","TestInterface2");
}
@ -48,9 +60,9 @@ public class JavaWriterTest {
public void testBasic() throws IOException {
writer.packageDecl("com.mysema.codegen");
writer.imports(IOException.class, StringWriter.class, Test.class);
writer.beginClass("JavaWriterTest");
writer.beginClass(testType);
writer.annotation(Test.class);
writer.beginPublicMethod("void", "test");
writer.beginPublicMethod(Types.VOID, "test");
writer.line("// TODO");
writer.end();
writer.end();
@ -60,7 +72,7 @@ public class JavaWriterTest {
@Test
public void testExtends() throws IOException{
writer.beginClass("Test", "Superclass");
writer.beginClass(testType2, testSuperType);
writer.end();
match("/testExtends", w.toString());
@ -68,7 +80,7 @@ public class JavaWriterTest {
@Test
public void testImplements() throws IOException{
writer.beginClass("Test", null, "TestInterface1","TestInterface2");
writer.beginClass(testType2, null, testInterface1,testInterface2);
writer.end();
match("/testImplements", w.toString());
@ -78,7 +90,7 @@ public class JavaWriterTest {
public void testInterface() throws IOException{
writer.packageDecl("com.mysema.codegen");
writer.imports(IOException.class, StringWriter.class, Test.class);
writer.beginInterface("JavaWriterTest");
writer.beginInterface(testType);
writer.end();
match("/testInterface", w.toString());
@ -86,7 +98,7 @@ public class JavaWriterTest {
@Test
public void testInterface2() throws IOException{
writer.beginInterface("Test", "Test1");
writer.beginInterface(testType2, testInterface1);
writer.end();
match("/testInterface2", w.toString());
@ -97,7 +109,7 @@ public class JavaWriterTest {
writer.packageDecl("com.mysema.codegen");
writer.imports(IOException.class, StringWriter.class, Test.class);
writer.javadoc("JavaWriterTest is a test class");
writer.beginClass("JavaWriterTest");
writer.beginClass(testType);
writer.end();
match("/testJavadoc", w.toString());
@ -109,9 +121,9 @@ public class JavaWriterTest {
writer.packageDecl("com.mysema.codegen");
writer.imports(IOException.class, StringWriter.class);
writer.annotation(Entity.class);
writer.beginClass("JavaWriterTest");
writer.beginClass(testType);
writer.annotation(Test.class);
writer.beginPublicMethod("void", "test");
writer.beginPublicMethod(Types.VOID, "test");
writer.end();
writer.end();
@ -123,7 +135,7 @@ public class JavaWriterTest {
writer.packageDecl("com.mysema.codegen");
writer.imports(IOException.class.getPackage(), StringWriter.class.getPackage());
writer.annotation(Entity.class);
writer.beginClass("JavaWriterTest");
writer.beginClass(testType);
writer.annotation(new Test(){
@Override
public Class<? extends Throwable> expected() {
@ -139,7 +151,7 @@ public class JavaWriterTest {
public Class<? extends Annotation> annotationType() {
return Test.class;
}});
writer.beginPublicMethod("void", "test");
writer.beginPublicMethod(Types.VOID, "test");
writer.end();
writer.end();
@ -148,19 +160,19 @@ public class JavaWriterTest {
@Test
public void testFields() throws IOException{
writer.beginClass("FieldTests");
writer.beginClass(testType);
// private
writer.privateField("String", "privateField");
writer.privateStaticFinal("String", "privateStaticFinal", "\"val\"");
writer.privateField(Types.STRING, "privateField");
writer.privateStaticFinal(Types.STRING, "privateStaticFinal", "\"val\"");
// protected
writer.protectedField("String","protectedField");
writer.protectedField(Types.STRING,"protectedField");
// field
writer.field("String","field");
writer.field(Types.STRING,"field");
// public
writer.publicField("String","publicField");
writer.publicStaticFinal("String", "publicStaticFinal", "\"val\"");
writer.publicFinal("String", "publicFinalField");
writer.publicFinal("String", "publicFinalField2", "\"val\"");
writer.publicField(Types.STRING,"publicField");
writer.publicStaticFinal(Types.STRING, "publicStaticFinal", "\"val\"");
writer.publicFinal(Types.STRING, "publicFinalField");
writer.publicFinal(Types.STRING, "publicFinalField2", "\"val\"");
writer.end();
@ -169,7 +181,7 @@ public class JavaWriterTest {
@Test
public void testMethods() throws IOException{
writer.beginClass("MethodTests");
writer.beginClass(testType);
// private
// protected
@ -177,11 +189,11 @@ public class JavaWriterTest {
// method
// public
writer.beginPublicMethod("String", "publicMethod", Arrays.asList("String a"), transformer);
writer.beginPublicMethod(Types.STRING, "publicMethod", Arrays.asList("String a"), transformer);
writer.line("return null;");
writer.end();
writer.beginStaticMethod("String", "staticMethod", Arrays.asList("String a"), transformer);
writer.beginStaticMethod(Types.STRING, "staticMethod", Arrays.asList("String a"), transformer);
writer.line("return null;");
writer.end();
@ -192,7 +204,7 @@ public class JavaWriterTest {
@Test
public void testConstructors() throws IOException{
writer.beginClass("ConstructorTests");
writer.beginClass(testType);
writer.beginConstructor(Arrays.asList("String a","String b"), transformer);
writer.end();
@ -225,7 +237,7 @@ public class JavaWriterTest {
@Test
public void testSuppressWarnings() throws IOException{
writer.suppressWarnings("unused");
writer.privateField("String", "test");
writer.privateField(Types.STRING, "test");
match("/testSuppressWarnings", w.toString());
}

View File

@ -1,9 +1,9 @@
public class ConstructorTests {
public class JavaWriterTest {
public ConstructorTests(String a, String b) {
public JavaWriterTest(String a, String b) {
}
public ConstructorTests(String a) {
public JavaWriterTest(String a) {
}
}

View File

@ -1,4 +1,4 @@
public class FieldTests {
public class JavaWriterTest {
private String privateField;

View File

@ -1,3 +1,3 @@
public interface Test extends Test1 {
public interface Test extends TestInterface1 {
}

View File

@ -1,4 +1,4 @@
public class MethodTests {
public class JavaWriterTest {
public String publicMethod(String a) {
return null;