diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index 12b5d816bfcf..df79556fd5b3 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -9,6 +9,7 @@ package com.intellij.compiler; import com.intellij.CommonBundle; +import com.intellij.ProjectTopics; import com.intellij.compiler.impl.javaCompiler.BackendCompiler; import com.intellij.compiler.impl.javaCompiler.api.CompilerAPICompiler; import com.intellij.compiler.impl.javaCompiler.eclipse.EclipseCompiler; @@ -22,6 +23,9 @@ import com.intellij.openapi.compiler.CompilerBundle; import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.ModuleListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.InputValidator; import com.intellij.openapi.ui.Messages; @@ -63,6 +67,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements private final List> myNegatedCompiledPatterns = new ArrayList>(); private boolean myWildcardPatternsInitialized = false; private final Project myProject; + private final ModuleManager myModuleManager; private final ExcludedEntriesConfiguration myExcludedEntriesConfiguration; public int DEPLOY_AFTER_MAKE = Options.SHOW_DIALOG; @@ -75,10 +80,37 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements loadDefaultWildcardPatterns(); } - public CompilerConfigurationImpl(Project project) { + private boolean myEnableAnnotationProcessors = false; + private final Map myProcessorsMap = new HashMap(); // map: AnnotationProcessorName -> options + private boolean myObtainProcessorsFromClasspath = true; + private String myProcessorPath = ""; + private final Set myExcludedModules = new HashSet(); + private final Set myExcludedModuleNames = new HashSet(); + + + public CompilerConfigurationImpl(Project project, ModuleManager moduleManager) { myProject = project; + myModuleManager = moduleManager; myExcludedEntriesConfiguration = new ExcludedEntriesConfiguration(); Disposer.register(project, myExcludedEntriesConfiguration); + project.getMessageBus().connect(project).subscribe(ProjectTopics.MODULES, new ModuleListener() { + public void modulesRenamed(Project project, List modules) { + } + + public void moduleRemoved(Project project, Module module) { + } + + public void beforeModuleRemoved(Project project, Module module) { + myExcludedModules.remove(module); + myExcludedModuleNames.remove(module.getName()); + } + + public void moduleAdded(Project project, Module module) { + if (myExcludedModuleNames.remove(module.getName())) { + myExcludedModules.add(module); + } + } + }); } public Element getState() { @@ -262,6 +294,49 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements return isResourceFile(virtualFile.getName(), virtualFile.getParent()); } + public boolean isAnnotationProcessorsEnabled() { + return myEnableAnnotationProcessors; + } + + public void setAnnotationProcessorsEnabled(boolean enableAnnotationProcessors) { + myEnableAnnotationProcessors = enableAnnotationProcessors; + } + + public boolean isObtainProcessorsFromClasspath() { + return myObtainProcessorsFromClasspath; + } + + public void setObtainProcessorsFromClasspath(boolean obtainProcessorsFromClasspath) { + myObtainProcessorsFromClasspath = obtainProcessorsFromClasspath; + } + + public String getProcessorPath() { + return myProcessorPath; + } + + public void setProcessorsPath(String processorsPath) { + myProcessorPath = processorsPath; + } + + public Map getAnnotationProcessorsMap() { + return Collections.unmodifiableMap(myProcessorsMap); + } + + public void setAnnotationProcessorsMap(Map map) { + myProcessorsMap.clear(); + myProcessorsMap.putAll(map); + } + + public Set getExcludedModules() { + return Collections.unmodifiableSet(myExcludedModules); + } + + public void setExcludedModules(Collection modules) { + myExcludedModules.clear(); + myExcludedModuleNames.clear(); + myExcludedModules.addAll(modules); + } + private void addWildcardResourcePattern(@NonNls final String wildcardPattern) throws MalformedPatternException { final Pair pattern = convertToRegexp(wildcardPattern); if (pattern != null) { @@ -400,6 +475,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements // property names @NonNls private static final String EXCLUDE_FROM_COMPILE = "excludeFromCompile"; @NonNls private static final String RESOURCE_EXTENSIONS = "resourceExtensions"; + @NonNls private static final String ANNOTATION_PROCESSING = "annotationProcessing"; @NonNls private static final String WILDCARD_RESOURCE_PATTERNS = "wildcardResourcePatterns"; @NonNls private static final String ENTRY = "entry"; @NonNls private static final String NAME = "name"; @@ -442,6 +518,52 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements throw new InvalidDataException(e); } + final Element annotationProcessingSettings = parentNode.getChild(ANNOTATION_PROCESSING); + if (annotationProcessingSettings != null) { + myEnableAnnotationProcessors = Boolean.valueOf(annotationProcessingSettings.getAttributeValue("enabled", "false")); + myObtainProcessorsFromClasspath = Boolean.valueOf(annotationProcessingSettings.getAttributeValue("useClasspath", "true")); + + final StringBuilder pathBuilder = new StringBuilder(); + for (Element pathElement : ((Collection)annotationProcessingSettings.getChildren("processorPath"))) { + final String path = pathElement.getAttributeValue("value"); + if (path != null) { + if (pathBuilder.length() > 0) { + pathBuilder.append(File.pathSeparator); + } + pathBuilder.append(path); + } + } + myProcessorPath = pathBuilder.toString(); + + myProcessorPath = annotationProcessingSettings.getAttributeValue("processorPath", ""); + myProcessorsMap.clear(); + for (Element processorChild : ((Collection)annotationProcessingSettings.getChildren("processor"))) { + final String name = processorChild.getAttributeValue("name"); + final String options = processorChild.getAttributeValue("options", ""); + myProcessorsMap.put(name, options); + } + myExcludedModules.clear(); + myExcludedModuleNames.clear(); + final Collection excluded = (Collection)annotationProcessingSettings.getChildren("excludeModule"); + if (excluded.size() > 0) { + final Map moduleMap = new com.intellij.util.containers.HashMap(); + for (Module module : myModuleManager.getModules()) { + moduleMap.put(module.getName(), module); + } + for (Element moduleElement : excluded) { + final String name = moduleElement.getAttributeValue("name"); + if (name != null) { + final Module module = moduleMap.get(name); + if (module != null) { + myExcludedModules.add(module); + } + else { + myExcludedModuleNames.add(name); + } + } + } + } + } } public void writeExternal(Element parentNode) throws WriteExternalException { @@ -453,9 +575,8 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements parentNode.addContent(newChild); } - String[] patterns = getRegexpPatterns(); final Element newChild = new Element(RESOURCE_EXTENSIONS); - for (final String pattern : patterns) { + for (final String pattern : getRegexpPatterns()) { final Element entry = new Element(ENTRY); entry.setAttribute(NAME, pattern); newChild.addContent(entry); @@ -471,6 +592,37 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements } parentNode.addContent(wildcardPatterns); } + + final Element annotationProcessingSettings = new Element(ANNOTATION_PROCESSING); + parentNode.addContent(annotationProcessingSettings); + annotationProcessingSettings.setAttribute("enabled", String.valueOf(myEnableAnnotationProcessors)); + annotationProcessingSettings.setAttribute("useClasspath", String.valueOf(myObtainProcessorsFromClasspath)); + if (myProcessorPath.length() > 0) { + final StringTokenizer tokenizer = new StringTokenizer(myProcessorPath, File.pathSeparator, false); + while (tokenizer.hasMoreTokens()) { + final String path = tokenizer.nextToken(); + final Element pathElement = new Element("processorPath"); + annotationProcessingSettings.addContent(pathElement); + pathElement.setAttribute("value", path); + } + } + for (Map.Entry entry : myProcessorsMap.entrySet()) { + final Element processor = new Element("processor"); + annotationProcessingSettings.addContent(processor); + processor.setAttribute("name", entry.getKey()); + processor.setAttribute("options", entry.getValue()); + } + final List modules = new ArrayList(getExcludedModules()); + Collections.sort(modules, new Comparator() { + public int compare(Module o1, Module o2) { + return o1.getName().compareToIgnoreCase(o2.getName()); + } + }); + for (Module module : modules) { + final Element moduleElement = new Element("excludeModule"); + annotationProcessingSettings.addContent(moduleElement); + moduleElement.setAttribute("name", module.getName()); + } } @NotNull @NonNls diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java index dd36a7c59037..40847d1c6f8c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java @@ -16,6 +16,7 @@ package com.intellij.compiler; import com.intellij.compiler.impl.*; +import com.intellij.compiler.impl.javaCompiler.AnnotationProcessingCompiler; import com.intellij.compiler.impl.javaCompiler.JavaCompiler; import com.intellij.compiler.impl.packagingCompiler.IncrementalPackagingCompiler; import com.intellij.compiler.impl.resourceCompiler.ResourceCompiler; @@ -65,8 +66,7 @@ public class CompilerManagerImpl extends CompilerManager { // predefined compilers addTranslatingCompiler(new JavaCompiler(myProject), new HashSet(Arrays.asList(StdFileTypes.JAVA)), new HashSet(Arrays.asList(StdFileTypes.CLASS))); - // todo: enable compiler later - //addCompiler(new AnnotationProcessingCompiler(project)); + addCompiler(new AnnotationProcessingCompiler(project)); addCompiler(new ResourceCompiler(project, compilerConfiguration)); addCompiler(new RmicCompiler()); addCompiler(new IncrementalPackagingCompiler()); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/AnnotationProcessingCompiler.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/AnnotationProcessingCompiler.java index c34fe7f148ef..8754e36642cb 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/AnnotationProcessingCompiler.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/AnnotationProcessingCompiler.java @@ -38,10 +38,7 @@ import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.*; public class AnnotationProcessingCompiler implements SourceProcessingCompiler{ private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.javaCompiler.JavaCompiler"); @@ -58,16 +55,23 @@ public class AnnotationProcessingCompiler implements SourceProcessingCompiler{ @NotNull public ProcessingItem[] getProcessingItems(CompileContext context) { - final VirtualFile[] files = context.getCompileScope().getFiles(StdFileTypes.JAVA, true); - ProcessingItem[] items = new ProcessingItem[files.length]; - for (int idx = 0; idx < files.length; idx++) { - items[idx] = new MyProcessingItem(files[idx]); + final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject); + if (!config.isAnnotationProcessorsEnabled()) { + return ProcessingItem.EMPTY_ARRAY; } - return items; + final VirtualFile[] files = context.getCompileScope().getFiles(StdFileTypes.JAVA, true); + final List items = new ArrayList(files.length); + final Set excludedModules = config.getExcludedModules(); + for (final VirtualFile file : files) { + if (excludedModules.size() == 0 || !excludedModules.contains(context.getModuleByFile(file))) { + items.add(new MyProcessingItem(file)); + } + } + return items.toArray(new ProcessingItem[items.size()]); } public ProcessingItem[] process(CompileContext context, ProcessingItem[] items) { - VirtualFile[] files = new VirtualFile[items.length]; + final VirtualFile[] files = new VirtualFile[items.length]; for (int idx = 0; idx < items.length; idx++) { files[idx] = items[idx].getFile(); } diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java index 8daa6f36dc3f..5bc689b7520a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java @@ -15,6 +15,7 @@ */ package com.intellij.compiler.impl.javaCompiler.javac; +import com.intellij.compiler.CompilerConfiguration; import com.intellij.compiler.CompilerConfigurationImpl; import com.intellij.compiler.CompilerIOUtil; import com.intellij.compiler.OutputParser; @@ -285,10 +286,29 @@ public class JavacCompiler extends ExternalCompiler { isAnnotationProcessing = false; // makes no sense for these versions } if (isAnnotationProcessing) { + final CompilerConfiguration config = CompilerConfiguration.getInstance(javacSettings.getProject()); additionalOptions.add("-Xprefer:source"); additionalOptions.add("-implicit:none"); additionalOptions.add("-proc:only"); - // todo: temporary! + if (!config.isObtainProcessorsFromClasspath()) { + final String processorPath = config.getProcessorPath(); + if (processorPath.length() > 0) { + additionalOptions.add("-processorpath"); + additionalOptions.add(FileUtil.toSystemDependentName(processorPath)); + } + } + for (Map.Entry entry : config.getAnnotationProcessorsMap().entrySet()) { + additionalOptions.add("-processor"); + additionalOptions.add(entry.getKey()); + final String options = entry.getValue(); + if (options.length() > 0) { + StringTokenizer optionsTokenizer = new StringTokenizer(options, " ", false); + while (optionsTokenizer.hasMoreTokens()) { + final String token = optionsTokenizer.nextToken(); + additionalOptions.add("-A"+token); + } + } + } //additionalOptions.add("-processor"); //additionalOptions.add("CheckNamesProcessor"); //additionalOptions.add("org.apache.openjpa.persistence.meta.AnnotationProcessor6"); @@ -358,12 +378,15 @@ public class JavacCompiler extends ExternalCompiler { } if (isAnnotationProcessingMode) { - // todo: come up with some solution about the path for generated sources commandLine.add("-s"); commandLine.add(outputPath.replace('/', File.separatorChar)); + commandLine.add("-d"); + commandLine.add(outputPath.replace('/', File.separatorChar)); + } + else { + commandLine.add("-d"); + commandLine.add(outputPath.replace('/', File.separatorChar)); } - commandLine.add("-d"); - commandLine.add(outputPath.replace('/', File.separatorChar)); } private static void addClassPathValue(final Sdk jdk, final boolean isVersion1_0, final List commandLine, final String cpString, @NonNls final String tempFileName, diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacSettings.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacSettings.java index 21ee257333d7..16df8703ccc9 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacSettings.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacSettings.java @@ -53,6 +53,10 @@ public class JavacSettings implements PersistentStateComponent { myProject = project; } + public Project getProject() { + return myProject; + } + public Element getState() { try { final Element e = new Element("state"); diff --git a/java/compiler/impl/src/com/intellij/compiler/options/CompilerConfigurable.java b/java/compiler/impl/src/com/intellij/compiler/options/CompilerConfigurable.java index 16ea98ae97e0..2a87d9f7356c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/CompilerConfigurable.java +++ b/java/compiler/impl/src/com/intellij/compiler/options/CompilerConfigurable.java @@ -136,6 +136,7 @@ public class CompilerConfigurable implements SearchableConfigurable.Parent { } additional.add(0, new RmicConfigurable(RmicSettings.getInstance(myProject))); + additional.add(0, new AnnotationProcessorsConfigurable(myProject)); additional.add(0, new JavaCompilersTab(myProject, compilerConfiguration.getRegisteredJavaCompilers(), compilerConfiguration.getDefaultCompiler())); kids.addAll(additional); diff --git a/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java b/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java index 10e47a528d82..8862b7fc7c64 100644 --- a/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java +++ b/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java @@ -16,9 +16,14 @@ package com.intellij.compiler; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + public abstract class CompilerConfiguration { // need this flag for profiling purposes. In production code is always set to 'true' public static final boolean MAKE_ENABLED = true; @@ -35,4 +40,23 @@ public abstract class CompilerConfiguration { public abstract void addResourceFilePattern(String namePattern) throws MalformedPatternException; + public abstract boolean isAnnotationProcessorsEnabled(); + + public abstract void setAnnotationProcessorsEnabled(boolean enableAnnotationProcessors); + + public abstract boolean isObtainProcessorsFromClasspath(); + + public abstract void setObtainProcessorsFromClasspath(boolean obtainProcessorsFromClasspath); + + public abstract String getProcessorPath(); + + public abstract void setProcessorsPath(String processorsPath); + + public abstract Map getAnnotationProcessorsMap(); + + public abstract void setAnnotationProcessorsMap(Map map); + + public abstract Set getExcludedModules(); + + public abstract void setExcludedModules(Collection modules); } \ No newline at end of file diff --git a/java/compiler/openapi/src/com/intellij/openapi/compiler/SourceProcessingCompiler.java b/java/compiler/openapi/src/com/intellij/openapi/compiler/SourceProcessingCompiler.java index efff833a4205..8392fdc865ee 100644 --- a/java/compiler/openapi/src/com/intellij/openapi/compiler/SourceProcessingCompiler.java +++ b/java/compiler/openapi/src/com/intellij/openapi/compiler/SourceProcessingCompiler.java @@ -15,11 +15,5 @@ */ package com.intellij.openapi.compiler; -/** - * A tag interface indicating that the compiler will instrument java sources. - * This affects the order of compiler calls: - * The sequence in which compilers are called: - * SourceGeneratingCompiler -> SourceInstrumentingCompiler -> TranslatingCompiler -> ClassInstrumentingCompiler -> ClassPostProcessingCompiler -> Validator - */ public interface SourceProcessingCompiler extends FileProcessingCompiler, IntermediateOutputCompiler { } \ No newline at end of file