From c06c3db2b9a4cd48732bd14d1bf6b09b5f01cefc Mon Sep 17 00:00:00 2001 From: Sergey Evdokimov Date: Mon, 6 Aug 2012 20:18:41 +0400 Subject: [PATCH] IDEA-60774 target/generated-sources/annotations and target/generated-sources/test-annotations should be specially handled for maven 2 projects --- .../compiler/CompilerConfigurationImpl.java | 21 ++++ .../maven/importing/MavenModuleImporter.java | 110 +++++++++++++++++ .../idea/maven/project/MavenProject.java | 82 +++++++++++++ .../AnnotationProcessorImportingTest.groovy | 115 ++++++++++++++++++ 4 files changed, 328 insertions(+) create mode 100644 plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index 6d67633f26f2..cbf9e666de42 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -384,6 +384,27 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements myModuleProcessorProfiles.addAll(moduleProfiles); } + @Nullable + public ProcessorConfigProfile findModuleProcessorProfile(@NotNull String name) { + for (ProcessorConfigProfile profile : myModuleProcessorProfiles) { + if (name.equals(profile.getName())) { + return profile; + } + } + + return null; + } + + public void removeModuleProcessorProfile(ProcessorConfigProfile profile) { + myModuleProcessorProfiles.remove(profile); + myProcessorsProfilesMap = null; // clear cache + } + + public void addModuleProcessorProfile(@NotNull ProcessorConfigProfile profile) { + myModuleProcessorProfiles.add(profile); + myProcessorsProfilesMap = null; // clear cache + } + @Override @NotNull public ProcessorConfigProfile getAnnotationProcessingConfiguration(Module module) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java index a319b64bac20..bc39cb9fcf48 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java @@ -15,10 +15,14 @@ */ package org.jetbrains.idea.maven.importing; +import com.intellij.compiler.CompilerConfiguration; +import com.intellij.compiler.CompilerConfigurationImpl; +import com.intellij.compiler.ProcessorConfigProfile; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VfsUtil; @@ -33,6 +37,7 @@ import org.jetbrains.idea.maven.model.MavenConstants; import org.jetbrains.idea.maven.project.*; import org.jetbrains.idea.maven.utils.MavenUtil; +import java.io.File; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; @@ -40,6 +45,11 @@ import java.util.List; import java.util.Map; public class MavenModuleImporter { + + public static final String PROFILE_PREFIX = "Annotation profile for "; + + public static final String MAVEN_DEFAULT_ANNOTATION_PROFILE = "Maven default annotation processors profile"; + private final Module myModule; private final MavenProjectsTree myMavenTree; private final MavenProject myMavenProject; @@ -79,6 +89,7 @@ public class MavenModuleImporter { configDependencies(); configLanguageLevel(); configEncoding(); + configAnnotationProcessors(); } public void preConfigFacets() { @@ -218,6 +229,105 @@ public class MavenModuleImporter { } } + private void configAnnotationProcessors() { + if (Boolean.parseBoolean(System.getProperty("idea.maven.keep.annotation.processors"))) return; + + CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance( + myModule.getProject()); + + ProcessorConfigProfile currentProfile = compilerConfiguration.getAnnotationProcessingConfiguration(myModule); + + String moduleProfileName = PROFILE_PREFIX + myModule.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); + + if (shouldEnableAnnotationProcessors()) { + String annotationProcessorDirectory = getRelativeAnnotationProcessorDirectory(); + if (annotationProcessorDirectory == null) { + annotationProcessorDirectory = "target/generated-sources/annotations"; + } + + List processors = myMavenProject.getDeclaredAnnotationProcessors(); + + if (processors == null && "target/generated-sources/annotations".equals(annotationProcessorDirectory)) { + if (moduleProfile != null) { + compilerConfiguration.removeModuleProcessorProfile(moduleProfile); + } + + if (defaultMavenProfile == null) { + defaultMavenProfile = new ProcessorConfigProfile(MAVEN_DEFAULT_ANNOTATION_PROFILE); + defaultMavenProfile.setEnabled(true); + defaultMavenProfile.setObtainProcessorsFromClasspath(true); + defaultMavenProfile.setGeneratedSourcesDirectoryName("target/generated-sources/annotations"); + compilerConfiguration.addModuleProcessorProfile(defaultMavenProfile); + } + + defaultMavenProfile.addModuleName(myModule.getName()); + } + else { + if (defaultMavenProfile != null) { + defaultMavenProfile.removeModuleName(myModule.getName()); + + if (defaultMavenProfile.getModuleNames().isEmpty()) { + compilerConfiguration.removeModuleProcessorProfile(defaultMavenProfile); + } + } + + if (moduleProfile == null) { + moduleProfile = new ProcessorConfigProfile(moduleProfileName); + moduleProfile.setEnabled(true); + moduleProfile.addModuleName(myModule.getName()); + compilerConfiguration.addModuleProcessorProfile(moduleProfile); + } + + moduleProfile.setGeneratedSourcesDirectoryName(annotationProcessorDirectory); + + if (processors == null) { + moduleProfile.setObtainProcessorsFromClasspath(true); + } + else { + moduleProfile.setObtainProcessorsFromClasspath(false); + for (String processor : processors) { + moduleProfile.addProcessor(processor); + } + } + } + } + else { + if (defaultMavenProfile != null) { + defaultMavenProfile.removeModuleName(myModule.getName()); + + if (defaultMavenProfile.getModuleNames().isEmpty()) { + compilerConfiguration.removeModuleProcessorProfile(defaultMavenProfile); + } + } + + if (moduleProfile != null) { + compilerConfiguration.removeModuleProcessorProfile(moduleProfile); + } + } + } + + @Nullable + private String getRelativeAnnotationProcessorDirectory() { + String absoluteAnnotationProcessorDirectory = myMavenProject.getAnnotationProcessorDirectory(false); + String absoluteProjectDirectory = myMavenProject.getDirectory(); + + return FileUtil.getRelativePath(new File(absoluteProjectDirectory), new File(absoluteAnnotationProcessorDirectory)); + } + + private boolean shouldEnableAnnotationProcessors() { + return myMavenProject.getProcMode() != MavenProject.ProcMode.NONE; + } + @NotNull private static DependencyScope selectScope(String mavenScope) { if (MavenConstants.SCOPE_RUNTIME.equals(mavenScope)) return DependencyScope.RUNTIME; 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 d7191d536bb1..2a2aea64cb61 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 @@ -60,6 +60,8 @@ public class MavenProject { .put("1.7", "1.7") .put("7", "1.7").build(); + public enum ProcMode {BOTH, ONLY, NONE} + @Nullable public static MavenProject read(DataInputStream in) throws IOException { String path = in.readUTF(); @@ -360,6 +362,86 @@ public class MavenProject { testSources ? "generatedTestSourcesDirectory" : "generatedSourcesDirectory", def); } + + @NotNull + public ProcMode getProcMode() { + Element compilerConfiguration = getCompilerConfig(); + if (compilerConfiguration == null) { + return ProcMode.BOTH; + } + Element procElement = compilerConfiguration.getChild("proc"); + if (procElement == null) { + return ProcMode.BOTH; + } + else { + String procMode = procElement.getValue(); + return ("only".equalsIgnoreCase(procMode)) ? ProcMode.ONLY : ("none".equalsIgnoreCase(procMode)) ? ProcMode.NONE : ProcMode.BOTH; + } + } + + //@Nullable + //private static Element getAnnotationProcessorsConfiguration(@Nullable Element compilerConfig) { + // return (compilerConfig == null) ? null : compilerConfig.getChild("annotationProcessors"); + //} + + //private String getCompilerArgument() { + // return MavenJDOMUtil.findChildValueByPath(getCompilerConfig(), "compilerArgument"); + //} + // + //private String getCompilerArguments(){ + // StringBuilder compilerArguments = new StringBuilder(); + // Element compilerArgumentsElement = MavenJDOMUtil.findChildByPath(getCompilerConfig(), "compilerArguments"); + // if(compilerArgumentsElement != null){ + // List compilerArgumentsElements = compilerArgumentsElement.getChildren(); + // for(Object compilerArgumentsElementKey: compilerArgumentsElements){ + // String key = ((Element)compilerArgumentsElementKey).getName(); + // String value = ((Element)compilerArgumentsElementKey).getValue(); + // compilerArguments.append(prepareKeyValue(key)).append(" ").append(prepareValueContent(value)); + // } + // } + // return compilerArguments.toString(); + //} + // + //private static String prepareValueContent(String value) { + // return (value == null || value.length() == 0)? "" : value + " "; + //} + // + //private static String prepareKeyValue(final String key) { + // return (key.startsWith( "-A" ))? key.substring(2) : key; + //} + + @Nullable + public List getDeclaredAnnotationProcessors() { + Element compilerConfig = getCompilerConfig(); + if (compilerConfig == null) return null; + + Element processors = compilerConfig.getChild("annotationProcessors"); + if (processors == null) return null; + + List res = new ArrayList(); + + for (Element element : (List)processors.getChildren("annotationProcessor")){ + String processorClassName = element.getTextTrim(); + if (!processorClassName.isEmpty()) { + res.add(processorClassName); + } + } + + return res; + } + + //private String getArgumentsForAnnotationProcessor(){ + // return getCompilerArguments() + formatCompilerArgument(getCompilerArgument()) ; + //} + + //private static String formatCompilerArgument(String compilerArgument){ + // String[] splitArguments = compilerArgument.split("\\s+"); + // List formattedArguments = new ArrayList(); + // for(String splitArgument: splitArguments){ + // formattedArguments.add((splitArgument.startsWith( "-A" ))? splitArgument.substring(2) : splitArgument); + // } + // return StringUtil.join(formattedArguments, " "); + //} @NotNull public String getOutputDirectory() { 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 new file mode 100644 index 000000000000..5b7dfd7e16db --- /dev/null +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/AnnotationProcessorImportingTest.groovy @@ -0,0 +1,115 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * 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 org.jetbrains.idea.maven.compiler + +import com.intellij.compiler.CompilerConfiguration +import com.intellij.compiler.CompilerConfigurationImpl +import org.jetbrains.idea.maven.MavenImportingTestCase +import org.jetbrains.idea.maven.importing.MavenModuleImporter +/** + * @author Sergey Evdokimov + */ +@SuppressWarnings("GroovyPointlessBoolean") +class AnnotationProcessorImportingTest extends MavenImportingTestCase { + + public void testSettingTargetLevel() throws Exception { + createModulePom("module1", """ +test +module1 +1 +""") + + createModulePom("module2", """ +test +module2 +1 + + + + + maven-compiler-plugin + + + com.test.SourceCodeGeneratingAnnotationProcessor2 + + + + + +""") + + createModulePom("module3", """ +test +module3 +1 + + + + + maven-compiler-plugin + + none + + + + +""") + + importProject """ +test +project +1 + + + module1 + module2 + module3 + + +"""; + + def compilerConfiguration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)) + + assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.MAVEN_DEFAULT_ANNOTATION_PROFILE).getModuleNames() == new HashSet(["project", "module1"]) + assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + 'module2').isObtainProcessorsFromClasspath() == false + assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + 'module2').getProcessors() == new HashSet(["com.test.SourceCodeGeneratingAnnotationProcessor2"]) + } + + public void testOverrideGeneratedOutputDir() { + importProject """ +test +project +1 + + + + + maven-compiler-plugin + + out/generated + + + + +"""; + + def compilerConfiguration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)) + + assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.MAVEN_DEFAULT_ANNOTATION_PROFILE) == null + assert compilerConfiguration.findModuleProcessorProfile(MavenModuleImporter.PROFILE_PREFIX + "project").getGeneratedSourcesDirectoryName().endsWith("out/generated") + } + +}