diff --git a/pom.xml b/pom.xml
new file mode 100644
index 000000000..47f2e10c3
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,51 @@
+
+
+
+ 4.0.0
+ com.mysema.codegen
+ codegen
+ 0.1.0
+ Codegen
+ Code generation and compilation for Java
+
+ com.mysema.home
+ mysema-source
+ 0.2.0
+
+ jar
+
+ 2010
+
+
+
+ net.sourceforge.collections
+ collections-generic
+ 4.01
+
+
+ com.mysema.commons
+ mysema-commons-lang
+ 0.1.7
+
+
+ commons-lang
+ commons-lang
+ 2.4
+
+
+
+
+ junit
+ junit
+ 4.4
+ test
+
+
+ javax.servlet
+ servlet-api
+
+
+
+
+
+
diff --git a/src/main/java/com/mysema/codegen/CodeWriter.java b/src/main/java/com/mysema/codegen/CodeWriter.java
new file mode 100644
index 000000000..2781f9aca
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/CodeWriter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+
+import org.apache.commons.collections15.Transformer;
+
+/**
+ * @author tiwe
+ *
+ */
+public interface CodeWriter extends Appendable{
+
+ CodeWriter annotation(Annotation annotation) throws IOException;
+
+ CodeWriter annotation(Class extends Annotation> annotation) throws IOException;
+
+ CodeWriter beginClass(String simpleName) throws IOException;
+
+ CodeWriter beginClass(String simpleName, String superClass, String... interfaces) throws IOException;
+
+ CodeWriter beginConstructor(Collection params, Transformer transformer) throws IOException;
+
+ CodeWriter beginConstructor(String... params) throws IOException;
+
+ CodeWriter beginInterface(String simpleName, String... interfaces) throws IOException;
+
+ CodeWriter beginLine(String... segments) throws IOException;
+
+ CodeWriter beginPublicMethod(String returnType, String methodName, Collection parameters, Transformer transformer) throws IOException;
+
+ CodeWriter beginPublicMethod(String returnType, String methodName, String... args) throws IOException;
+
+ CodeWriter beginStaticMethod(String type, String name, Collection params, Transformer transformer) throws IOException;
+
+ CodeWriter beginStaticMethod(String returnType, String methodName, String... args) throws IOException;
+
+ CodeWriter end() throws IOException;
+
+ CodeWriter field(String type, String name) throws IOException;
+
+ CodeWriter imports(Class>... imports) throws IOException;
+
+ CodeWriter imports(Package... imports) throws IOException;
+
+ CodeWriter javadoc(String... lines) throws IOException;
+
+ String join(String prefix, String suffix, Iterable args);
+
+ String join(String prefix, String suffix, String... args);
+
+ CodeWriter line(String... segments) throws IOException;
+
+ CodeWriter nl() throws IOException;
+
+ CodeWriter packageDecl(String packageName) throws IOException;
+
+ CodeWriter privateField(String type, String name) throws IOException;
+
+ CodeWriter privateStaticFinal(String type, String name, String value) throws IOException;
+
+ CodeWriter protectedField(String type, String name) throws IOException;
+
+ CodeWriter publicField(String type, String name) throws IOException;
+
+ CodeWriter publicFinal(String type, String name) throws IOException;
+
+ CodeWriter publicFinal(String type, String name, String value) throws IOException;
+
+ CodeWriter publicStaticFinal(String type, String name, String value) throws IOException;
+
+ CodeWriter staticimports(Class>... imports) throws IOException;
+
+ CodeWriter suppressWarnings(String type) throws IOException;
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/mysema/codegen/Evaluator.java b/src/main/java/com/mysema/codegen/Evaluator.java
new file mode 100644
index 000000000..8c942e8d2
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/Evaluator.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+/**
+ * Evaluator defines an interface for returning a value as a result of
+ * evaluating an expression using the given argument array
+ *
+ * @author tiwe
+ *
+ */
+public interface Evaluator {
+
+ /**
+ * @param args
+ * @return
+ */
+ T evaluate(Object... args);
+
+}
diff --git a/src/main/java/com/mysema/codegen/EvaluatorFactory.java b/src/main/java/com/mysema/codegen/EvaluatorFactory.java
new file mode 100644
index 000000000..18bb65cc0
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/EvaluatorFactory.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.tools.JavaCompiler;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.JavaCompiler.CompilationTask;
+
+
+/**
+ * EvaluatorFactory is a factory implementation for creating Evaluator instances
+ *
+ * @author tiwe
+ *
+ */
+public class EvaluatorFactory {
+
+ private final File classDir;
+
+ private final ClassLoader loader;
+
+ private final String classpath;
+
+ private final JavaCompiler compiler;
+
+ private final List compilationOptions;
+
+ public EvaluatorFactory(JavaCompiler compiler, File classDir,
+ URLClassLoader parent) {
+ try {
+ this.compiler = compiler;
+ this.classDir = classDir;
+ if (!classDir.exists()){
+ if (!classDir.mkdirs()){
+ throw new IllegalArgumentException(
+ classDir.getAbsolutePath() + " could not be created");
+ }
+ }
+ this.classpath = SimpleCompiler.getClassPath(parent);
+ this.loader = new URLClassLoader(new URL[] { classDir.toURI().toURL() }, parent);
+ this.compilationOptions = Arrays.asList(
+ "-classpath", classpath,
+ "-d", classDir.getAbsolutePath(),
+ "-g:none");
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void compile(String source, Class> projectionType,
+ String[] names, Class>[] types, String id) throws IOException,
+ UnsupportedEncodingException {
+ // 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] = toName(types[i]) + " " + names[i];
+ }
+
+ javaw.beginStaticMethod(toName(projectionType), "eval", params);
+ javaw.line("return ", source, ";");
+ javaw.end();
+ javaw.end();
+
+ // compile
+ try {
+ SimpleJavaFileObject javaFileObject = new StringJavaFileObject(id, writer.toString());
+ Writer out = new StringWriter();
+
+ CompilationTask task = compiler.getTask(out, null, null,
+ compilationOptions, null, Collections.singletonList(javaFileObject));
+ if (!task.call().booleanValue()) {
+ throw new RuntimeException("Compilation of " + source + " failed.\n" + out.toString());
+ }
+ } catch (URISyntaxException e) {
+ throw new IOException(e);
+ }
+
+ }
+
+ protected String toId(String source, Class> returnType, Class>... types) {
+ StringBuilder b = new StringBuilder("Q");
+ b.append("_").append(source.hashCode());
+ b.append("_").append(returnType.getName().hashCode());
+ for (Class> type : types) {
+ b.append("_").append(type.getName().hashCode());
+ }
+ return b.toString().replace('-', '0');
+ }
+
+ protected String toName(Class> cl) {
+ if (cl.isArray()) {
+ return toName(cl.getComponentType()) + "[]";
+ } else if (cl.getPackage() == null || cl.getPackage().getName().equals("java.lang")) {
+ return cl.getSimpleName();
+ } else {
+ return cl.getName().replace('$', '.');
+ }
+ }
+
+ public Evaluator createEvaluator(String source,
+ Class extends T> projectionType, String[] names, Class>[] types) {
+
+ try {
+ String id = toId(source, projectionType, types);
+ if (!new File(classDir, id + ".class").exists()) {
+ compile(source, projectionType, names, types, id);
+ }
+
+ Class> clazz = loader.loadClass(id);
+ final Method method = clazz.getMethod("eval", types);
+ return new Evaluator() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public T evaluate(Object... args) {
+ try {
+ return (T) method.invoke(null, args);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException(e);
+ } catch (InvocationTargetException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ };
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/JavaWriter.java b/src/main/java/com/mysema/codegen/JavaWriter.java
new file mode 100644
index 000000000..c38516b8e
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/JavaWriter.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+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;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.collections15.Transformer;
+import org.apache.commons.lang.StringEscapeUtils;
+
+import com.mysema.commons.lang.Assert;
+
+/**
+ * @author tiwe
+ *
+ */
+public final class JavaWriter implements Appendable, CodeWriter{
+
+ private static final String EXTENDS = " extends ";
+
+ private static final String IMPLEMENTS = " implements ";
+
+ private static final String IMPORT = "import ";
+
+ private static final String IMPORT_STATIC = "import static ";
+
+ private static final String PACKAGE = "package ";
+
+ private static final String PRIVATE = "private ";
+
+ private static final String PRIVATE_STATIC_FINAL = "private static final ";
+
+ private static final String PROTECTED = "protected ";
+
+ private static final String PUBLIC = "public ";
+
+ private static final String PUBLIC_CLASS = "public class ";
+
+ private static final String PUBLIC_FINAL = "public final ";
+
+ private static final String PUBLIC_INTERFACE = "public interface ";
+
+ private static final String PUBLIC_STATIC = "public static ";
+
+ 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){
+ this.appendable = Assert.notNull(appendable,"appendable");
+ importedPackages.add(Object.class.getPackage());
+ }
+
+ @Override
+ public JavaWriter annotation(Annotation annotation) throws IOException {
+ append(indent).append("@").appendType(annotation.annotationType()).append("(");
+ boolean first = true;
+ for (Method method : annotation.annotationType().getDeclaredMethods()){
+ if (!first){
+ append(COMMA);
+ }
+ append(method.getName()+"=");
+ try {
+ Object value = method.invoke(annotation);
+ annotationConstant(value);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ first = false;
+ }
+ return append(")").nl();
+ }
+
+
+ @Override
+ public JavaWriter annotation(Class extends Annotation> annotation) throws IOException{
+ return append(indent).append("@").appendType(annotation).nl();
+ }
+
+ @SuppressWarnings("unchecked")
+ private void annotationConstant(Object value) throws IOException{
+ if (value instanceof Class){
+ appendType((Class)value).append(".class");
+ }else if (value instanceof Number){
+ append(value.toString());
+ }else if (value instanceof Enum){
+ Enum enumValue = (Enum)value;
+ append(enumValue.getDeclaringClass().getName()+DOT+enumValue.name());
+ }else if (value instanceof String){
+ append(QUOTE + StringEscapeUtils.escapeJava(value.toString()) + QUOTE);
+ }else{
+ throw new IllegalArgumentException("Unsupported annotation value : " + value);
+ }
+ }
+
+
+ @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) || importedPackages.contains(type.getPackage())){
+ append(type.getSimpleName());
+ }else{
+ append(type.getName());
+ }
+ return this;
+ }
+
+ public JavaWriter beginClass(String simpleName) throws IOException{
+ return beginClass(simpleName, null);
+ }
+
+ @Override
+ public JavaWriter beginClass(String simpleName, String superClass, String... interfaces) throws IOException{
+ nl().append(indent + PUBLIC_CLASS + simpleName);
+ if (superClass != null){
+ append(EXTENDS + superClass);
+ }
+ if (interfaces.length > 0){
+ append(IMPLEMENTS).join(COMMA, interfaces);
+ }
+ append(" {").nl().nl();
+ goIn();
+
+ type = simpleName;
+ if (type.contains("<")){
+ type = type.substring(0, type.indexOf('<'));
+ }
+ return this;
+ }
+
+ @Override
+ public JavaWriter beginConstructor(Collection parameters, Transformer transformer) throws IOException {
+ append(indent + 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();
+ return goIn();
+ }
+
+ @Override
+ public JavaWriter beginInterface(String simpleName, String... interfaces) throws IOException {
+ nl().append(indent + PUBLIC_INTERFACE + simpleName);
+ if (interfaces.length > 0){
+ append(EXTENDS).join(COMMA, interfaces);
+ }
+ append(" {").nl().nl();
+ goIn();
+
+ type = simpleName;
+ if (type.contains("<")){
+ type = type.substring(0, type.indexOf('<'));
+ }
+ return this;
+
+ }
+
+ @Override
+ public JavaWriter beginLine(String... segments) throws IOException {
+ append(indent);
+ for (String segment : segments){
+ append(segment);
+ }
+ return this;
+ }
+
+ private JavaWriter beginMethod(String returnType, String modifiers, String methodName, String... args) throws IOException{
+ append(indent + modifiers + returnType + SPACE + methodName).params(args).append(" {").nl();
+ return goIn();
+ }
+
+ @Override
+ public JavaWriter beginPublicMethod(String returnType, String methodName, Collection parameters, Transformer transformer) throws IOException {
+ return beginMethod(returnType, PUBLIC, methodName, transform(parameters, transformer));
+ }
+
+ @Override
+ public JavaWriter beginPublicMethod(String returnType, String methodName, String... args) throws IOException{
+ return beginMethod(returnType, PUBLIC, methodName, args);
+ }
+
+ @Override
+ public JavaWriter beginStaticMethod(String returnType, String methodName, Collection parameters, Transformer transformer) throws IOException {
+ return beginMethod(returnType, PUBLIC_STATIC, methodName, transform(parameters, transformer));
+ }
+
+ @Override
+ public JavaWriter beginStaticMethod(String returnType, String methodName, String... args) throws IOException{
+ return beginMethod(returnType, PUBLIC_STATIC, methodName, args);
+ }
+
+ @Override
+ public JavaWriter end() throws IOException{
+ goOut();
+ return line("}").nl();
+ }
+
+ @Override
+ public JavaWriter field(String type, String name) throws IOException {
+ return stmt(type + SPACE + name).nl();
+ }
+
+ private JavaWriter goIn(){
+ indent += " ";
+ return this;
+ }
+
+ private JavaWriter goOut(){
+ if (indent.length() >= 4){
+ indent = indent.substring(0, indent.length() - 4);
+ }
+ return this;
+ }
+
+ @Override
+ public JavaWriter imports(Class>... imports) throws IOException{
+ for (Class> cl : imports){
+ importedClasses.add(cl);
+ line(IMPORT + cl.getName() + SEMICOLON);
+ }
+ return this;
+ }
+
+ @Override
+ public JavaWriter imports(Package... imports) throws IOException {
+ for (Package p : imports){
+ importedPackages.add(p);
+ line(IMPORT + p.getName() + ".*;");
+ }
+ return this;
+ }
+
+ @Override
+ public JavaWriter javadoc(String... lines) throws IOException {
+ line("/**");
+ for (String line : lines){
+ line(" * " + line);
+ }
+ return line(" */");
+ }
+
+ private JavaWriter join(String sep, String... args) throws IOException{
+ for (int i = 0; i < args.length; i++){
+ if (i > 0){
+ append(sep);
+ }
+ append(args[i]);
+ }
+ return this;
+ }
+
+ @Override
+ public String join(String prefix, String suffix, Iterable args) {
+ StringBuilder builder = new StringBuilder();
+ boolean first = true;
+ for (String arg : args){
+ if (!first){
+ builder.append(COMMA);
+ }
+ builder.append(prefix).append(arg).append(suffix);
+ first = false;
+ }
+ return builder.toString();
+ }
+
+
+ @Override
+ public String join(String prefix, String suffix, String... args) {
+ return join(prefix, suffix, Arrays.asList(args));
+ }
+
+ @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{
+ return line(PACKAGE + packageName + SEMICOLON).nl();
+ }
+
+ private JavaWriter params(Collection parameters, Transformer transformer) throws IOException{
+ append("(");
+ boolean first = true;
+ for (T param : parameters){
+ if (!first){
+ append(COMMA);
+ }
+ append(transformer.transform(param));
+ first = false;
+ }
+ append(")");
+ return this;
+ }
+
+ private JavaWriter params(String... params) throws IOException{
+ append("(");
+ join(COMMA, params);
+ append(")");
+ return this;
+ }
+
+ @Override
+ public JavaWriter privateField(String type, String name) throws IOException {
+ return stmt(PRIVATE + type + SPACE + name).nl();
+ }
+
+ @Override
+ public JavaWriter privateStaticFinal(String type, String name, String value) throws IOException {
+ return stmt(PRIVATE_STATIC_FINAL + type + SPACE + name + ASSIGN + value).nl();
+ }
+
+ @Override
+ public JavaWriter protectedField(String type, String name) throws IOException {
+ return stmt(PROTECTED + type + SPACE + name).nl();
+ }
+
+ @Override
+ public JavaWriter publicField(String type, String name) throws IOException {
+ return stmt(PUBLIC + type + SPACE + name).nl();
+ }
+
+ @Override
+ public JavaWriter publicFinal(String type, String name) throws IOException {
+ return stmt(PUBLIC_FINAL + type + SPACE + name).nl();
+ }
+
+ @Override
+ public JavaWriter publicFinal(String type, String name, String value) throws IOException {
+ return stmt(PUBLIC_FINAL + type + SPACE + name + ASSIGN + value).nl();
+ }
+
+ @Override
+ public JavaWriter publicStaticFinal(String type, String name, String value) throws IOException {
+ return stmt(PUBLIC_STATIC_FINAL + type + SPACE + name + ASSIGN + value).nl();
+ }
+
+ @Override
+ public JavaWriter staticimports(Class>... imports) throws IOException{
+ for (Class> cl : imports){
+ line(IMPORT_STATIC + cl.getName() + ".*;");
+ }
+ return this;
+ }
+
+ private JavaWriter stmt(String stmt) throws IOException{
+ return line(stmt + SEMICOLON);
+ }
+
+ @Override
+ public JavaWriter suppressWarnings(String type) throws IOException{
+ return line("@SuppressWarnings(\"" + type +"\")");
+ }
+
+ private String[] transform(Collection parameters, Transformer transformer){
+ String[] rv = new String[parameters.size()];
+ int i = 0;
+ for (T value : parameters){
+ rv[i++] = transformer.transform(value);
+ }
+ return rv;
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/SimpleCompiler.java b/src/main/java/com/mysema/codegen/SimpleCompiler.java
new file mode 100644
index 000000000..01a9c7118
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/SimpleCompiler.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLDecoder;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.lang.model.SourceVersion;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+/**
+ * @author tiwe
+ *
+ */
+public class SimpleCompiler implements JavaCompiler{
+
+ private final ClassLoader classLoader;
+
+ private String classPath;
+
+ private final JavaCompiler compiler;
+
+ public static String getClassPath(URLClassLoader classLoader) {
+ try{
+ StringBuilder path = new StringBuilder();
+ for (URL url : ((URLClassLoader)classLoader).getURLs()){
+ if (path.length() > 0){
+ path.append(File.pathSeparator);
+ }
+ String decodedPath = URLDecoder.decode(url.getPath(),"UTF-8");
+ path.append(new File(decodedPath).getAbsolutePath());
+ }
+ return path.toString();
+ }catch(UnsupportedEncodingException e){
+ throw new RuntimeException(e);
+ }
+ }
+
+ public SimpleCompiler(){
+ this(ToolProvider.getSystemJavaCompiler(), Thread.currentThread().getContextClassLoader());
+ }
+
+ public SimpleCompiler(JavaCompiler compiler, ClassLoader classLoader){
+ this.compiler = compiler;
+ this.classLoader = classLoader;
+ }
+
+ private String getClasspath(){
+ if (classPath == null){
+ if (classLoader instanceof URLClassLoader){
+ classPath = getClassPath((URLClassLoader)classLoader);
+ }else{
+ throw new IllegalArgumentException("Unsupported ClassLoader " + classLoader);
+ }
+ }
+ return classPath;
+ }
+
+ @Override
+ public Set getSourceVersions() {
+ return compiler.getSourceVersions();
+ }
+
+ @Override
+ public StandardJavaFileManager getStandardFileManager(
+ DiagnosticListener super JavaFileObject> diagnosticListener,
+ Locale locale, Charset charset) {
+ return compiler.getStandardFileManager(diagnosticListener, locale, charset);
+ }
+
+ @Override
+ public CompilationTask getTask(Writer out, JavaFileManager fileManager,
+ DiagnosticListener super JavaFileObject> diagnosticListener,
+ Iterable options, Iterable classes,
+ Iterable extends JavaFileObject> compilationUnits) {
+ return compiler.getTask(out, fileManager, diagnosticListener, options, classes, compilationUnits);
+ }
+
+ @Override
+ public int isSupportedOption(String option) {
+ return compiler.isSupportedOption(option);
+ }
+
+ @Override
+ public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) {
+ for (String a : arguments){
+ if (a.equals("-classpath")){
+ return compiler.run(in, out, err, arguments);
+ }
+ }
+
+ // no classpath given
+ List args = new ArrayList(arguments.length + 2);
+ args.add("-classpath");
+ args.add(getClasspath());
+ for (String arg : arguments){
+ args.add(arg);
+ }
+ return compiler.run(in, out, err, args.toArray(new String[args.size()]));
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/StringJavaFileObject.java b/src/main/java/com/mysema/codegen/StringJavaFileObject.java
new file mode 100644
index 000000000..d152bdba3
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/StringJavaFileObject.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.tools.SimpleJavaFileObject;
+
+/**
+ * @author tiwe
+ *
+ */
+public class StringJavaFileObject extends SimpleJavaFileObject {
+
+ private final String contents;
+
+ public StringJavaFileObject(String className, String contents) throws URISyntaxException{
+ super(new URI(className), Kind.SOURCE);
+ this.contents = contents;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return contents;
+ }
+
+ @Override
+ public boolean isNameCompatible(String simpleName, Kind kind) {
+ return kind.equals(getKind()) &&
+ (simpleName.equals(toUri().getPath()) || toUri().getPath().endsWith("/" + simpleName));
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/Symbols.java b/src/main/java/com/mysema/codegen/Symbols.java
new file mode 100644
index 000000000..d297ae3c7
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/Symbols.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+/**
+ * @author tiwe
+ *
+ */
+public final class Symbols {
+
+ public static final String ASSIGN = " = ";
+
+ public static final String COMMA = ", ";
+
+ public static final String DOT = ".";
+
+ public static final String DOT_CLASS = ".class";
+
+ public static final String EMPTY = "";
+
+ public static final String NEW = "new ";
+
+ public static final String NEWLINE = "\n";
+
+ public static final String QUOTE = "\"";
+
+ public static final String RETURN = "return ";
+
+ public static final String SEMICOLON = ";";
+
+ public static final String SERIAL = "serial";
+
+ public static final String SPACE = " ";
+
+ public static final String STAR = "*";
+
+ public static final String SUPER = "super";
+
+ public static final String THIS = "this";
+
+ public static final String UNCHECKED = "unchecked";
+
+ private Symbols(){}
+}
diff --git a/src/test/java/com/mysema/codegen/JavaWriterTest.java b/src/test/java/com/mysema/codegen/JavaWriterTest.java
new file mode 100644
index 000000000..a1b91ddd0
--- /dev/null
+++ b/src/test/java/com/mysema/codegen/JavaWriterTest.java
@@ -0,0 +1,61 @@
+package com.mysema.codegen;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.junit.Test;
+
+public class JavaWriterTest {
+
+ @Test
+ public void testBasic() throws IOException {
+ StringWriter w = new StringWriter();
+ CodeWriter writer = new JavaWriter(w);
+ writer.packageDecl("com.mysema.codegen");
+ writer.imports(IOException.class, StringWriter.class, Test.class);
+ writer.beginClass("JavaWriterTest");
+ writer.annotation(Test.class);
+ writer.beginPublicMethod("void", "test");
+ writer.line("// TODO");
+ writer.end();
+ writer.end();
+ System.out.println(w);
+ }
+
+ @Test
+ public void testFields() throws IOException{
+ StringWriter w = new StringWriter();
+ CodeWriter writer = new JavaWriter(w);
+ writer.beginClass("FieldTests");
+ // private
+ writer.privateField("String", "privateField");
+ writer.privateStaticFinal("String", "privateStaticFinal", "\"val\"");
+ // protected
+ writer.protectedField("String","protectedField");
+ // field
+ writer.field("String","field");
+ // public
+ writer.publicField("String","publicField");
+ writer.publicStaticFinal("String", "publicStaticFinal", "\"val\"");
+ writer.end();
+ System.out.println(w);
+ }
+
+ @Test
+ public void testMethods() throws IOException{
+ StringWriter w = new StringWriter();
+ CodeWriter writer = new JavaWriter(w);
+ writer.beginClass("MethodTests");
+ // private
+
+ // protected
+
+ // method
+
+ // public
+
+ writer.end();
+ System.out.println(w);
+ }
+
+}