From e48668b498029a18f977a6b1ae2afac5ffe8157a Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Tue, 16 Oct 2012 14:55:17 +0200 Subject: [PATCH] annotation processors: allow configuration of generated sources production/test directory names either relative to module content root or module output directory --- .../options/ProcessorProfilePanel.java | 106 ++++++++++++------ .../openapi/compiler/CompilerPaths.java | 12 +- .../src/org/jetbrains/jps/ProjectPaths.java | 16 ++- .../jps/incremental/IncProjectBuilder.java | 4 +- .../jps/incremental/java/JavaBuilder.java | 3 +- .../AnnotationProcessingConfiguration.java | 5 +- .../java/compiler/ProcessorConfigProfile.java | 5 + .../compiler/ProcessorConfigProfileImpl.java | 26 ++++- .../AnnotationProcessorProfileSerializer.java | 13 ++- 9 files changed, 128 insertions(+), 62 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/options/ProcessorProfilePanel.java b/java/compiler/impl/src/com/intellij/compiler/options/ProcessorProfilePanel.java index 88287542f066..1553b84f16a6 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/ProcessorProfilePanel.java +++ b/java/compiler/impl/src/com/intellij/compiler/options/ProcessorProfilePanel.java @@ -56,6 +56,8 @@ public class ProcessorProfilePanel extends JPanel { private TextFieldWithBrowseButton myProcessorPathField; private JTextField myGeneratedProductionDirField; private JTextField myGeneratedTestsDirField; + private JRadioButton myRbRelativeToOutputRoot; + private JRadioButton myRbRelativeToContentRoot; private ProcessorTableModel myProcessorsModel; private JCheckBox myCbEnableProcessing; private JBTable myProcessorTable; @@ -63,6 +65,12 @@ public class ProcessorProfilePanel extends JPanel { private JPanel myProcessorPanel; private JPanel myOptionsPanel; private OptionsTableModel myOptionsModel; + private JLabel myWarninglabel; + private JLabel myStoreGenSourcesLabel; + private JLabel myProductionLabel; + private JLabel myTestLabel; + private JPanel myProcessorTablePanel; + private JPanel myOptionsTablePanel; public ProcessorProfilePanel(Project project) { @@ -71,11 +79,21 @@ public class ProcessorProfilePanel extends JPanel { myCbEnableProcessing = new JCheckBox("Enable annotation processing"); - myRbClasspath = new JRadioButton("Obtain processors from project classpath"); - myRbProcessorsPath = new JRadioButton("Processor path:"); - ButtonGroup group = new ButtonGroup(); - group.add(myRbClasspath); - group.add(myRbProcessorsPath); + { + myRbClasspath = new JRadioButton("Obtain processors from project classpath"); + myRbProcessorsPath = new JRadioButton("Processor path:"); + ButtonGroup group = new ButtonGroup(); + group.add(myRbClasspath); + group.add(myRbProcessorsPath); + } + + { + myRbRelativeToContentRoot = new JRadioButton("Module content root"); + myRbRelativeToOutputRoot = new JRadioButton("Module output directory"); + final ButtonGroup group = new ButtonGroup(); + group.add(myRbRelativeToContentRoot); + group.add(myRbRelativeToOutputRoot); + } myProcessorPathField = new TextFieldWithBrowseButton(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -94,62 +112,66 @@ public class ProcessorProfilePanel extends JPanel { } }); - final JPanel processorTablePanel = new JPanel(new BorderLayout()); + myProcessorTablePanel = new JPanel(new BorderLayout()); myProcessorsModel = new ProcessorTableModel(); - processorTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processors", false)); + myProcessorTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processors", false)); myProcessorTable = new JBTable(myProcessorsModel); myProcessorTable.getEmptyText().setText("Compiler will run all automatically discovered processors"); myProcessorPanel = createTablePanel(myProcessorTable); - processorTablePanel.add(myProcessorPanel, BorderLayout.CENTER); + myProcessorTablePanel.add(myProcessorPanel, BorderLayout.CENTER); - final JPanel optionsTablePanel = new JPanel(new BorderLayout()); + myOptionsTablePanel = new JPanel(new BorderLayout()); myOptionsModel = new OptionsTableModel(); - optionsTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processor options", false)); + myOptionsTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processor options", false)); myOptionsTable = new JBTable(myOptionsModel); myOptionsTable.getEmptyText().setText("No processor-specific options configured"); myOptionsPanel = createTablePanel(myOptionsTable); - optionsTablePanel.add(myOptionsPanel, BorderLayout.CENTER); + myOptionsTablePanel.add(myOptionsPanel, BorderLayout.CENTER); myGeneratedProductionDirField = new JTextField(); myGeneratedTestsDirField = new JTextField(); - final JLabel warning = new JLabel("WARNING!
" + + myWarninglabel = new JLabel("WARNING!
" + /*"All source files located in the generated sources output directory WILL BE EXCLUDED from annotation processing. " +*/ "If option 'Clear output directory on rebuild' is enabled, " + "the entire contents of directories where generated sources are stored WILL BE CLEARED on rebuild."); - warning.setFont(warning.getFont().deriveFont(Font.BOLD)); + myWarninglabel.setFont(myWarninglabel.getFont().deriveFont(Font.BOLD)); add(myCbEnableProcessing, - new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); add(myRbClasspath, - new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(10, 0, 0, 0), 0, 0)); + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(10, 0, 0, 0), 0, 0)); add(myRbProcessorsPath, - new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0)); + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0)); add(myProcessorPathField, - new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); + new GridBagConstraints(1, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); - final JLabel noteMessage = new JLabel("Source files generated by annotation processors will be stored under the project output directory. " + - "To override this behaviour for this profile you may specify the directory name in the field below. " + - "If specified, the directory will be created under corresponding module's content root."); - add(noteMessage, - new GridBagConstraints(0, 3, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); + myStoreGenSourcesLabel = new JLabel("Store generated sources relative to: "); + add(myStoreGenSourcesLabel, + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(15, 5, 0, 0), 0, 0)); + add(myRbRelativeToOutputRoot, + new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(15, 5, 0, 0), 0, 0)); + add(myRbRelativeToContentRoot, + new GridBagConstraints(2, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(15, 5, 0, 0), 0, 0)); - add(new JLabel("Production sources directory:"), - new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); + myProductionLabel = new JLabel("Production sources directory:"); + add(myProductionLabel, + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); add(myGeneratedProductionDirField, - new GridBagConstraints(1, 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); + new GridBagConstraints(1, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); - add(new JLabel("Test sources directory:"), - new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); + myTestLabel = new JLabel("Test sources directory:"); + add(myTestLabel, + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); add(myGeneratedTestsDirField, - new GridBagConstraints(1, 5, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); + new GridBagConstraints(1, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); - add(processorTablePanel, - new GridBagConstraints(0, 6, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0)); - add(optionsTablePanel, - new GridBagConstraints(0, 7, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0)); - add(warning, - new GridBagConstraints(0, 8, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); + add(myProcessorTablePanel, + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0)); + add(myOptionsTablePanel, + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0)); + add(myWarninglabel, + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0)); myRbClasspath.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { @@ -185,6 +207,12 @@ public class ProcessorProfilePanel extends JPanel { myGeneratedProductionDirField.setText(productionDirName != null? productionDirName.trim() : ""); final String testsDirName = config.getGeneratedSourcesDirectoryName(true); myGeneratedTestsDirField.setText(testsDirName != null? testsDirName.trim() : ""); + if (config.isOutputRelativeToContentRoot()) { + myRbRelativeToContentRoot.setSelected(true); + } + else { + myRbRelativeToOutputRoot.setSelected(true); + } myProcessorsModel.setProcessors(config.getProcessors()); myOptionsModel.setOptions(config.getProcessorOptions()); @@ -201,6 +229,8 @@ public class ProcessorProfilePanel extends JPanel { final String testsDir = myGeneratedTestsDirField.getText().trim(); profile.setGeneratedSourcesDirectoryName(StringUtil.isEmpty(testsDir)? null : testsDir, true); + profile.setOutputRelativeToContentRoot(myRbRelativeToContentRoot.isSelected()); + profile.clearProcessors(); for (String processor : myProcessorsModel.getProcessors()) { profile.addProcessor(processor); @@ -240,6 +270,14 @@ public class ProcessorProfilePanel extends JPanel { updateTable(myOptionsPanel, myOptionsTable, enabled); myGeneratedProductionDirField.setEnabled(enabled); myGeneratedTestsDirField.setEnabled(enabled); + myRbRelativeToOutputRoot.setEnabled(enabled); + myRbRelativeToContentRoot.setEnabled(enabled); + myWarninglabel.setEnabled(enabled); + myStoreGenSourcesLabel.setEnabled(enabled); + myProductionLabel.setEnabled(enabled); + myTestLabel.setEnabled(enabled); + myProcessorTablePanel.setEnabled(enabled); + myOptionsTablePanel.setEnabled(enabled); } private static void updateTable(final JPanel tablePanel, final JBTable table, boolean enabled) { diff --git a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java index dcd4e27a2e2f..86d4e0299348 100644 --- a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java +++ b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java @@ -34,6 +34,7 @@ import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.util.PathUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.java.compiler.AnnotationProcessingConfiguration; import java.io.File; import java.util.Arrays; @@ -214,10 +215,9 @@ public class CompilerPaths { @Nullable public static String getAnnotationProcessorsGenerationPath(Module module) { - final CompilerConfiguration config = CompilerConfiguration.getInstance(module.getProject()); - - final String sourceDirName = config.getAnnotationProcessingConfiguration(module).getGeneratedSourcesDirectoryName(false); - if (!StringUtil.isEmpty(sourceDirName)) { + final AnnotationProcessingConfiguration config = CompilerConfiguration.getInstance(module.getProject()).getAnnotationProcessingConfiguration(module); + final String sourceDirName = config.getGeneratedSourcesDirectoryName(false); + if (config.isOutputRelativeToContentRoot()) { final String[] roots = ModuleRootManager.getInstance(module).getContentRootUrls(); if (roots.length == 0) { return null; @@ -225,7 +225,7 @@ public class CompilerPaths { if (roots.length > 1) { Arrays.sort(roots, URLS_COMPARATOR); } - return VirtualFileManager.extractPath(roots[0]) + "/" + sourceDirName; + return StringUtil.isEmpty(sourceDirName)? VirtualFileManager.extractPath(roots[0]): VirtualFileManager.extractPath(roots[0]) + "/" + sourceDirName; } final CompilerProjectExtension extension = CompilerProjectExtension.getInstance(module.getProject()); @@ -236,7 +236,7 @@ public class CompilerPaths { if (url == null) { return null; } - return VirtualFileManager.extractPath(url) + "/" + DEFAULT_GENERATED_DIR_NAME + "/" + module.getName().toLowerCase(); + return StringUtil.isEmpty(sourceDirName)? VirtualFileManager.extractPath(url) : VirtualFileManager.extractPath(url) + "/" + sourceDirName; } @NonNls diff --git a/jps/jps-builders/src/org/jetbrains/jps/ProjectPaths.java b/jps/jps-builders/src/org/jetbrains/jps/ProjectPaths.java index ba752157c796..08d4e54ea41d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/ProjectPaths.java +++ b/jps/jps-builders/src/org/jetbrains/jps/ProjectPaths.java @@ -9,6 +9,7 @@ import org.jetbrains.jps.model.JpsDummyElement; import org.jetbrains.jps.model.JpsProject; import org.jetbrains.jps.model.JpsSimpleElement; import org.jetbrains.jps.model.java.*; +import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile; import org.jetbrains.jps.model.library.JpsOrderRootType; import org.jetbrains.jps.model.library.sdk.JpsSdk; import org.jetbrains.jps.model.module.JpsDependencyElement; @@ -25,7 +26,6 @@ import java.util.*; * Date: 9/30/11 */ public class ProjectPaths { - private static final String DEFAULT_GENERATED_DIR_NAME = "generated"; @NotNull private final JpsProject myProject; //private final Map>> myCachedClasspath = new HashMap>>(); @@ -148,8 +148,9 @@ public class ProjectPaths { } @Nullable - public File getAnnotationProcessorGeneratedSourcesOutputDir(JpsModule module, final boolean forTests, String sourceDirName) { - if (!StringUtil.isEmpty(sourceDirName)) { + public File getAnnotationProcessorGeneratedSourcesOutputDir(JpsModule module, final boolean forTests, ProcessorConfigProfile profile) { + final String sourceDirName = profile.getGeneratedSourcesDirectoryName(forTests); + if (profile.isOutputRelativeToContentRoot()) { List roots = module.getContentRootsList().getUrls(); if (roots.isEmpty()) { return null; @@ -163,18 +164,15 @@ public class ProjectPaths { } }); } - return new File(JpsPathUtil.urlToFile(roots.get(0)), sourceDirName); + final File parent = JpsPathUtil.urlToFile(roots.get(0)); + return StringUtil.isEmpty(sourceDirName)? parent : new File(parent, sourceDirName); } final File outputDir = getModuleOutputDir(module, forTests); if (outputDir == null) { return null; } - final File parentFile = outputDir.getParentFile(); - if (parentFile == null) { - return null; - } - return new File(parentFile, DEFAULT_GENERATED_DIR_NAME); + return StringUtil.isEmpty(sourceDirName)? outputDir : new File(outputDir, sourceDirName); } private enum ClasspathPart {WHOLE, BEFORE_JDK, AFTER_JDK} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 26cee42e7982..cd5d40998a25 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -368,9 +368,7 @@ public class IncProjectBuilder { for (ModuleBuildTarget target : projectDescriptor.getBuildTargetIndex().getAllTargets(type)) { final ProcessorConfigProfile profile = context.getAnnotationProcessingProfile(target.getModule()); if (profile.isEnabled()) { - final File annotationOut = paths.getAnnotationProcessorGeneratedSourcesOutputDir( - target.getModule(), target.isTests(), profile.getGeneratedSourcesDirectoryName(target.isTests()) - ); + final File annotationOut = paths.getAnnotationProcessorGeneratedSourcesOutputDir(target.getModule(), target.isTests(), profile); if (annotationOut != null) { annotationOutputs.add(annotationOut); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 4b2ab483f882..3d4b4f2ee275 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -751,9 +751,8 @@ public class JavaBuilder extends ModuleLevelBuilder { options.add("-A" + optionEntry.getKey() + "=" + optionEntry.getValue()); } - final boolean forTests = chunk.containsTests(); final File srcOutput = context.getProjectPaths().getAnnotationProcessorGeneratedSourcesOutputDir( - chunk.getModules().iterator().next(), forTests, profile.getGeneratedSourcesDirectoryName(forTests) + chunk.getModules().iterator().next(), chunk.containsTests(), profile ); if (srcOutput != null) { srcOutput.mkdirs(); diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/compiler/AnnotationProcessingConfiguration.java b/jps/model-api/src/org/jetbrains/jps/model/java/compiler/AnnotationProcessingConfiguration.java index 4133955a01df..91009b952740 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/java/compiler/AnnotationProcessingConfiguration.java +++ b/jps/model-api/src/org/jetbrains/jps/model/java/compiler/AnnotationProcessingConfiguration.java @@ -16,7 +16,6 @@ package org.jetbrains.jps.model.java.compiler; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.Set; @@ -31,9 +30,11 @@ public interface AnnotationProcessingConfiguration { @NotNull String getProcessorPath(); - @Nullable + @NotNull String getGeneratedSourcesDirectoryName(boolean forTests); + boolean isOutputRelativeToContentRoot(); + @NotNull Set getProcessors(); diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/compiler/ProcessorConfigProfile.java b/jps/model-api/src/org/jetbrains/jps/model/java/compiler/ProcessorConfigProfile.java index 2baf37316741..aab4f690279f 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/java/compiler/ProcessorConfigProfile.java +++ b/jps/model-api/src/org/jetbrains/jps/model/java/compiler/ProcessorConfigProfile.java @@ -10,6 +10,9 @@ import java.util.Set; * @author nik */ public interface ProcessorConfigProfile extends AnnotationProcessingConfiguration { + String DEFAULT_PRODUCTION_DIR_NAME = "generated"; + String DEFAULT_TESTS_DIR_NAME = "generated_tests"; + void initFrom(ProcessorConfigProfile other); String getName(); @@ -49,4 +52,6 @@ public interface ProcessorConfigProfile extends AnnotationProcessingConfiguratio String getOption(String key); void clearProcessorOptions(); + + void setOutputRelativeToContentRoot(boolean outputRelativeToContentRoot); } diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/compiler/ProcessorConfigProfileImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/compiler/ProcessorConfigProfileImpl.java index b3cca63ad370..3ee4e8b9f045 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/compiler/ProcessorConfigProfileImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/compiler/ProcessorConfigProfileImpl.java @@ -26,15 +26,17 @@ import java.util.*; * Date: 5/25/12 */ public final class ProcessorConfigProfileImpl implements ProcessorConfigProfile { + private String myName = ""; private boolean myEnabled = false; private boolean myObtainProcessorsFromClasspath = true; private String myProcessorPath = ""; private final Set myProcessors = new HashSet(); // empty list means all discovered private final Map myProcessorOptions = new HashMap(); // key=value map of options - @Nullable - private String myGeneratedProductionDirectoryName = null; // null means 'auto' - private String myGeneratedTestsDirectoryName = null; // null means 'auto' + private String myGeneratedProductionDirectoryName = DEFAULT_PRODUCTION_DIR_NAME; + private String myGeneratedTestsDirectoryName = DEFAULT_TESTS_DIR_NAME; + private boolean myOutputRelativeToContentRoot = false; + private final Set myModuleNames = new HashSet(); public ProcessorConfigProfileImpl(String name) { @@ -57,6 +59,7 @@ public final class ProcessorConfigProfileImpl implements ProcessorConfigProfile myProcessorOptions.putAll(other.getProcessorOptions()); myGeneratedProductionDirectoryName = other.getGeneratedSourcesDirectoryName(false); myGeneratedTestsDirectoryName = other.getGeneratedSourcesDirectoryName(true); + myOutputRelativeToContentRoot = other.isOutputRelativeToContentRoot(); myModuleNames.clear(); myModuleNames.addAll(other.getModuleNames()); } @@ -103,13 +106,16 @@ public final class ProcessorConfigProfileImpl implements ProcessorConfigProfile } @Override - @Nullable + @NotNull public String getGeneratedSourcesDirectoryName(boolean forTests) { return forTests? myGeneratedTestsDirectoryName : myGeneratedProductionDirectoryName; } @Override public void setGeneratedSourcesDirectoryName(@Nullable String name, boolean forTests) { + if (name == null || name.trim().isEmpty()) { + name = ""; + } if (forTests) { myGeneratedTestsDirectoryName = name; } @@ -118,6 +124,16 @@ public final class ProcessorConfigProfileImpl implements ProcessorConfigProfile } } + @Override + public boolean isOutputRelativeToContentRoot() { + return myOutputRelativeToContentRoot; + } + + @Override + public void setOutputRelativeToContentRoot(boolean relativeToContent) { + myOutputRelativeToContentRoot = relativeToContent; + } + @Override @NotNull public Set getModuleNames() { @@ -211,6 +227,7 @@ public final class ProcessorConfigProfileImpl implements ProcessorConfigProfile : profile.myGeneratedTestsDirectoryName != null) { return false; } + if (myOutputRelativeToContentRoot != profile.myOutputRelativeToContentRoot)return false; if (!myModuleNames.equals(profile.myModuleNames)) return false; if (!myProcessorOptions.equals(profile.myProcessorOptions)) return false; if (myProcessorPath != null ? !myProcessorPath.equals(profile.myProcessorPath) : profile.myProcessorPath != null) return false; @@ -230,6 +247,7 @@ public final class ProcessorConfigProfileImpl implements ProcessorConfigProfile result = 31 * result + myProcessorOptions.hashCode(); result = 31 * result + (myGeneratedProductionDirectoryName != null ? myGeneratedProductionDirectoryName.hashCode() : 0); result = 31 * result + (myGeneratedTestsDirectoryName != null ? myGeneratedTestsDirectoryName.hashCode() : 0); + result = 31 * result + (myOutputRelativeToContentRoot ? 1 : 0); result = 31 * result + myModuleNames.hashCode(); return result; } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/AnnotationProcessorProfileSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/AnnotationProcessorProfileSerializer.java index 2d2311f93144..4760cfb0d247 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/AnnotationProcessorProfileSerializer.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/AnnotationProcessorProfileSerializer.java @@ -50,6 +50,11 @@ public class AnnotationProcessorProfileSerializer { final Element srcTestOutput = element.getChild("sourceTestOutputDir"); profile.setGeneratedSourcesDirectoryName(srcTestOutput != null ? srcTestOutput.getAttributeValue(NAME) : null, true); + final Element isRelativeToContentRoot = element.getChild("outputRelativeToContentRoot"); + if (isRelativeToContentRoot != null) { + profile.setOutputRelativeToContentRoot(Boolean.parseBoolean(isRelativeToContentRoot.getAttributeValue(VALUE))); + } + profile.clearProcessorOptions(); for (Object optionElement : element.getChildren(OPTION)) { final Element elem = (Element)optionElement; @@ -98,14 +103,18 @@ public class AnnotationProcessorProfileSerializer { element.setAttribute(ENABLED, Boolean.toString(profile.isEnabled())); final String srcDirName = profile.getGeneratedSourcesDirectoryName(false); - if (srcDirName != null) { + if (!StringUtil.equals(ProcessorConfigProfile.DEFAULT_PRODUCTION_DIR_NAME, srcDirName)) { addChild(element, "sourceOutputDir").setAttribute(NAME, srcDirName); } final String testSrcDirName = profile.getGeneratedSourcesDirectoryName(true); - if (testSrcDirName != null) { + if (!StringUtil.equals(ProcessorConfigProfile.DEFAULT_TESTS_DIR_NAME, testSrcDirName)) { addChild(element, "sourceTestOutputDir").setAttribute(NAME, testSrcDirName); } + if (profile.isOutputRelativeToContentRoot()) { + addChild(element, "outputRelativeToContentRoot").setAttribute(VALUE, "true"); + } + final Map options = profile.getProcessorOptions(); if (!options.isEmpty()) { final List keys = new ArrayList(options.keySet());