From 1bd5efc80d54b65c244a78df96cdd7dab6a75e95 Mon Sep 17 00:00:00 2001 From: uuidcode Date: Wed, 13 Apr 2016 21:26:12 +0900 Subject: [PATCH] support kotlin --- pom.xml | 16 +- .../java/com/mysema/codegen/KotlinWriter.java | 637 ++++++++++++++++++ .../codegen/support/KotlinSyntaxUtils.java | 39 ++ .../com/mysema/codegen/KotlinWriterTest.java | 590 ++++++++++++++++ 4 files changed, 1280 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/mysema/codegen/KotlinWriter.java create mode 100644 src/main/java/com/mysema/codegen/support/KotlinSyntaxUtils.java create mode 100644 src/test/java/com/mysema/codegen/KotlinWriterTest.java 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 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 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 expected() { + // TODO Auto-generated method stub + return null; + } + + @Override + public long timeout() { + + return 0; + } + + @Override + public Class 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) { + } + } +}