diff --git a/pom.xml b/pom.xml
index 21c638f..afe8fc9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,8 +69,20 @@
1.0.CR3
test
-
-
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ 1.0.1-2
+ test
+
+
+ org.apache.commons
+ commons-lang3
+ 3.4
+ test
+
+
+
diff --git a/src/main/java/com/mysema/codegen/KotlinWriter.java b/src/main/java/com/mysema/codegen/KotlinWriter.java
new file mode 100644
index 0000000..15144c3
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/KotlinWriter.java
@@ -0,0 +1,637 @@
+/*
+ * Copyright 2011, Mysema Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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.QUOTE;
+
+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.List;
+import java.util.Set;
+
+import com.google.common.base.Function;
+import com.mysema.codegen.model.Parameter;
+import com.mysema.codegen.model.Type;
+import com.mysema.codegen.model.Types;
+import com.mysema.codegen.support.KotlinSyntaxUtils;
+
+/**
+ * @author uuidcode
+ *
+ */
+public class KotlinWriter extends AbstractCodeWriter {
+
+ private static final Set PRIMITIVE_TYPES = new HashSet(Arrays.asList("boolean",
+ "byte", "char", "int", "long", "short", "double", "float"));
+
+ private static final String FUN = "fun ";
+
+ private static final String OVERRIDE_FUN = "override " + FUN;
+
+ private static final String EXTENDS = " : ";
+
+ private static final String IMPORT = "import ";
+
+ private static final String PACKAGE = "package ";
+
+ private static final String PRIVATE = "private ";
+
+ private static final String PROTECTED = "protected ";
+
+ private static final String PUBLIC = "public ";
+
+ private static final String PUBLIC_CLASS = "class ";
+
+ private static final String PUBLIC_DATA_CLASS = "data class ";
+
+ private static final String PUBLIC_OBJECT = "object ";
+
+ private static final String VAR = "var ";
+
+ private static final String VAL = "val ";
+
+ private static final String CONSTRUCTOR = "constructor";
+
+ private static final String INTERFACE = "interface ";
+
+ private final Set classes = new HashSet();
+
+ private final Set packages = new HashSet();
+
+ private Type type;
+
+ private final boolean compact;
+
+ public KotlinWriter(Appendable appendable) {
+ this(appendable, false);
+ }
+
+ public KotlinWriter(Appendable appendable, boolean compact) {
+ super(appendable, 2);
+ this.classes.add("java.lang.String");
+ this.classes.add("java.lang.Long");
+ this.classes.add("java.lang.Object");
+ this.classes.add("java.lang.Integer");
+ this.classes.add("java.lang.Comparable");
+ this.compact = compact;
+ }
+
+ @Override
+ public KotlinWriter annotation(Annotation annotation) throws IOException {
+ beginLine().append("@").appendType(annotation.annotationType());
+ Method[] methods = annotation.annotationType().getDeclaredMethods();
+ if (methods.length == 1 && methods[0].getName().equals("value")) {
+ try {
+ Object value = methods[0].invoke(annotation);
+ append("(");
+ annotationConstant(value);
+ append(")");
+ } catch (IllegalArgumentException e) {
+ throw new CodegenException(e);
+ } catch (IllegalAccessException e) {
+ throw new CodegenException(e);
+ } catch (InvocationTargetException e) {
+ throw new CodegenException(e);
+ }
+ } else {
+ boolean first = true;
+ for (Method method : methods) {
+ try {
+ Object value = method.invoke(annotation);
+ if (value == null
+ || value.equals(method.getDefaultValue())
+ || (value.getClass().isArray() && Arrays.equals((Object[]) value,
+ (Object[]) method.getDefaultValue()))) {
+ continue;
+ } else if (!first) {
+ append(COMMA);
+ } else {
+ append("(");
+ }
+ append(escape(method.getName())).append("=");
+ annotationConstant(value);
+ } catch (IllegalArgumentException e) {
+ throw new CodegenException(e);
+ } catch (IllegalAccessException e) {
+ throw new CodegenException(e);
+ } catch (InvocationTargetException e) {
+ throw new CodegenException(e);
+ }
+ first = false;
+ }
+ if (!first) {
+ append(")");
+ }
+ }
+ return nl();
+ }
+
+ @Override
+ public KotlinWriter annotation(Class extends Annotation> annotation) throws IOException {
+ return beginLine().append("@").appendType(annotation).nl();
+ }
+
+ @SuppressWarnings("unchecked")
+ private void annotationConstant(Object value) throws IOException {
+ if (value.getClass().isArray()) {
+ append("arrayOf(");
+ boolean first = true;
+ for (Object o : (Object[]) value) {
+ if (!first) {
+ append(", ");
+ }
+ annotationConstant(o);
+ first = false;
+ }
+ append(")");
+ } else if (value instanceof Class) {
+ appendType((Class) value);
+ append("::class");
+ } else if (value instanceof Number || value instanceof Boolean) {
+ append(value.toString());
+ } else if (value instanceof Enum) {
+ Enum> enumValue = (Enum>) value;
+ if (classes.contains(enumValue.getClass().getName())
+ || packages.contains(enumValue.getClass().getPackage().getName())) {
+ append(enumValue.name());
+ } else {
+ append(enumValue.getDeclaringClass().getName()).append(DOT).append(enumValue.name());
+ }
+ } else if (value instanceof String) {
+ append(QUOTE).append(StringUtils.escapeJava(value.toString())).append(QUOTE);
+ } else {
+ throw new IllegalArgumentException("Unsupported annotation value : " + value);
+ }
+ }
+
+ private KotlinWriter appendType(Class> type) throws IOException {
+ if (type.isPrimitive()) {
+ append(StringUtils.capitalize(type.getName()));
+ } else if (type.getPackage() == null || classes.contains(type.getName())
+ || packages.contains(type.getPackage().getName())) {
+ append(type.getSimpleName());
+ } else {
+ append(type.getName());
+ }
+ return this;
+ }
+
+ public KotlinWriter beginObject(String header) throws IOException {
+ line(PUBLIC_OBJECT, header, " {");
+ goIn();
+ return this;
+ }
+
+ public KotlinWriter beginClass(String header) throws IOException {
+ line(PUBLIC_CLASS, header, " {");
+ goIn();
+ return this;
+ }
+
+ public KotlinWriter beginDataClass(String header, List parameterList) throws IOException {
+ beginLine(PUBLIC_DATA_CLASS, header)
+ .dataParams(parameterList.toArray(new Parameter[0]))
+ .line(" {");
+ goIn();
+ return this;
+ }
+
+ @Override
+ public KotlinWriter beginClass(Type type) throws IOException {
+ return beginClass(type, null);
+ }
+
+ @Override
+ public KotlinWriter beginClass(Type type, Type superClass, Type... interfaces)
+ throws IOException {
+ packages.add(type.getPackageName());
+ beginLine(PUBLIC_CLASS, getGenericName(false, type));
+ if (superClass != null) {
+ append(EXTENDS).append(getGenericName(false, superClass));
+ append("()");
+ }
+
+ if (interfaces.length > 0) {
+ if (superClass == null) {
+ append(EXTENDS);
+ append(getGenericName(false, interfaces[0]));
+ append(COMMA);
+ for (int i = 1; i < interfaces.length; i++) {
+ if (i > 1) {
+ append(COMMA);
+ }
+ append(getGenericName(false, interfaces[i]));
+ }
+ } else {
+ append(COMMA);
+ for (int i = 0; i < interfaces.length; i++) {
+ if (i > 0) {
+ append(COMMA);
+ }
+ append(getGenericName(false, interfaces[i]));
+ }
+ }
+ }
+ append(" {").nl().nl();
+ goIn();
+ this.type = type;
+ return this;
+ }
+
+ @Override
+ public KotlinWriter beginConstructor(Collection parameters,
+ Function transformer) throws IOException {
+ beginLine(CONSTRUCTOR).params(parameters, transformer).append(" {").nl();
+ return goIn();
+ }
+
+ @Override
+ public KotlinWriter beginConstructor(Parameter... params) throws IOException {
+ beginLine(CONSTRUCTOR).params(params).append(" {").nl();
+ return goIn();
+ }
+
+ @Override
+ public KotlinWriter beginInterface(Type type, Type... interfaces) throws IOException {
+ packages.add(type.getPackageName());
+ beginLine(INTERFACE, getGenericName(false, type));
+ if (interfaces.length > 0) {
+ append(EXTENDS);
+ append(getGenericName(false, interfaces[0]));
+ if (interfaces.length > 1) {
+ append(COMMA);
+ for (int i = 1; i < interfaces.length; i++) {
+ if (i > 1) {
+ append(COMMA);
+ }
+ append(getGenericName(false, interfaces[i]));
+ }
+ }
+
+ }
+ append(" {").nl().nl();
+ goIn();
+ this.type = type;
+ return this;
+ }
+
+ private KotlinWriter beginMethod(String modifiers, Type returnType, String methodName,
+ Parameter... args) throws IOException {
+ if (returnType.equals(Types.VOID)) {
+ beginLine(modifiers, escape(methodName)).params(args).append(" {").nl();
+ } else {
+ beginLine(modifiers, escape(methodName)).params(args)
+ .append(": ").append(getGenericName(true, returnType)).append("? {").nl();
+ }
+
+ return goIn();
+ }
+
+ @Override
+ public KotlinWriter beginPublicMethod(Type returnType, String methodName,
+ Collection parameters, Function transformer) throws IOException {
+ return beginMethod(FUN, returnType, methodName, transform(parameters, transformer));
+ }
+
+ @Override
+ public KotlinWriter beginPublicMethod(Type returnType, String methodName, Parameter... args)
+ throws IOException {
+ return beginMethod(FUN, returnType, methodName, args);
+ }
+
+ public KotlinWriter beginOverridePublicMethod(Type returnType, String methodName,
+ Collection parameters, Function transformer)
+ throws IOException {
+ return beginMethod(OVERRIDE_FUN, returnType, methodName, transform(parameters, transformer));
+ }
+
+ public KotlinWriter beginOverridePublicMethod(Type returnType, String methodName, Parameter... args)
+ throws IOException {
+ return beginMethod(OVERRIDE_FUN, returnType, methodName, args);
+ }
+
+ @Override
+ public KotlinWriter beginStaticMethod(Type returnType, String methodName,
+ Collection parameters, Function transformer) throws IOException {
+ return beginMethod(FUN, returnType, methodName, transform(parameters, transformer));
+ }
+
+ @Override
+ public KotlinWriter beginStaticMethod(Type returnType, String methodName, Parameter... args)
+ throws IOException {
+ return beginMethod(FUN, returnType, methodName, args);
+ }
+
+ @Override
+ public KotlinWriter end() throws IOException {
+ goOut();
+ return line("}").nl();
+ }
+
+ public KotlinWriter field(Type type, String name) throws IOException {
+ line(VAR, escape(name), ": ", getGenericName(true, type), "? = null");
+ return compact ? this : nl();
+ }
+
+ private KotlinWriter field(String modifier, String variable, Type type, String name) throws IOException {
+ line(modifier, variable, escape(name), ": ", getGenericName(true, type));
+ return compact ? this : nl();
+ }
+
+ private KotlinWriter field(String modifier, String variable, Type type, String name, String value)
+ throws IOException {
+ line(modifier, variable, escape(name), ": ", getGenericName(true, type), "?", ASSIGN, value);
+ return compact ? this : nl();
+ }
+
+ @Override
+ public String getClassConstant(String className) {
+ return className + "::class";
+ }
+
+ @Override
+ public String getGenericName(boolean asArgType, Type type) {
+ if (type.getParameters().isEmpty()) {
+ return getRawName(type);
+ } else {
+ StringBuilder builder = new StringBuilder();
+ builder.append(getRawName(type));
+ builder.append("<");
+ boolean first = true;
+ String fullName = type.getFullName();
+ for (Type parameter : type.getParameters()) {
+ if (!first) {
+ builder.append(", ");
+ }
+ if (parameter == null || parameter.getFullName().equals(fullName)) {
+ builder.append("_");
+ } else {
+ builder.append(getGenericName(false, parameter));
+ }
+ first = false;
+ }
+ builder.append(">? = null");
+ return builder.toString();
+ }
+ }
+
+ @Override
+ public String getRawName(Type type) {
+ String fullName = type.getFullName();
+ if (PRIMITIVE_TYPES.contains(fullName)) {
+ fullName = StringUtils.capitalize(fullName);
+ }
+ String packageName = type.getPackageName();
+ if (packageName != null && packageName.length() > 0) {
+ fullName = packageName + "." + fullName.substring(packageName.length()+1).replace('.', '$');
+ } else {
+ fullName = fullName.replace('.', '$');
+ }
+ String rv = fullName;
+ if (type.isPrimitive() && packageName.isEmpty()) {
+ rv = Character.toUpperCase(rv.charAt(0)) + rv.substring(1);
+ }
+ if (packages.contains(packageName) || classes.contains(fullName)) {
+ if (packageName.length() > 0) {
+ rv = fullName.substring(packageName.length() + 1);
+ }
+ }
+ if (rv.endsWith("[]")) {
+ rv = rv.substring(0, rv.length() - 2);
+ if (PRIMITIVE_TYPES.contains(rv)) {
+ rv = StringUtils.capitalize(rv);
+ } else if (classes.contains(rv)) {
+ rv = rv.substring(packageName.length() + 1);
+ }
+ return "Array<" + rv + ">";
+ } else {
+ return rv;
+ }
+ }
+
+ @Override
+ public KotlinWriter imports(Class>... imports) throws IOException {
+ for (Class> cl : imports) {
+ classes.add(cl.getName());
+ line(IMPORT, cl.getName());
+ }
+ nl();
+ return this;
+ }
+
+ @Override
+ public KotlinWriter imports(Package... imports) throws IOException {
+ for (Package p : imports) {
+ packages.add(p.getName());
+ line(IMPORT, p.getName(), ".*");
+ }
+ nl();
+ return this;
+ }
+
+ @Override
+ public KotlinWriter importClasses(String... imports) throws IOException {
+ for (String cl : imports) {
+ classes.add(cl);
+ line(IMPORT, cl);
+ }
+ nl();
+ return this;
+ }
+
+ @Override
+ public KotlinWriter importPackages(String... imports) throws IOException {
+ for (String p : imports) {
+ packages.add(p);
+ line(IMPORT, p, ".*");
+ }
+ nl();
+ return this;
+ }
+
+ @Override
+ public KotlinWriter javadoc(String... lines) throws IOException {
+ line("/**");
+ for (String line : lines) {
+ line(" * ", line);
+ }
+ return line(" */");
+ }
+
+ @Override
+ public KotlinWriter packageDecl(String packageName) throws IOException {
+ packages.add(packageName);
+ return line(PACKAGE, packageName).nl();
+ }
+
+ private KotlinWriter params(Collection parameters, Function transformer)
+ throws IOException {
+ append("(");
+ boolean first = true;
+ for (T param : parameters) {
+ if (!first) {
+ append(COMMA);
+ }
+ param(transformer.apply(param));
+ first = false;
+ }
+ append(")");
+ return this;
+ }
+
+ private KotlinWriter params(Parameter... params) throws IOException {
+ append("(");
+ for (int i = 0; i < params.length; i++) {
+ if (i > 0) {
+ append(COMMA);
+ nl();
+ }
+ param(params[i]);
+ }
+ append(")");
+ return this;
+ }
+
+ private KotlinWriter dataParams(Parameter... params) throws IOException {
+ append("(");
+ nl();
+
+ goIn();
+ for (int i = 0; i < params.length; i++) {
+ if (i > 0) {
+ append(COMMA);
+ nl();
+ }
+ beginLine("");
+ dataParam(params[i]);
+ }
+ append(")");
+ goOut();
+ return this;
+ }
+
+ public KotlinWriter dataParam(Parameter parameter) throws IOException {
+ append(VAR);
+ return this.param(parameter);
+ }
+
+ public KotlinWriter param(Parameter parameter) throws IOException {
+ append(escape(parameter.getName()));
+ append(": ");
+ append(getGenericName(true, parameter.getType()));
+ append("?");
+ return this;
+ }
+
+ @Override
+ public KotlinWriter privateField(Type type, String name) throws IOException {
+ return field(PRIVATE, VAR, type, name, null);
+ }
+
+ @Override
+ public KotlinWriter privateFinal(Type type, String name) throws IOException {
+ return field(PRIVATE, VAL, type, name);
+ }
+
+ @Override
+ public KotlinWriter privateFinal(Type type, String name, String value) throws IOException {
+ return field(PRIVATE, VAL, type, name, value);
+ }
+
+ @Override
+ public KotlinWriter privateStaticFinal(Type type, String name, String value) throws IOException {
+ return field(PRIVATE, VAL, type, name, value);
+ }
+
+ @Override
+ public KotlinWriter protectedField(Type type, String name) throws IOException {
+ return field(PROTECTED, VAR, type, name, null);
+ }
+
+ @Override
+ public KotlinWriter protectedFinal(Type type, String name) throws IOException {
+ return field(PROTECTED, VAL, type, name);
+ }
+
+ @Override
+ public KotlinWriter protectedFinal(Type type, String name, String value) throws IOException {
+ return field(PROTECTED, VAL, type, name, value);
+ }
+
+ @Override
+ public KotlinWriter publicField(Type type, String name) throws IOException {
+ return field(type, name);
+ }
+
+ @Override
+ public KotlinWriter publicField(Type type, String name, String value) throws IOException {
+ return field("", VAR, type, name, value);
+ }
+
+ @Override
+ public KotlinWriter publicFinal(Type type, String name) throws IOException {
+ return field(type, name);
+ }
+
+ @Override
+ public KotlinWriter publicFinal(Type type, String name, String value) throws IOException {
+ return field(PUBLIC, VAL, type, name, value);
+ }
+
+ @Override
+ public KotlinWriter publicStaticFinal(Type type, String name, String value) throws IOException {
+ return field(PUBLIC, VAL, type, name, value);
+ }
+
+ @Override
+ public KotlinWriter staticimports(Class>... imports) throws IOException {
+ throw new UnsupportedOperationException("not support static imports");
+ }
+
+ @Override
+ public KotlinWriter suppressWarnings(String type) throws IOException {
+ return line("@SuppressWarnings(\"", type, "\")");
+ }
+
+ @Override
+ public CodeWriter suppressWarnings(String... types) throws IOException {
+ return annotation(new MultiSuppressWarnings(types));
+ }
+
+ private Parameter[] transform(Collection parameters,
+ Function transformer) {
+ Parameter[] rv = new Parameter[parameters.size()];
+ int i = 0;
+ for (T value : parameters) {
+ rv[i++] = transformer.apply(value);
+ }
+ return rv;
+ }
+
+ private String escape(String token) {
+ if (KotlinSyntaxUtils.isReserved(token)) {
+ return "`" + token + "`";
+ } else {
+ return token;
+ }
+ }
+}
diff --git a/src/main/java/com/mysema/codegen/support/KotlinSyntaxUtils.java b/src/main/java/com/mysema/codegen/support/KotlinSyntaxUtils.java
new file mode 100644
index 0000000..2ea75d5
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/support/KotlinSyntaxUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010, Mysema Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.mysema.codegen.support;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author uuidcode
+ *
+ */
+public final class KotlinSyntaxUtils {
+
+ private KotlinSyntaxUtils() {}
+
+ private static final Set reserved = new HashSet(Arrays.asList("abstract", "do",
+ "finally", "import", "object", "return", "data", "var", "val", "_", ":", "case", "else",
+ "for", "lazy", "override", "open", "sealed", "try", "while", "=", "=>", "<-", "catch",
+ "it", "package", "super", "true", "with", "<:", "class",
+ "false", "if", "new", "private", "this", "type", "yield", "<%", ">:", "fun", "final",
+ "implicit", "null", "protected", "throw", "#", "@", "constructor", "companion",
+ "is", "when", "?:", "internal", "get", "set", "field", "inline"));
+
+ public static boolean isReserved(String token) {
+ return reserved.contains(token);
+ }
+}
diff --git a/src/test/java/com/mysema/codegen/KotlinWriterTest.java b/src/test/java/com/mysema/codegen/KotlinWriterTest.java
new file mode 100644
index 0000000..6d85172
--- /dev/null
+++ b/src/test/java/com/mysema/codegen/KotlinWriterTest.java
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.validation.constraints.Max;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.codehaus.plexus.util.FileUtils;
+import org.jetbrains.kotlin.maven.K2JVMCompileMojo;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Function;
+import com.mysema.codegen.model.ClassType;
+import com.mysema.codegen.model.Parameter;
+import com.mysema.codegen.model.SimpleType;
+import com.mysema.codegen.model.Type;
+import com.mysema.codegen.model.TypeCategory;
+import com.mysema.codegen.model.Types;
+
+public class KotlinWriterTest {
+
+ private static final Function transformer = new Function() {
+ @Override
+ public Parameter apply(Parameter input) {
+ return input;
+ }
+ };
+
+ private final Writer w = new StringWriter();
+
+ private final KotlinWriter writer = new KotlinWriter(w, true);
+
+ private Type testType, testType2, testSuperType, testInterface1, testInterface2;
+
+ @Before
+ public void setUp() {
+ testType = new ClassType(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");
+ }
+
+ @Test
+ public void Object() throws Exception {
+ writer.beginObject("Test");
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("object Test {"));
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Class() throws Exception {
+ writer.beginClass("Test");
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("class Test {"));
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Class_With_Interfaces() throws Exception {
+ writer.line("open class Test");
+ writer.line("interface TestInterface1");
+
+ writer.beginClass(testType, testType2, testInterface1);
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("class JavaWriterTest : Test(), TestInterface1 {"));
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Interface_With_Superinterfaces() throws Exception {
+ writer.line("interface Test");
+ writer.line("interface TestInterface1");
+
+ writer.beginInterface(testType, testType2, testInterface1);
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("interface JavaWriterTest : Test, TestInterface1 {"));
+ this.compileTest(source);
+ }
+
+ @Test
+ public void DataParam() throws IOException {
+ writer.dataParam(new Parameter("a", Types.STRING));
+ writer.line();
+ writer.dataParam(new Parameter("b", Types.INT));
+ writer.line();
+ writer.dataParam(new Parameter("is", Types.LONG));
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.checkParameter();
+ }
+
+ @Test
+ public void Param() throws IOException {
+ writer.param(new Parameter("a", Types.STRING));
+ writer.line();
+ writer.param(new Parameter("b", Types.INT));
+ writer.line();
+ writer.param(new Parameter("is", Types.LONG));
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("a: String?"));
+ assertTrue(source.contains("b: Int?"));
+ assertTrue(source.contains("`is`: Long?"));
+ }
+
+
+ private void checkParameter() {
+ assertTrue(w.toString().contains("var a: String?"));
+ assertTrue(w.toString().contains("var b: Int?"));
+ assertTrue(w.toString().contains("var `is`: Long?"));
+ }
+
+ @Test
+ public void DataClass() throws Exception {
+ writer.beginDataClass("User",
+ Arrays.asList(
+ new Parameter("a", Types.STRING),
+ new Parameter("b", Types.INT),
+ new Parameter("is", Types.LONG)));
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("data class User"));
+ this.checkParameter();
+ this.compileTest(source);
+ }
+
+ @Test
+ public void BeanAccessors() throws Exception {
+ writer.beginClass(new SimpleType("Person"));
+
+ writer.beginPublicMethod(Types.STRING, "getName");
+ writer.line("return \"Daniel Spiewak\"");
+ writer.end();
+
+ writer.beginPublicMethod(Types.VOID, "setName", new Parameter("name", Types.STRING));
+ writer.line("//");
+ writer.end();
+
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Arrays() throws Exception {
+ writer.beginClass(new SimpleType("Main"));
+ writer.field(Types.STRING.asArrayType(), "stringArray");
+ writer.beginPublicMethod(Types.VOID, "main",
+ new Parameter("args", Types.STRING.asArrayType()));
+ writer.line("//");
+ writer.end();
+
+ writer.beginPublicMethod(Types.VOID, "main2", new Parameter("args", new ClassType(
+ TypeCategory.ARRAY, String[].class)));
+ writer.line("//");
+ writer.end();
+
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("var stringArray: Array"));
+ assertTrue(source.contains("fun main(args: Array?)"));
+ assertTrue(source.contains("fun main2(args: Array?)"));
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Arrays2() throws Exception {
+ writer.beginClass(new SimpleType("Main"));
+ writer.field(Types.BYTE_P.asArrayType(), "byteArray");
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("var byteArray: Array"));
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Field() throws Exception {
+ writer.imports(List.class);
+ writer.line("class Person");
+ writer.nl();
+ writer.beginClass(new SimpleType("Main"));
+ writer.privateFinal(new SimpleType(Types.LIST, new SimpleType("Person")), "people");
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("private val people: List? = null"));
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Basic() throws Exception {
+ writer.packageDecl("com.mysema.codegen");
+ writer.imports(IOException.class, StringWriter.class, Test.class);
+ writer.beginClass(testType);
+ writer.annotation(Test.class);
+ writer.beginPublicMethod(Types.VOID, "test");
+ writer.line("// TODO");
+ writer.end();
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+ }
+
+ @Test
+ public void Extends() throws Exception {
+ writer.line("open class Superclass");
+ writer.nl();
+ writer.beginClass(testType2, testSuperType);
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Implements() throws Exception {
+ writer.line("interface TestInterface1");
+ writer.nl();
+ writer.line("interface TestInterface2");
+ writer.nl();
+ writer.beginClass(testType2, null, testInterface1, testInterface2);
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Interface() throws Exception {
+ writer.packageDecl("com.mysema.codegen");
+ writer.imports(IOException.class, StringWriter.class);
+ writer.beginInterface(testType);
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Interface2() throws Exception {
+ writer.line("interface TestInterface1");
+ writer.nl();
+ writer.beginInterface(testType2, testInterface1);
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Javadoc() throws Exception {
+ writer.packageDecl("com.mysema.codegen");
+ writer.imports(IOException.class, StringWriter.class);
+ writer.javadoc("JavaWriterTest is a test class");
+ writer.beginClass(testType);
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void AnnotationConstant() throws Exception {
+ Max annotation = new MaxImpl(0l) {
+ @Override
+ public Class>[] groups() {
+ return new Class>[] { Object.class, String.class, int.class };
+ }
+ };
+ writer.annotation(annotation);
+
+ String source = w.toString();
+ System.out.println(source);
+ }
+
+ @Test
+ public void Annotation_With_ArrayMethod() throws IOException {
+ Target annotation = new Target() {
+ @Override
+ public ElementType[] value() {
+ return new ElementType[] { ElementType.FIELD, ElementType.METHOD };
+ }
+
+ @Override
+ public Class extends Annotation> annotationType() {
+ return Target.class;
+ }
+ };
+
+ writer.imports(Target.class.getPackage());
+ writer.annotation(annotation);
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("@Target(arrayOf(FIELD, METHOD))"));
+ }
+
+ @Test
+ public void Annotations() throws IOException {
+ writer.packageDecl("com.mysema.codegen");
+ writer.imports(IOException.class, StringWriter.class);
+ writer.annotation(Entity.class);
+ writer.beginClass(testType);
+ writer.annotation(Test.class);
+ writer.beginPublicMethod(Types.VOID, "test");
+ writer.end();
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+ }
+
+ @Test
+ public void Annotations2() throws IOException {
+ writer.packageDecl("com.mysema.codegen");
+ writer.imports(IOException.class.getPackage(), StringWriter.class.getPackage());
+ writer.annotation(Entity.class);
+ writer.beginClass(testType);
+ writer.annotation(new Test() {
+ @Override
+ public Class extends Throwable> expected() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public long timeout() {
+
+ return 0;
+ }
+
+ @Override
+ public Class extends Annotation> annotationType() {
+ return Test.class;
+ }
+ });
+ writer.beginPublicMethod(Types.VOID, "test");
+ writer.end();
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+ }
+
+ @Test
+ public void Fields() throws Exception {
+ writer.beginClass(testType);
+ // private
+ writer.privateField(Types.STRING, "privateField");
+ writer.privateStaticFinal(Types.STRING, "privateStaticFinal", "\"val\"");
+ // protected
+ writer.protectedField(Types.STRING, "protectedField");
+ // field
+ writer.field(Types.STRING, "field");
+ // public
+ writer.publicField(Types.STRING, "publicField");
+ writer.publicStaticFinal(Types.STRING, "publicStaticFinal", "\"val\"");
+ writer.publicFinal(Types.STRING, "publicFinalField");
+ writer.publicFinal(Types.STRING, "publicFinalField2", "\"val\"");
+
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Methods() throws Exception {
+ writer.beginClass(testType);
+ // private
+
+ // protected
+
+ // method
+
+ // public
+ writer.beginPublicMethod(Types.STRING, "publicMethod",
+ Arrays.asList(new Parameter("a", Types.STRING)), transformer);
+ writer.line("return null");
+ writer.end();
+
+ writer.beginStaticMethod(Types.STRING, "staticMethod",
+ Arrays.asList(new Parameter("a", Types.STRING)), transformer);
+ writer.line("return null");
+ writer.end();
+
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Constructors() throws Exception {
+ writer.beginClass(testType);
+
+ writer.beginConstructor(
+ Arrays.asList(new Parameter("a", Types.STRING), new Parameter("b", Types.STRING)),
+ transformer);
+ writer.end();
+
+ writer.beginConstructor(new Parameter("a", Types.STRING));
+ writer.end();
+
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Primitive() throws Exception {
+ writer.beginClass(testType);
+
+ writer.beginConstructor(new Parameter("a", Types.INT));
+ writer.end();
+
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(source.contains("constructor("));
+ assertTrue(source.contains("a: Int?) {"));
+
+ this.compileTest(source);
+ }
+
+ @Test
+ public void Primitive_Types() throws IOException {
+ writer.field(Types.BOOLEAN_P, "field");
+ writer.field(Types.BYTE_P, "field");
+ writer.field(Types.CHAR, "field");
+ writer.field(Types.INT, "field");
+ writer.field(Types.LONG_P, "field");
+ writer.field(Types.SHORT_P, "field");
+ writer.field(Types.DOUBLE_P, "field");
+ writer.field(Types.FLOAT_P, "field");
+
+ String source = w.toString();
+ System.out.println(source);
+
+ for (String type : Arrays.asList("boolean", "byte", "char", "int", "long", "short",
+ "double", "float")) {
+ assertTrue(source.contains("`field`: " + StringUtils.capitalize(type)));
+ }
+ }
+
+ @Test
+ public void ReservedWords() throws Exception {
+ writer.beginClass(testType);
+
+ writer.beginConstructor(new Parameter("type", Types.INT));
+ writer.end();
+
+ writer.publicField(testType, "class");
+
+ writer.beginPublicMethod(testType, "var");
+ writer.end();
+
+ writer.end();
+
+ String source = w.toString();
+ System.out.println(source);
+
+ assertTrue(w.toString().contains("`type`: Int"));
+ assertTrue(w.toString().contains("`class`: JavaWriterTest"));
+ assertTrue(w.toString().contains("`var`(): JavaWriterTest"));
+ }
+
+ private void compileTest(String source) throws Exception {
+ System.out.println(new RuntimeException().getStackTrace()[1]);
+ String temp = String.valueOf(System.currentTimeMillis());
+ File sourceDir = new File(System.getProperty("java.io.tmpdir"), "sourceDir/" + temp);
+ File outputDir = new File(System.getProperty("java.io.tmpdir"), "outputDir/" + temp);
+ File testOuputDir = new File(System.getProperty("java.io.tmpdir"), "testOuputDir/" + temp);
+
+ sourceDir.mkdirs();
+ outputDir.mkdirs();
+ testOuputDir.mkdirs();
+
+ setContent(new File(sourceDir, "Test.kt"), source);
+
+ System.out.println(sourceDir.getCanonicalPath());
+ System.out.println(outputDir.getCanonicalPath());
+ System.out.println(testOuputDir.getCanonicalPath());
+
+ K2JVMCompileMojo k2JVMCompileMojo = new K2JVMCompileMojo();
+ writeField(k2JVMCompileMojo, "sourceDirs", Arrays.asList(sourceDir.getCanonicalPath()));
+ writeField(k2JVMCompileMojo, "output", outputDir.getCanonicalPath());
+ writeField(k2JVMCompileMojo, "sourceDirs", testOuputDir.getCanonicalPath());
+ writeField(k2JVMCompileMojo, "classpath", Arrays.asList("."));
+ writeField(k2JVMCompileMojo, "testClasspath", Arrays.asList("."));
+ k2JVMCompileMojo.execute();
+
+ sourceDir.delete();
+ outputDir.delete();
+ testOuputDir.delete();
+ }
+
+ public void writeField(Object target, String fieldName, Object value) {
+ try {
+ FieldUtils.writeField(target, fieldName, value, true);
+ } catch (Exception e) {
+ }
+ }
+
+ public static void setContent(File file, String data) {
+ try {
+ FileUtils.fileWrite(file, data);
+ } catch (Exception e) {
+ }
+ }
+}