diff --git a/libraries/pom.xml b/libraries/pom.xml
index ba346994c2e..a4ec559507f 100644
--- a/libraries/pom.xml
+++ b/libraries/pom.xml
@@ -105,6 +105,7 @@
tools/kotlin-js-tests
tools/kotlin-js-tests-junit
tools/kotlin-annotation-processing
+ tools/kotlin-annotation-processing-maven
tools/kotlin-allopen
tools/kotlin-maven-allopen
tools/kotlin-noarg
diff --git a/libraries/tools/kotlin-annotation-processing-maven/pom.xml b/libraries/tools/kotlin-annotation-processing-maven/pom.xml
new file mode 100755
index 00000000000..c6977b95173
--- /dev/null
+++ b/libraries/tools/kotlin-annotation-processing-maven/pom.xml
@@ -0,0 +1,178 @@
+
+
+
+ 4.0.0
+
+ 3.0.4
+ ${basedir}/../../../plugins/kapt3/src
+ ${basedir}/target/src/main/kotlin
+ ${basedir}/target/src/test/kotlin
+ ${basedir}/target/resource
+
+
+
+ org.jetbrains.kotlin
+ kotlin-project
+ 1.1-SNAPSHOT
+ ../../pom.xml
+
+
+ kotlin-annotation-processing-maven
+ jar
+
+ Annotation Processor wrapper for Kotlin Maven plugin
+
+
+
+ jetbrains-utils
+ http://repository.jetbrains.com/utils
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ ${project.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-compiler
+ ${project.version}
+ provided
+
+
+ org.jetbrains.kotlin
+ gradle-api
+ 1.6
+ provided
+
+
+ com.android.tools.build
+ gradle
+ 1.1.0
+ provided
+
+
+
+
+ ${annotation-processing.target-src}
+ ${annotation-processing.target-src-test}
+
+
+ ${annotation-processing.target-resource}
+
+
+
+
+
+ maven-resources-plugin
+ 3.0.0
+
+
+ copy-sources
+ validate
+
+ copy-resources
+
+
+ ${annotation-processing.target-src}
+
+ ${annotation-processing.src}
+
+
+
+
+ copy-resources
+ validate
+
+ copy-resources
+
+
+ ${annotation-processing.target-resource}/META-INF
+
+ ${annotation-processing.src}/META-INF
+
+
+
+
+
+
+ kotlin-maven-plugin
+ org.jetbrains.kotlin
+ ${project.version}
+
+ ${env.JDK_18}
+
+ ${basedir}/kotlinAnnotation
+
+
+
+
+
+ compile
+ compile
+ compile
+
+
+ ${annotation-processing.target-src}
+
+
+
+
+
+ test-compile
+ test-compile
+ test-compile
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.6
+ 1.6
+
+
+
+ maven-failsafe-plugin
+ 2.6
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+
+
+
+
+ tools_jar_profile
+
+ false
+
+ kotlin-annotation-processing-maven-build.txt
+
+
+
+ ${env.JDK_18}/lib/tools.jar
+
+
+
+ com.sun
+ tools
+ 1.8.0
+ system
+ ${toolsjar}
+
+
+
+
+
diff --git a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/K2JVMCompileMojo.java b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/K2JVMCompileMojo.java
index a96681fbca6..7d9cdde02c9 100644
--- a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/K2JVMCompileMojo.java
+++ b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/K2JVMCompileMojo.java
@@ -17,16 +17,15 @@
package org.jetbrains.kotlin.maven;
import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugins.annotations.LifecyclePhase;
-import org.apache.maven.plugins.annotations.Mojo;
-import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.plugins.annotations.*;
import org.apache.maven.project.MavenProject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments;
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler;
+import org.jetbrains.kotlin.maven.kapt.AnnotationProcessingManager;
import java.io.File;
+import java.util.ArrayList;
import java.util.List;
import static com.intellij.openapi.util.text.StringUtil.join;
@@ -83,6 +82,24 @@ public class K2JVMCompileMojo extends KotlinCompileMojoBase getSourceFilePaths() {
+ List paths = super.getSourceFilePaths();
+
+ File sourcesDir = AnnotationProcessingManager.getGeneratedSourcesDirectory(project, getSourceSetName());
+ if (sourcesDir.isDirectory()) {
+ paths = new ArrayList(paths);
+ paths.add(sourcesDir.getAbsolutePath());
+ }
+
+ return paths;
+ }
+
+ @NotNull
+ protected String getSourceSetName() {
+ return AnnotationProcessingManager.COMPILE_SOURCE_SET_NAME;
+ }
+
@Override
protected void configureSpecificCompilerArguments(@NotNull K2JVMCompilerArguments arguments) throws MojoExecutionException {
arguments.destination = output;
diff --git a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/KotlinTestCompileMojo.java b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/KotlinTestCompileMojo.java
index 1d6cab86764..692e87d9be0 100644
--- a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/KotlinTestCompileMojo.java
+++ b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/KotlinTestCompileMojo.java
@@ -25,6 +25,8 @@ import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments;
+import org.jetbrains.kotlin.maven.kapt.AnnotationProcessingManager;
+import org.jetbrains.kotlin.maven.kapt.KaptTestJvmCompilerMojo;
import java.util.List;
@@ -33,6 +35,10 @@ import java.util.List;
*
* @noinspection UnusedDeclaration
*/
+
+/** Note!
+ * Please change {@link KaptTestJvmCompilerMojo} as well as it was majorly copied from this file. */
+
@Mojo(name = "test-compile",
defaultPhase = LifecyclePhase.TEST_COMPILE,
requiresDependencyResolution = ResolutionScope.TEST
@@ -95,4 +101,9 @@ public class KotlinTestCompileMojo extends K2JVMCompileMojo {
protected List getRelatedSourceRoots(MavenProject project) {
return project.getTestCompileSourceRoots();
}
+
+ @NotNull
+ protected String getSourceSetName() {
+ return AnnotationProcessingManager.TEST_SOURCE_SET_NAME;
+ }
}
diff --git a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/AnnotationProcessingManager.java b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/AnnotationProcessingManager.java
new file mode 100644
index 00000000000..d2ea8728d41
--- /dev/null
+++ b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/AnnotationProcessingManager.java
@@ -0,0 +1,191 @@
+package org.jetbrains.kotlin.maven.kapt;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.artifact.resolver.ResolutionErrorHandler;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.compiler.DependencyCoordinate;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.repository.RepositorySystem;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+public class AnnotationProcessingManager {
+ private final ArtifactHandlerManager artifactHandlerManager;
+ private final MavenSession session;
+ private final MavenProject project;
+ private final RepositorySystem repositorySystem;
+ private final ResolutionErrorHandler resolutionErrorHandler;
+
+ AnnotationProcessingManager(@NotNull ArtifactHandlerManager artifactHandlerManager,
+ @NotNull MavenSession session,
+ @NotNull MavenProject project,
+ @NotNull RepositorySystem repositorySystem,
+ @NotNull ResolutionErrorHandler resolutionErrorHandler) {
+ this.artifactHandlerManager = artifactHandlerManager;
+ this.session = session;
+ this.project = project;
+ this.repositorySystem = repositorySystem;
+ this.resolutionErrorHandler = resolutionErrorHandler;
+ }
+
+ private final static DependencyCoordinate KAPT_DEPENDENCY = new DependencyCoordinate();
+
+ public final static String COMPILE_SOURCE_SET_NAME = "compile";
+ public final static String TEST_SOURCE_SET_NAME = "test";
+
+ static {
+ KAPT_DEPENDENCY.setGroupId("org.jetbrains.kotlin");
+ KAPT_DEPENDENCY.setArtifactId("kotlin-annotation-processing-maven");
+ try {
+ KAPT_DEPENDENCY.setVersion(getMavenPluginVersion());
+ }
+ catch (MojoExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @NotNull
+ public static File getGeneratedSourcesDirectory(@NotNull MavenProject project, @NotNull String sourceSetName) {
+ return new File(getTargetDirectory(project), "generated-sources/kapt/" + sourceSetName);
+ }
+
+ @NotNull
+ static File getStubsDirectory(@NotNull MavenProject project, @NotNull String sourceSetName) {
+ return new File(getTargetDirectory(project), "kaptStubs/" + sourceSetName);
+ }
+
+ @NotNull
+ static File getGeneratedClassesDirectory(@NotNull MavenProject project, @NotNull String sourceSetName) {
+ if (sourceSetName.equals(COMPILE_SOURCE_SET_NAME)) {
+ return new File(project.getModel().getBuild().getOutputDirectory());
+ }
+ else if (sourceSetName.equals(TEST_SOURCE_SET_NAME)) {
+ return new File(project.getModel().getBuild().getTestOutputDirectory());
+ }
+ else {
+ throw new IllegalArgumentException("'" + COMPILE_SOURCE_SET_NAME + "' or '" +
+ TEST_SOURCE_SET_NAME + "' expected");
+ }
+ }
+
+ @NotNull
+ private static File getTargetDirectory(@NotNull MavenProject project) {
+ return new File(project.getModel().getBuild().getDirectory());
+ }
+
+ @NotNull
+ ResolvedArtifacts resolveAnnotationProcessors(@Nullable List aptDependencies) throws Exception {
+ if (aptDependencies == null) {
+ aptDependencies = Collections.emptyList();
+ }
+
+ Set requiredArtifacts = new LinkedHashSet();
+
+ requiredArtifacts.add(getArtifact(artifactHandlerManager, KAPT_DEPENDENCY));
+
+ for (DependencyCoordinate dependency : aptDependencies) {
+ requiredArtifacts.add(getArtifact(artifactHandlerManager, dependency));
+ }
+
+ ArtifactResolutionRequest request = new ArtifactResolutionRequest()
+ .setArtifact(requiredArtifacts.iterator().next())
+ .setResolveRoot(true)
+ .setResolveTransitively(true)
+ .setArtifactDependencies(requiredArtifacts)
+ .setLocalRepository(session.getLocalRepository())
+ .setRemoteRepositories(project.getRemoteArtifactRepositories());
+
+ ArtifactResolutionResult resolutionResult = repositorySystem.resolve(request);
+ resolutionErrorHandler.throwErrors(request, resolutionResult);
+
+ if (resolutionResult == null || resolutionResult.getArtifacts() == null) {
+ throw new IllegalStateException("Annotation processing artifacts were not resolved.");
+ }
+
+ List apClasspath = new ArrayList(resolutionResult.getArtifacts().size());
+ String kaptCompilerPluginArtifact = null;
+
+ for (Artifact artifact : resolutionResult.getArtifacts()) {
+ if (artifact == null) {
+ continue;
+ }
+
+ if (artifact.getGroupId().equals(KAPT_DEPENDENCY.getGroupId())
+ && artifact.getArtifactId().equals(KAPT_DEPENDENCY.getArtifactId())) {
+ kaptCompilerPluginArtifact = artifact.getFile().getAbsolutePath();
+ }
+ else {
+ apClasspath.add(artifact.getFile().getAbsolutePath());
+ }
+ }
+
+ if (kaptCompilerPluginArtifact == null) {
+ throw new IllegalStateException("Kapt compiler plugin artifact was not resolved.");
+ }
+
+ return new ResolvedArtifacts(apClasspath, kaptCompilerPluginArtifact);
+ }
+
+ @NotNull
+ private Artifact getArtifact(
+ @NotNull ArtifactHandlerManager artifactHandlerManager,
+ @NotNull DependencyCoordinate dependency) throws Exception {
+ ArtifactHandler handler = artifactHandlerManager.getArtifactHandler(dependency.getType());
+
+ return new DefaultArtifact(
+ dependency.getGroupId(),
+ dependency.getArtifactId(),
+ VersionRange.createFromVersionSpec(dependency.getVersion()),
+ Artifact.SCOPE_RUNTIME,
+ dependency.getType(),
+ dependency.getClassifier(),
+ handler,
+ false);
+ }
+
+ @NotNull
+ private static String getMavenPluginVersion() throws MojoExecutionException {
+ ClassLoader classLoader = AnnotationProcessingManager.class.getClassLoader();
+ InputStream pomPropertiesIs = classLoader.getResourceAsStream(
+ "META-INF/maven/org.jetbrains.kotlin/kotlin-maven-plugin/pom.properties");
+ if (pomPropertiesIs == null) {
+ throw new MojoExecutionException("Can't resolve the version of kotlin-maven-plugin");
+ }
+
+ Properties properties = new Properties();
+ try {
+ properties.load(pomPropertiesIs);
+ }
+ catch (IOException e) {
+ throw new MojoExecutionException("Error while reading kotlin-maven-plugin/pom.properties", e);
+ }
+
+ return properties.getProperty("version");
+ }
+
+ class ResolvedArtifacts {
+ @NotNull
+ final List annotationProcessingClasspath;
+
+ @NotNull
+ final String kaptCompilerPluginArtifact;
+
+ ResolvedArtifacts(@NotNull List annotationProcessingClasspath,
+ @NotNull String kaptCompilerPluginArtifact) {
+ this.annotationProcessingClasspath = annotationProcessingClasspath;
+ this.kaptCompilerPluginArtifact = kaptCompilerPluginArtifact;
+ }
+ }
+}
diff --git a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptJVMCompilerMojo.java b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptJVMCompilerMojo.java
new file mode 100644
index 00000000000..cc477ac1e4d
--- /dev/null
+++ b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptJVMCompilerMojo.java
@@ -0,0 +1,183 @@
+package org.jetbrains.kotlin.maven.kapt;
+
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.resolver.ResolutionErrorHandler;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.compiler.DependencyCoordinate;
+import org.apache.maven.plugins.annotations.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments;
+import org.jetbrains.kotlin.maven.K2JVMCompileMojo;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.jetbrains.kotlin.maven.kapt.AnnotationProcessingManager.getGeneratedClassesDirectory;
+import static org.jetbrains.kotlin.maven.kapt.AnnotationProcessingManager.getGeneratedSourcesDirectory;
+import static org.jetbrains.kotlin.maven.kapt.AnnotationProcessingManager.getStubsDirectory;
+
+/** @noinspection UnusedDeclaration */
+@Mojo(name = "kapt", defaultPhase = LifecyclePhase.PROCESS_SOURCES, requiresDependencyResolution = ResolutionScope.COMPILE)
+public class KaptJVMCompilerMojo extends K2JVMCompileMojo {
+ @Parameter
+ private String[] annotationProcessors;
+
+ @Parameter
+ private List annotationProcessorPaths;
+
+ @Parameter
+ private boolean useLightAnalysis = true;
+
+ @Parameter
+ private boolean correctErrorTypes = false;
+
+ // Components for AnnotationProcessingManager
+
+ @Component
+ private ArtifactHandlerManager artifactHandlerManager;
+
+ @Parameter( defaultValue = "${session}", readonly = true, required = true )
+ private MavenSession session;
+
+ @Component
+ private ResolutionErrorHandler resolutionErrorHandler;
+
+ private AnnotationProcessingManager cachedAnnotationProcessingManager;
+
+ private AnnotationProcessingManager getAnnotationProcessingManager() {
+ if (cachedAnnotationProcessingManager != null) {
+ return cachedAnnotationProcessingManager;
+ }
+
+ cachedAnnotationProcessingManager = new AnnotationProcessingManager(
+ artifactHandlerManager, session, project, system, resolutionErrorHandler);
+ return cachedAnnotationProcessingManager;
+ }
+
+ @NotNull
+ private List getKaptOptions(
+ @NotNull K2JVMCompilerArguments arguments,
+ @NotNull AnnotationProcessingManager.ResolvedArtifacts resolvedArtifacts
+ ) {
+ List options = new ArrayList();
+
+ options.add(new KaptOption("aptOnly", true));
+ options.add(new KaptOption("useLightAnalysis", useLightAnalysis));
+ options.add(new KaptOption("correctErrorTypes", correctErrorTypes));
+ options.add(new KaptOption("processors", annotationProcessors));
+
+ if (arguments.verbose) {
+ options.add(new KaptOption("verbose", true));
+ }
+
+ for (String entry : resolvedArtifacts.annotationProcessingClasspath) {
+ options.add(new KaptOption("apclasspath", entry));
+ }
+
+ String sourceSetName = getSourceSetName();
+ File sourcesDirectory = getGeneratedSourcesDirectory(project, sourceSetName);
+ File classesDirectory = getGeneratedClassesDirectory(project, sourceSetName);
+ File stubsDirectory = getStubsDirectory(project, sourceSetName);
+
+ addKaptSourcesDirectory(sourcesDirectory.getPath());
+
+ mkdirsSafe(sourcesDirectory);
+ mkdirsSafe(classesDirectory);
+ mkdirsSafe(stubsDirectory);
+
+ options.add(new KaptOption("sources", sourcesDirectory.getAbsolutePath()));
+ options.add(new KaptOption("classes", classesDirectory.getAbsolutePath()));
+ options.add(new KaptOption("stubs", stubsDirectory.getAbsolutePath()));
+
+ return options;
+ }
+
+ protected void addKaptSourcesDirectory(@NotNull String path) {
+ project.addCompileSourceRoot(path);
+ }
+
+ private void mkdirsSafe(@NotNull File directory) {
+ if (!directory.mkdirs()) {
+ getLog().warn("Unable to create directory " + directory);
+ }
+ }
+
+ @Override
+ protected void configureSpecificCompilerArguments(@NotNull K2JVMCompilerArguments arguments) throws MojoExecutionException {
+ super.configureSpecificCompilerArguments(arguments);
+
+ AnnotationProcessingManager.ResolvedArtifacts resolvedArtifacts;
+
+ try {
+ resolvedArtifacts = getAnnotationProcessingManager().resolveAnnotationProcessors(annotationProcessorPaths);
+ }
+ catch (Exception e) {
+ throw new MojoExecutionException("Error while processing kapt options", e);
+ }
+
+ String[] kaptOptions = renderKaptOptions(getKaptOptions(arguments, resolvedArtifacts));
+ arguments.pluginOptions = joinArrays(arguments.pluginOptions, kaptOptions);
+
+ String jdkToolsJarPath = getJdkToolsJarPath();
+ arguments.pluginClasspaths = joinArrays(arguments.pluginClasspaths,
+ (jdkToolsJarPath == null)
+ ? new String[] { resolvedArtifacts.kaptCompilerPluginArtifact }
+ : new String[] { jdkToolsJarPath, resolvedArtifacts.kaptCompilerPluginArtifact });
+ }
+
+ @Nullable
+ private String getJdkToolsJarPath() {
+ String javaHomePath = System.getProperty("java.home");
+ if (javaHomePath == null || javaHomePath.isEmpty()) {
+ getLog().warn("Can't determine Java home, 'java.home' property does not exist");
+ return null;
+ }
+ File javaHome = new File(javaHomePath);
+ File toolsJar = new File(javaHome, "lib/tools.jar");
+ if (toolsJar.exists()) {
+ return toolsJar.getAbsolutePath();
+ }
+
+ // We might be inside jre.
+ if (javaHome.getName().equals("jre")) {
+ toolsJar = new File(javaHome.getParent(), "lib/tools.jar");
+ if (toolsJar.exists()) {
+ return toolsJar.getAbsolutePath();
+ }
+ }
+
+ getLog().debug(toolsJar.getAbsolutePath() + " does not exist");
+ getLog().warn("'tools.jar' was not found, kapt may work unreliably");
+ return null;
+ }
+
+ @NotNull
+ private String[] renderKaptOptions(@NotNull List options) {
+ String[] result = new String[options.size()];
+ int i = 0;
+ for (KaptOption option : options) {
+ result[i++] = option.toString();
+ }
+ return result;
+ }
+
+ @NotNull
+ private String[] joinArrays(@Nullable String[] first, @Nullable String[] second) {
+ if (first == null) {
+ first = new String[0];
+ }
+ if (second == null) {
+ second = new String[0];
+ }
+
+ String[] result = new String[first.length + second.length];
+
+ System.arraycopy(first, 0, result, 0, first.length);
+ System.arraycopy(second, 0, result, first.length, second.length);
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptOption.java b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptOption.java
new file mode 100644
index 00000000000..8941e578998
--- /dev/null
+++ b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptOption.java
@@ -0,0 +1,48 @@
+package org.jetbrains.kotlin.maven.kapt;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+class KaptOption {
+ @NotNull
+ private final String key;
+
+ @NotNull
+ private final String value;
+
+ KaptOption(@NotNull String key, boolean value) {
+ this(key, String.valueOf(value));
+ }
+
+ KaptOption(@NotNull String key, @Nullable String[] value) {
+ this(key, renderStringArray(value));
+ }
+
+ KaptOption(@NotNull String key, @Nullable String value) {
+ this.key = key;
+ this.value = String.valueOf(value);
+ }
+
+ @NotNull
+ private static String renderStringArray(@Nullable String[] arr) {
+ if (arr == null) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ for (String s : arr) {
+ if (sb.length() > 0) {
+ sb.append(',');
+ }
+ sb.append(s);
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return "plugin:org.jetbrains.kotlin.kapt3:" + key + "=" + value;
+ }
+}
diff --git a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptTestJvmCompilerMojo.java b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptTestJvmCompilerMojo.java
new file mode 100644
index 00000000000..13eb61255d6
--- /dev/null
+++ b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/kapt/KaptTestJvmCompilerMojo.java
@@ -0,0 +1,90 @@
+package org.jetbrains.kotlin.maven.kapt;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments;
+
+import java.util.List;
+
+/** Note! This file was majorly copied from {@link org.jetbrains.kotlin.maven.KotlinTestCompileMojo}.
+ * Please change the original file if you make changes to {@link KaptTestJvmCompilerMojo}.
+ *
+ * @noinspection UnusedDeclaration
+ */
+@Mojo(name = "test-kapt", defaultPhase = LifecyclePhase.PROCESS_TEST_SOURCES, requiresDependencyResolution = ResolutionScope.TEST)
+public class KaptTestJvmCompilerMojo extends KaptJVMCompilerMojo {
+ /**
+ * Flag to allow test compilation to be skipped.
+ */
+ @Parameter(property = "maven.test.skip", defaultValue = "false")
+ private boolean skip;
+
+ // TODO it would be nice to avoid using 2 injected fields for sources
+ // but I've not figured out how to have a defaulted parameter value
+ // which is also customisable inside an in a maven pom.xml
+ // so for now lets just use 2 fields
+
+ /**
+ * The default source directories containing the sources to be compiled.
+ */
+ @Parameter(defaultValue = "${project.testCompileSourceRoots}", required = true)
+ private List defaultSourceDirs;
+
+ /**
+ * The source directories containing the sources to be compiled.
+ */
+ @Parameter
+ private List sourceDirs;
+
+ @Override
+ public List getSourceFilePaths() {
+ if (sourceDirs != null && !sourceDirs.isEmpty()) return sourceDirs;
+ return defaultSourceDirs;
+ }
+
+ /**
+ * The source directories containing the sources to be compiled for tests.
+ */
+ @Parameter(defaultValue = "${project.testCompileSourceRoots}", required = true, readonly = true)
+ private List defaultSourceDir;
+
+ @Override
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ if (skip) {
+ getLog().info("Test compilation is skipped");
+ } else {
+ super.execute();
+ }
+ }
+
+ @Override
+ protected void configureSpecificCompilerArguments(@NotNull K2JVMCompilerArguments arguments) throws MojoExecutionException {
+ module = testModule;
+ classpath = testClasspath;
+ arguments.friendPaths = new String[] { output };
+ output = testOutput;
+ super.configureSpecificCompilerArguments(arguments);
+ }
+
+ @Override
+ protected List getRelatedSourceRoots(MavenProject project) {
+ return project.getTestCompileSourceRoots();
+ }
+
+ @NotNull
+ @Override
+ protected String getSourceSetName() {
+ return AnnotationProcessingManager.TEST_SOURCE_SET_NAME;
+ }
+
+ @Override
+ protected void addKaptSourcesDirectory(@NotNull String path) {
+ project.addTestCompileSourceRoot(path);
+ }
+}
\ No newline at end of file