diff --git a/kotlin-codegen/compiler/pom.xml b/kotlin-codegen/compiler/pom.xml
index d6aa8dd..092d18e 100644
--- a/kotlin-codegen/compiler/pom.xml
+++ b/kotlin-codegen/compiler/pom.xml
@@ -25,20 +25,10 @@
moshi
${project.version}
-
- com.squareup.moshi
- moshi-kotlin-codegen-runtime
- ${project.version}
-
org.jetbrains.kotlin
kotlin-stdlib
-
- me.eugeniomarletti
- kotlin-metadata
- 1.2.1
-
com.google.auto
auto-common
@@ -65,6 +55,32 @@
assertj-core
test
+
+
+
+ org.jetbrains.kotlin
+ kotlin-compiler-embeddable
+
+
+ org.jetbrains.kotlin
+ kotlin-annotation-processing-embeddable
+
+
+ me.eugeniomarletti
+ kotlin-metadata
+
+
+
+ com.google.testing.compile
+ compile-testing
+ test
+
@@ -129,6 +145,18 @@
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.21.0
+
+
+ false
+
+
diff --git a/kotlin-codegen/compiler/src/main/java/com/squareup/moshi/AdapterGenerator.kt b/kotlin-codegen/compiler/src/main/java/com/squareup/moshi/AdapterGenerator.kt
index 399a651..78b7428 100644
--- a/kotlin-codegen/compiler/src/main/java/com/squareup/moshi/AdapterGenerator.kt
+++ b/kotlin-codegen/compiler/src/main/java/com/squareup/moshi/AdapterGenerator.kt
@@ -168,7 +168,7 @@ internal class AdapterGenerator(
if (property.differentiateAbsentFromNull) {
result.beginControlFlow("%L -> ", index)
result.addStatement("%N = %N.fromJson(%N)",
- property.localName, property.delegateName, readerParam);
+ property.localName, property.delegateName, readerParam)
result.addStatement("%N = true", property.localIsPresentName)
result.endControlFlow()
} else {
diff --git a/kotlin-codegen/compiler/src/test/java/com/squareup/moshi/CompilerTest.kt b/kotlin-codegen/compiler/src/test/java/com/squareup/moshi/CompilerTest.kt
new file mode 100644
index 0000000..21ad81f
--- /dev/null
+++ b/kotlin-codegen/compiler/src/test/java/com/squareup/moshi/CompilerTest.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 Square, Inc.
+ *
+ * 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.squareup.moshi
+
+import org.assertj.core.api.Assertions.assertThat
+import org.jetbrains.kotlin.cli.common.ExitCode
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import javax.annotation.processing.Processor
+
+/** Execute kotlinc to confirm that either files are generated or errors are printed. */
+class CompilerTest {
+ @Rule @JvmField var temporaryFolder: TemporaryFolder = TemporaryFolder()
+
+ @Test
+ fun test() {
+ val call = KotlinCompilerCall(temporaryFolder.root)
+ call.inheritClasspath = true
+ call.addService(Processor::class, JsonClassCodeGenProcessor::class)
+ call.addKt("source.kt", """
+ |import com.squareup.moshi.JsonClass
+ |
+ |@JsonClass(generateAdapter = true)
+ |class ConstructorParameters(var a: Int, var b: Int)
+ |""".trimMargin())
+
+ val result = call.execute()
+ assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
+ assertThat(result.systemErr).contains(
+ "@JsonClass can't be applied to ConstructorParameters: must be a Kotlin data class")
+ }
+
+}
\ No newline at end of file
diff --git a/kotlin-codegen/compiler/src/test/java/com/squareup/moshi/KotlinCompilerCall.kt b/kotlin-codegen/compiler/src/test/java/com/squareup/moshi/KotlinCompilerCall.kt
new file mode 100644
index 0000000..3abb126
--- /dev/null
+++ b/kotlin-codegen/compiler/src/test/java/com/squareup/moshi/KotlinCompilerCall.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2018 Square, Inc.
+ *
+ * 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.squareup.moshi
+
+import com.google.common.collect.LinkedHashMultimap
+import okio.Buffer
+import okio.Okio
+import org.jetbrains.kotlin.cli.common.CLITool
+import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
+import java.io.File
+import java.io.FileOutputStream
+import java.io.PrintStream
+import java.net.URLClassLoader
+import java.net.URLDecoder
+import java.util.zip.ZipEntry
+import java.util.zip.ZipOutputStream
+import kotlin.reflect.KClass
+
+/** Prepares an invocation of the Kotlin compiler. */
+class KotlinCompilerCall(var scratchDir: File) {
+ val sourcesDir = File(scratchDir, "sources")
+ val classesDir = File(scratchDir, "classes")
+ val servicesJar = File(scratchDir, "services.jar")
+
+ var inheritClasspath = false
+
+ val args = mutableListOf()
+ val classpath = mutableListOf()
+ val services = LinkedHashMultimap.create, KClass<*>>()
+
+ /** Adds a source file to be compiled. */
+ fun addKt(path: String, source: String) {
+ val sourceFile = File(sourcesDir, path)
+ sourceFile.parentFile.mkdirs()
+ Okio.buffer(Okio.sink(sourceFile)).use {
+ it.writeUtf8(source)
+ }
+ }
+
+ /** Adds a service like an annotation processor to make available to the compiler. */
+ fun addService(serviceClass: KClass<*>, implementation: KClass<*>) {
+ services.put(serviceClass, implementation)
+ }
+
+ fun execute(): KotlinCompilerResult {
+ val fullArgs = mutableListOf()
+ fullArgs.addAll(args)
+
+ fullArgs.add("-d")
+ fullArgs.add(classesDir.toString())
+
+ val fullClasspath = fullClasspath()
+ if (fullClasspath.isNotEmpty()) {
+ fullArgs.add("-classpath")
+ fullArgs.add(fullClasspath.joinToString(separator = ":"))
+ }
+
+ for (source in sourcesDir.listFiles()) {
+ fullArgs.add(source.toString())
+ }
+
+ fullArgs.addAll(annotationProcessorArgs())
+
+ val systemErrBuffer = Buffer()
+ val oldSystemErr = System.err
+ System.setErr(PrintStream(systemErrBuffer.outputStream()))
+ try {
+ val exitCode = CLITool.doMainNoExit(K2JVMCompiler(), fullArgs.toTypedArray())
+ val systemErr = systemErrBuffer.readUtf8()
+ return KotlinCompilerResult(systemErr, exitCode)
+ } finally {
+ System.setErr(oldSystemErr)
+ }
+ }
+
+ /** Returns arguments necessary to enable and configure kapt3. */
+ private fun annotationProcessorArgs(): List {
+ val kaptSourceDir = File(scratchDir, "kapt/sources")
+ val kaptStubsDir = File(scratchDir, "kapt/stubs")
+
+ return listOf(
+ "-Xplugin=${kapt3Jar()}",
+ "-P", "plugin:org.jetbrains.kotlin.kapt3:sources=$kaptSourceDir",
+ "-P", "plugin:org.jetbrains.kotlin.kapt3:classes=$classesDir",
+ "-P", "plugin:org.jetbrains.kotlin.kapt3:stubs=$kaptStubsDir",
+ "-P", "plugin:org.jetbrains.kotlin.kapt3:apclasspath=$servicesJar",
+ "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"
+ )
+ }
+
+ /** Returns the classpath to use when compiling code. */
+ private fun fullClasspath(): List {
+ val result = mutableListOf()
+ result.addAll(classpath)
+
+ // Copy over the classpath of the running application.
+ if (inheritClasspath) {
+ for (classpathFile in classpathFiles()) {
+ result.add(classpathFile.toString())
+ }
+ }
+
+ if (!services.isEmpty) {
+ writeServicesJar()
+ result.add(servicesJar.toString())
+ }
+
+ return result.toList()
+ }
+
+ /**
+ * Generate a .jar file that holds ServiceManager registrations. Necessary because AutoService's
+ * results might not be visible to this test.
+ */
+ private fun writeServicesJar() {
+ ZipOutputStream(FileOutputStream(servicesJar)).use { zipOutputStream ->
+ for (entry in services.asMap()) {
+ zipOutputStream.putNextEntry(
+ ZipEntry("META-INF/services/${entry.key.qualifiedName}"))
+ val serviceFile = Okio.buffer(Okio.sink(zipOutputStream))
+ for (implementation in entry.value) {
+ serviceFile.writeUtf8(implementation.qualifiedName)
+ serviceFile.writeUtf8("\n")
+ }
+ serviceFile.emit() // Don't close the entry; that closes the file.
+ zipOutputStream.closeEntry()
+ }
+ }
+ }
+
+ /** Returns the files on the host process' classpath. */
+ private fun classpathFiles(): List {
+ val classLoader = CompilerTest::class.java.classLoader
+ if (classLoader !is URLClassLoader) {
+ throw UnsupportedOperationException("unable to extract classpath from $classLoader")
+ }
+
+ val result = mutableListOf()
+ for (url in classLoader.urLs) {
+ if (url.protocol != "file") {
+ throw UnsupportedOperationException("unable to handle classpath element $url")
+ }
+ result.add(File(URLDecoder.decode(url.path, "UTF-8")))
+ }
+ return result.toList()
+ }
+
+ /** Returns the path to the kotlin-annotation-processing .jar file. */
+ private fun kapt3Jar(): File {
+ for (file in classpathFiles()) {
+ if (file.name.startsWith("kotlin-annotation-processing-embeddable")) return file
+ }
+ throw IllegalStateException("no kotlin-annotation-processing-embeddable jar on classpath:\n " +
+ "${classpathFiles().joinToString(separator = "\n ")}}")
+ }
+}
\ No newline at end of file
diff --git a/kotlin-codegen/compiler/src/test/java/com/squareup/moshi/KotlinCompilerResult.kt b/kotlin-codegen/compiler/src/test/java/com/squareup/moshi/KotlinCompilerResult.kt
new file mode 100644
index 0000000..27a65a3
--- /dev/null
+++ b/kotlin-codegen/compiler/src/test/java/com/squareup/moshi/KotlinCompilerResult.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 Square, Inc.
+ *
+ * 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.squareup.moshi
+
+import org.jetbrains.kotlin.cli.common.ExitCode
+
+class KotlinCompilerResult(
+ val systemErr: String,
+ var exitCode: ExitCode
+)
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index d1d2a10..eebd3a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,11 +30,13 @@
UTF-8
1.7
1.2.21
+ 1.2.1
1.13.0
+ 0.8
4.12
1.7.0
@@ -97,6 +99,26 @@
${kotlin.version}
test
+
+ org.jetbrains.kotlin
+ kotlin-compiler-embeddable
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-annotation-processing-embeddable
+ ${kotlin.version}
+
+
+ me.eugeniomarletti
+ kotlin-metadata
+ ${kotlin-metadata.version}
+
+
+ com.google.testing.compile
+ compile-testing
+ ${compile-testing.version}
+