From fabfaf0f97549bc1f72822dd9ee08aa25a0f3799 Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Wed, 10 Feb 2016 12:10:37 +0300 Subject: [PATCH] IDEA-141849 Maven integration should not create multiple annotation processors profiles with same settings --- .../MavenAnnotationProcessorConfigurer.java | 192 +++++++++++------- .../idea/maven/project/MavenProject.java | 4 +- .../maven/project/MavenProjectsManager.java | 10 +- .../AnnotationProcessorImportingTest.groovy | 5 +- 4 files changed, 132 insertions(+), 79 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenAnnotationProcessorConfigurer.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenAnnotationProcessorConfigurer.java index 0bf545c453ad..69a0522c47b1 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenAnnotationProcessorConfigurer.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/configurers/MavenAnnotationProcessorConfigurer.java @@ -22,9 +22,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.project.MavenProject; +import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile; import org.jetbrains.jps.model.java.impl.compiler.ProcessorConfigProfileImpl; @@ -42,6 +45,10 @@ public class MavenAnnotationProcessorConfigurer extends MavenModuleConfigurer { public static final String DEFAULT_ANNOTATION_PATH_OUTPUT = "target/generated-sources/annotations"; public static final String DEFAULT_TEST_ANNOTATION_OUTPUT = "target/generated-test-sources/test-annotations"; + public static final String MAVEN_BSC_DEFAULT_ANNOTATION_PROFILE = PROFILE_PREFIX + "maven-processor-plugin default configuration"; + public static final String DEFAULT_BSC_ANNOTATION_PATH_OUTPUT = "target/generated-sources/apt"; + public static final String DEFAULT_BSC_TEST_ANNOTATION_OUTPUT = "target/generated-sources/apt-test"; + @Override public void configure(@NotNull MavenProject mavenProject, @NotNull Project project, @Nullable Module module) { if (module == null) return; @@ -50,29 +57,21 @@ public class MavenAnnotationProcessorConfigurer extends MavenModuleConfigurer { if (sdk != null) { String versionString = sdk.getVersionString(); if (versionString != null) { - if (versionString.contains("1.5") || versionString.contains("1.4") || versionString.contains("1.3") || versionString.contains("1.2")) { + if (versionString.contains("1.5") || + versionString.contains("1.4") || + versionString.contains("1.3") || + versionString.contains("1.2")) { return; } } } - CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(project); - - ProcessorConfigProfile currentProfile = compilerConfiguration.getAnnotationProcessingConfiguration(module); - - String moduleProfileName = PROFILE_PREFIX + module.getName(); - - if (currentProfile != compilerConfiguration.getDefaultProcessorProfile() - && !MAVEN_DEFAULT_ANNOTATION_PROFILE.equals(currentProfile.getName()) - && !moduleProfileName.equals(currentProfile.getName())) { - return; - } - - ProcessorConfigProfile moduleProfile = compilerConfiguration.findModuleProcessorProfile(moduleProfileName); - - ProcessorConfigProfile defaultMavenProfile = compilerConfiguration.findModuleProcessorProfile(MAVEN_DEFAULT_ANNOTATION_PROFILE); + final CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(project); + final MavenProject rootProject = + ObjectUtils.notNull(MavenProjectsManager.getInstance(project).findRootProject(mavenProject), mavenProject); if (shouldEnableAnnotationProcessors(mavenProject)) { + final String moduleProfileName; String annotationProcessorDirectory = getRelativeAnnotationProcessorDirectory(mavenProject, false); if (annotationProcessorDirectory == null) { annotationProcessorDirectory = DEFAULT_ANNOTATION_PATH_OUTPUT; @@ -83,80 +82,128 @@ public class MavenAnnotationProcessorConfigurer extends MavenModuleConfigurer { testAnnotationProcessorDirectory = DEFAULT_TEST_ANNOTATION_OUTPUT; } - Map options = mavenProject.getAnnotationProcessorOptions(); - - List processors = mavenProject.getDeclaredAnnotationProcessors(); - - if (processors == null - && options.isEmpty() - && DEFAULT_ANNOTATION_PATH_OUTPUT.equals(annotationProcessorDirectory.replace('\\', '/')) - && DEFAULT_TEST_ANNOTATION_OUTPUT.equals(testAnnotationProcessorDirectory.replace('\\', '/'))) { - if (moduleProfile != null) { - compilerConfiguration.removeModuleProcessorProfile(moduleProfile); - } - - if (defaultMavenProfile == null) { - defaultMavenProfile = new ProcessorConfigProfileImpl(MAVEN_DEFAULT_ANNOTATION_PROFILE); - defaultMavenProfile.setEnabled(true); - defaultMavenProfile.setOutputRelativeToContentRoot(true); - defaultMavenProfile.setObtainProcessorsFromClasspath(true); - defaultMavenProfile.setGeneratedSourcesDirectoryName(DEFAULT_ANNOTATION_PATH_OUTPUT, false); - defaultMavenProfile.setGeneratedSourcesDirectoryName(DEFAULT_TEST_ANNOTATION_OUTPUT, true); - compilerConfiguration.addModuleProcessorProfile(defaultMavenProfile); - } - - defaultMavenProfile.addModuleName(module.getName()); + final boolean isDefault; + if (isMavenDefaultAnnotationProcessorConfiguration(annotationProcessorDirectory, testAnnotationProcessorDirectory, mavenProject)) { + moduleProfileName = MAVEN_DEFAULT_ANNOTATION_PROFILE; + isDefault = true; + } + else if (isMavenProcessorPluginDefaultConfiguration(annotationProcessorDirectory, testAnnotationProcessorDirectory, mavenProject)) { + moduleProfileName = MAVEN_BSC_DEFAULT_ANNOTATION_PROFILE; + isDefault = true; } else { - if (defaultMavenProfile != null) { - defaultMavenProfile.removeModuleName(module.getName()); + moduleProfileName = PROFILE_PREFIX + module.getName(); + isDefault = false; + } + ProcessorConfigProfile moduleProfile = compilerConfiguration.findModuleProcessorProfile(moduleProfileName); - if (defaultMavenProfile.getModuleNames().isEmpty()) { - compilerConfiguration.removeModuleProcessorProfile(defaultMavenProfile); - } - } + if (moduleProfile == null) { + moduleProfile = new ProcessorConfigProfileImpl(moduleProfileName); + compilerConfiguration.addModuleProcessorProfile(moduleProfile); + } - if (moduleProfile == null) { - moduleProfile = new ProcessorConfigProfileImpl(moduleProfileName); - moduleProfile.setOutputRelativeToContentRoot(true); - moduleProfile.setEnabled(true); - moduleProfile.setObtainProcessorsFromClasspath(true); - moduleProfile.addModuleName(module.getName()); - compilerConfiguration.addModuleProcessorProfile(moduleProfile); - } + moduleProfile.setOutputRelativeToContentRoot(true); + moduleProfile.setEnabled(true); + moduleProfile.setObtainProcessorsFromClasspath(true); + moduleProfile.setGeneratedSourcesDirectoryName(annotationProcessorDirectory, false); + moduleProfile.setGeneratedSourcesDirectoryName(testAnnotationProcessorDirectory, true); - moduleProfile.setGeneratedSourcesDirectoryName(annotationProcessorDirectory, false); - moduleProfile.setGeneratedSourcesDirectoryName(testAnnotationProcessorDirectory, true); + moduleProfile.clearProcessorOptions(); + for (Map.Entry entry : mavenProject.getAnnotationProcessorOptions().entrySet()) { + moduleProfile.setOption(entry.getKey(), entry.getValue()); + } - moduleProfile.clearProcessorOptions(); - for (Map.Entry entry : options.entrySet()) { - moduleProfile.setOption(entry.getKey(), entry.getValue()); - } - - moduleProfile.clearProcessors(); - - if (processors != null) { - for (String processor : processors) { - moduleProfile.addProcessor(processor); - } + moduleProfile.clearProcessors(); + final List processors = mavenProject.getDeclaredAnnotationProcessors(); + if (processors != null) { + for (String processor : processors) { + moduleProfile.addProcessor(processor); } } + + moduleProfile.addModuleName(module.getName()); + cleanAndMergeModuleProfiles(rootProject, compilerConfiguration, moduleProfile, isDefault, module); } else { - if (defaultMavenProfile != null) { - defaultMavenProfile.removeModuleName(module.getName()); + cleanAndMergeModuleProfiles(rootProject, compilerConfiguration, null, false, module); + } + } - if (defaultMavenProfile.getModuleNames().isEmpty()) { - compilerConfiguration.removeModuleProcessorProfile(defaultMavenProfile); + private static void cleanAndMergeModuleProfiles(@NotNull MavenProject rootProject, + @NotNull CompilerConfigurationImpl compilerConfiguration, + @Nullable ProcessorConfigProfile moduleProfile, + boolean isDefault, + @NotNull Module module) { + List profiles = ContainerUtil.newArrayList(compilerConfiguration.getModuleProcessorProfiles()); + for (ProcessorConfigProfile p : profiles) { + if (p != moduleProfile) { + p.removeModuleName(module.getName()); + if (p.getModuleNames().isEmpty()) { + compilerConfiguration.removeModuleProcessorProfile(p); } } - if (moduleProfile != null) { - compilerConfiguration.removeModuleProcessorProfile(moduleProfile); + if (!isDefault && moduleProfile != null && isSimilarProfiles(p, moduleProfile)) { + final String mavenProjectRootProfileName = PROFILE_PREFIX + rootProject.getDisplayName(); + ProcessorConfigProfile mergedProfile = compilerConfiguration.findModuleProcessorProfile(mavenProjectRootProfileName); + if (mergedProfile == null) { + mergedProfile = new ProcessorConfigProfileImpl(moduleProfile); + mergedProfile.setName(mavenProjectRootProfileName); + compilerConfiguration.addModuleProcessorProfile(mergedProfile); + mergedProfile.addModuleNames(p.getModuleNames()); + p.clearModuleNames(); + compilerConfiguration.removeModuleProcessorProfile(p); + moduleProfile.clearModuleNames(); + compilerConfiguration.removeModuleProcessorProfile(moduleProfile); + } + else if (p == mergedProfile || isSimilarProfiles(mergedProfile, moduleProfile)) { + mergedProfile.addModuleNames(moduleProfile.getModuleNames()); + moduleProfile.clearModuleNames(); + compilerConfiguration.removeModuleProcessorProfile(moduleProfile); + if (p != mergedProfile) { + mergedProfile.addModuleNames(p.getModuleNames()); + p.clearModuleNames(); + compilerConfiguration.removeModuleProcessorProfile(p); + } + } } } } + private static boolean isSimilarProfiles(@Nullable ProcessorConfigProfile profile1, @Nullable ProcessorConfigProfile profile2) { + if (profile1 == null || profile2 == null) return false; + + ProcessorConfigProfileImpl p1 = new ProcessorConfigProfileImpl(profile1); + p1.setName("tmp"); + p1.clearModuleNames(); + ProcessorConfigProfileImpl p2 = new ProcessorConfigProfileImpl(profile2); + p2.setName("tmp"); + p2.clearModuleNames(); + return p1.equals(p2); + } + + private static boolean isMavenDefaultAnnotationProcessorConfiguration(@NotNull String annotationProcessorDirectory, + @NotNull String testAnnotationProcessorDirectory, + @NotNull MavenProject mavenProject) { + Map options = mavenProject.getAnnotationProcessorOptions(); + List processors = mavenProject.getDeclaredAnnotationProcessors(); + return ContainerUtil.isEmpty(processors) + && options.isEmpty() + && DEFAULT_ANNOTATION_PATH_OUTPUT.equals(annotationProcessorDirectory.replace('\\', '/')) + && DEFAULT_TEST_ANNOTATION_OUTPUT.equals(testAnnotationProcessorDirectory.replace('\\', '/')); + } + + private static boolean isMavenProcessorPluginDefaultConfiguration(@NotNull String annotationProcessorDirectory, + @NotNull String testAnnotationProcessorDirectory, + @NotNull MavenProject mavenProject) { + Map options = mavenProject.getAnnotationProcessorOptions(); + List processors = mavenProject.getDeclaredAnnotationProcessors(); + return ContainerUtil.isEmpty(processors) + && options.isEmpty() + && DEFAULT_BSC_ANNOTATION_PATH_OUTPUT.equals(annotationProcessorDirectory.replace('\\', '/')) + && DEFAULT_BSC_TEST_ANNOTATION_OUTPUT.equals(testAnnotationProcessorDirectory.replace('\\', '/')); + } + @Nullable private static String getRelativeAnnotationProcessorDirectory(MavenProject mavenProject, boolean isTest) { String annotationProcessorDirectory = mavenProject.getAnnotationProcessorDirectory(isTest); @@ -175,5 +222,4 @@ public class MavenAnnotationProcessorConfigurer extends MavenModuleConfigurer { return mavenProject.getProcMode() != MavenProject.ProcMode.NONE || mavenProject.findPlugin("org.bsc.maven", "maven-processor-plugin") != null; } - } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 69f34416900a..6effded0e614 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -358,14 +358,14 @@ public class MavenProject { MavenPlugin bscMavenPlugin = findPlugin("org.bsc.maven", "maven-processor-plugin"); Element cfg = getPluginGoalConfiguration(bscMavenPlugin, testSources ? "process-test" : "process"); if (bscMavenPlugin != null && cfg == null) { - return getBuildDirectory() + "/generated-sources/apt"; + return getBuildDirectory() + (testSources ? "/generated-sources/apt-test" : "/generated-sources/apt"); } if (cfg != null) { String out = MavenJDOMUtil.findChildValueByPath(cfg, "outputDirectory"); if (out == null) { out = MavenJDOMUtil.findChildValueByPath(cfg, "defaultOutputDirectory"); if (out == null) { - return getBuildDirectory() + "/generated-sources/apt"; + return getBuildDirectory() + (testSources ? "/generated-sources/apt-test" : "/generated-sources/apt"); } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java index 4d85f9b0d8bd..db929294871f 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java @@ -730,9 +730,15 @@ public class MavenProjectsManager extends MavenSimpleProjectComponent } @Nullable - public MavenProject findAggregator(@NotNull MavenProject module) { + public MavenProject findAggregator(@NotNull MavenProject mavenProject) { if (!isInitialized()) return null; - return myProjectsTree.findAggregator(module); + return myProjectsTree.findAggregator(mavenProject); + } + + @Nullable + public MavenProject findRootProject(@NotNull MavenProject mavenProject) { + if (!isInitialized()) return null; + return myProjectsTree.findRootProject(mavenProject); } @NotNull diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy index 9014ceac574c..17686098f12c 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy @@ -26,7 +26,7 @@ import org.jetbrains.idea.maven.importing.configurers.MavenAnnotationProcessorCo @SuppressWarnings("GroovyPointlessBoolean") class AnnotationProcessorImportingTest extends MavenImportingTestCase { - public void testSettingTargetLevel() throws Exception { + public void testImportAnnotationProcessorProfiles() throws Exception { createModulePom("module1", """ test module1 @@ -126,7 +126,8 @@ class AnnotationProcessorImportingTest extends MavenImportingTestCase { def compilerConfiguration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)) - assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.MAVEN_DEFAULT_ANNOTATION_PROFILE).getModuleNames() == new HashSet(["module1"]) + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.MAVEN_DEFAULT_ANNOTATION_PROFILE).getModuleNames() == new HashSet(["module1", "module4"]) + assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.MAVEN_BSC_DEFAULT_ANNOTATION_PROFILE) == null assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + 'module2').getProcessors() == new HashSet(["com.test.SourceCodeGeneratingAnnotationProcessor2"]) assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + 'module3') == null assert compilerConfiguration.findModuleProcessorProfile(MavenAnnotationProcessorConfigurer.PROFILE_PREFIX + 'module3_1') == null