Skip to content

Commit 69a063b

Browse files
committed
Kapt3: Serialize annotation processor options to base64 to support spaces in option values
1 parent 8479618 commit 69a063b

File tree

4 files changed

+49
-17
lines changed

4 files changed

+49
-17
lines changed

libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ class Kapt3IT : BaseGradleIT() {
108108
assertSuccessful()
109109
assertKaptSuccessful()
110110
assertContains("Options: {suffix=Customized, justColon=:, justEquals==, containsColon=a:b, " +
111-
"containsEquals=a=b, startsWithColon=:a, startsWithEquals==a, endsWithColon=a:, endsWithEquals=a:}")
111+
"containsEquals=a=b, startsWithColon=:a, startsWithEquals==a, endsWithColon=a:, " +
112+
"endsWithEquals=a:, withSpace=a b c}")
112113
assertFileExists("build/generated/source/kapt/main/example/TestClassCustomized.java")
113114
assertFileExists("build/classes/main/example/TestClass.class")
114115
assertFileExists("build/classes/main/example/TestClassCustomized.class")

libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/arguments/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ kapt {
3131
arg("startsWithEquals", "=a")
3232
arg("endsWithColon", "a:")
3333
arg("endsWithEquals", "a:")
34+
arg("withSpace", "a b c") // key doesn't support spaces
3435
}
3536
}

libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@ import org.gradle.api.tasks.compile.JavaCompile
2929
import org.jetbrains.kotlin.gradle.plugin.*
3030
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
3131
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
32-
import org.jetbrains.kotlin.gradle.tasks.SyncOutputTask
32+
import java.io.ByteArrayOutputStream
3333
import java.io.File
34+
import java.io.ObjectOutputStream
35+
import javax.xml.bind.DatatypeConverter
36+
import javax.xml.bind.DatatypeConverter.printBase64Binary
3437

3538
// apply plugin: 'kotlin-kapt'
3639
class Kapt3GradleSubplugin : Plugin<Project> {
@@ -171,15 +174,27 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
171174

172175
val apOptions = kaptExtension.getAdditionalArguments(project, variantData, androidPlugin) + androidOptions
173176

174-
for ((key, value) in apOptions) {
175-
pluginOptions += SubpluginOption("apoption", "$key:$value")
176-
}
177+
SubpluginOption("apoptions", encodeAnnotationProcessingOptions(apOptions))
177178

178179
addMiscOptions(pluginOptions)
179180

180181
return pluginOptions
181182
}
182183

184+
fun encodeAnnotationProcessingOptions(options: Map<String, String>): String {
185+
val os = ByteArrayOutputStream()
186+
val oos = ObjectOutputStream(os)
187+
188+
oos.writeInt(options.size)
189+
for ((k, v) in options.entries) {
190+
oos.writeUTF(k)
191+
oos.writeUTF(v)
192+
}
193+
194+
oos.flush()
195+
return printBase64Binary(os.toByteArray())
196+
}
197+
183198
private fun Kapt3SubpluginContext.addMiscOptions(pluginOptions: MutableList<SubpluginOption>) {
184199
if (kaptExtension.generateStubs) {
185200
project.logger.warn("'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin")

plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,16 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys
3737
import org.jetbrains.kotlin.container.ComponentProvider
3838
import org.jetbrains.kotlin.context.ProjectContext
3939
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
40-
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
4140
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
4241
import org.jetbrains.kotlin.kapt3.diagnostic.DefaultErrorMessagesKapt3
4342
import org.jetbrains.kotlin.kapt3.util.KaptLogger
4443
import org.jetbrains.kotlin.psi.KtFile
4544
import org.jetbrains.kotlin.resolve.BindingTrace
4645
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
46+
import java.io.ByteArrayInputStream
4747
import java.io.File
48-
import java.util.*
48+
import java.io.ObjectInputStream
49+
import javax.xml.bind.DatatypeConverter
4950

5051
object Kapt3ConfigurationKeys {
5152
val SOURCE_OUTPUT_DIR: CompilerConfigurationKey<String> =
@@ -63,8 +64,8 @@ object Kapt3ConfigurationKeys {
6364
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
6465
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
6566

66-
val APT_OPTIONS: CompilerConfigurationKey<List<String>> =
67-
CompilerConfigurationKey.create<List<String>>("annotation processing options")
67+
val APT_OPTIONS: CompilerConfigurationKey<String> =
68+
CompilerConfigurationKey.create<String>("annotation processing options")
6869

6970
val VERBOSE_MODE: CompilerConfigurationKey<String> =
7071
CompilerConfigurationKey.create<String>("verbose mode")
@@ -100,8 +101,8 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
100101
required = false, allowMultipleOccurrences = true)
101102

102103
val APT_OPTIONS_OPTION: CliOption =
103-
CliOption("apoption", "<key>:<value>", "Annotation processor option",
104-
required = false, allowMultipleOccurrences = true)
104+
CliOption("apoptions", "options map", "Encoded annotation processor options",
105+
required = false, allowMultipleOccurrences = false)
105106

106107
val VERBOSE_MODE_OPTION: CliOption =
107108
CliOption("verbose", "true | false", "Enable verbose output", required = false)
@@ -126,7 +127,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
126127
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
127128
when (option) {
128129
ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> configuration.appendList(ANNOTATION_PROCESSOR_CLASSPATH, value)
129-
APT_OPTIONS_OPTION -> configuration.appendList(APT_OPTIONS, value)
130+
APT_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_OPTIONS, value)
130131
SOURCE_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.SOURCE_OUTPUT_DIR, value)
131132
CLASS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.CLASS_OUTPUT_DIR, value)
132133
STUBS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.STUBS_OUTPUT_DIR, value)
@@ -141,6 +142,24 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
141142
}
142143

143144
class Kapt3ComponentRegistrar : ComponentRegistrar {
145+
fun decodeAnnotationProcessingOptions(options: String): Map<String, String> {
146+
val map = LinkedHashMap<String, String>()
147+
148+
val decodedBytes = DatatypeConverter.parseBase64Binary(options)
149+
val bis = ByteArrayInputStream(decodedBytes)
150+
val ois = ObjectInputStream(bis)
151+
152+
val n = ois.readInt()
153+
154+
repeat(n) {
155+
val k = ois.readUTF()
156+
val v = ois.readUTF()
157+
map[k] = v
158+
}
159+
160+
return map
161+
}
162+
144163
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
145164
val isAptOnly = configuration.get(Kapt3ConfigurationKeys.APT_ONLY) == "true"
146165
val isVerbose = configuration.get(Kapt3ConfigurationKeys.VERBOSE_MODE) == "true"
@@ -170,11 +189,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
170189
return
171190
}
172191

173-
val apOptions = (configuration.get(APT_OPTIONS) ?: listOf())
174-
.map { it.split(':', limit = 2) }
175-
.filter { it.isNotEmpty() }
176-
.map { it[0] to it.getOrElse(1) { "" } }
177-
.toMap()
192+
val apOptions = configuration.get(APT_OPTIONS)?.let { decodeAnnotationProcessingOptions(it) } ?: emptyMap()
178193

179194
sourcesOutputDir.mkdirs()
180195

0 commit comments

Comments
 (0)