You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by "Michael Zav'yalov (JIRA)" <ji...@apache.org> on 2016/09/21 15:06:21 UTC

[jira] [Commented] (MCOMPILER-278) Incremental build does not track inter-module dependencies.

    [ https://issues.apache.org/jira/browse/MCOMPILER-278?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15510220#comment-15510220 ] 

Michael Zav'yalov commented on MCOMPILER-278:
---------------------------------------------

I do not see full good fix, but can we have a partial fix where jar checksum can be used to detect modifications?

Here is a patch for this:
Index: src/main/java/org/apache/maven/plugin/compiler/AbstractCompilerMojo.java
===================================================================
--- src/main/java/org/apache/maven/plugin/compiler/AbstractCompilerMojo.java	(revision 1761542)
+++ src/main/java/org/apache/maven/plugin/compiler/AbstractCompilerMojo.java	(working copy)
@@ -18,7 +18,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecution;
@@ -49,20 +48,28 @@
 import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
- * TODO: At least one step could be optimized, currently the plugin will do two
- * scans of all the source code if the compiler has to have the entire set of
- * sources. This is currently the case for at least the C# compiler and most
- * likely all the other .NET compilers too.
+ * TODO: At least one step could be optimized, currently the plugin will do two scans of all the source code if the compiler has to have the
+ * entire set of sources. This is currently the case for at least the C# compiler and most likely all the other .NET compilers too.
  *
  * @author others
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
@@ -70,1139 +77,1251 @@
  * @since 2.0
  */
 public abstract class AbstractCompilerMojo
-    extends AbstractMojo
+        extends AbstractMojo
 {
-    // ----------------------------------------------------------------------
-    // Configurables
-    // ----------------------------------------------------------------------
 
-    /**
-     * Indicates whether the build will continue even if there are compilation errors.
-     *
-     * @since 2.0.2
-     */
-    @Parameter(property = "maven.compiler.failOnError", defaultValue = "true")
-    private boolean failOnError = true;
+   private static final String DEPENDENCY_INFO_FILENAME = "dependencies.info";
 
-    /**
-     * Set to <code>true</code> to include debugging information in the compiled class files.
-     */
-    @Parameter(property = "maven.compiler.debug", defaultValue = "true")
-    private boolean debug = true;
+   // ----------------------------------------------------------------------
+   // Configurables
+   // ----------------------------------------------------------------------
+   /**
+    * Indicates whether the build will continue even if there are compilation errors.
+    *
+    * @since 2.0.2
+    */
+   @Parameter(property = "maven.compiler.failOnError", defaultValue = "true")
+   private boolean failOnError = true;
 
-    /**
-     * Set to <code>true</code> to show messages about what the compiler is doing.
-     */
-    @Parameter(property = "maven.compiler.verbose", defaultValue = "false")
-    private boolean verbose;
+   /**
+    * Set to <code>true</code> to include debugging information in the compiled class files.
+    */
+   @Parameter(property = "maven.compiler.debug", defaultValue = "true")
+   private boolean debug = true;
 
-    /**
-     * Sets whether to show source locations where deprecated APIs are used.
-     */
-    @Parameter(property = "maven.compiler.showDeprecation", defaultValue = "false")
-    private boolean showDeprecation;
+   /**
+    * Set to <code>true</code> to show messages about what the compiler is doing.
+    */
+   @Parameter(property = "maven.compiler.verbose", defaultValue = "false")
+   private boolean verbose;
 
-    /**
-     * Set to <code>true</code> to optimize the compiled code using the compiler's optimization methods.
-     */
-    @Parameter(property = "maven.compiler.optimize", defaultValue = "false")
-    private boolean optimize;
+   /**
+    * Sets whether to show source locations where deprecated APIs are used.
+    */
+   @Parameter(property = "maven.compiler.showDeprecation", defaultValue = "false")
+   private boolean showDeprecation;
 
-    /**
-     * Set to <code>true</code> to show compilation warnings.
-     */
-    @Parameter(property = "maven.compiler.showWarnings", defaultValue = "false")
-    private boolean showWarnings;
+   /**
+    * Set to <code>true</code> to optimize the compiled code using the compiler's optimization methods.
+    */
+   @Parameter(property = "maven.compiler.optimize", defaultValue = "false")
+   private boolean optimize;
 
-    /**
-     * The -source argument for the Java compiler.
-     */
-    @Parameter(property = "maven.compiler.source", defaultValue = "1.5")
-    protected String source;
+   /**
+    * Set to <code>true</code> to show compilation warnings.
+    */
+   @Parameter(property = "maven.compiler.showWarnings", defaultValue = "false")
+   private boolean showWarnings;
 
-    /**
-     * The -target argument for the Java compiler.
-     */
-    @Parameter(property = "maven.compiler.target", defaultValue = "1.5")
-    protected String target;
+   /**
+    * The -source argument for the Java compiler.
+    */
+   @Parameter(property = "maven.compiler.source", defaultValue = "1.5")
+   protected String source;
 
-    /**
-     * The -encoding argument for the Java compiler.
-     *
-     * @since 2.1
-     */
-    @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}")
-    private String encoding;
+   /**
+    * The -target argument for the Java compiler.
+    */
+   @Parameter(property = "maven.compiler.target", defaultValue = "1.5")
+   protected String target;
 
-    /**
-     * Sets the granularity in milliseconds of the last modification
-     * date for testing whether a source needs recompilation.
-     */
-    @Parameter(property = "lastModGranularityMs", defaultValue = "0")
-    private int staleMillis;
+   /**
+    * The -encoding argument for the Java compiler.
+    *
+    * @since 2.1
+    */
+   @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}")
+   private String encoding;
 
-    /**
-     * The compiler id of the compiler to use. See this
-     * <a href="non-javac-compilers.html">guide</a> for more information.
-     */
-    @Parameter(property = "maven.compiler.compilerId", defaultValue = "javac")
-    private String compilerId;
+   /**
+    * Sets the granularity in milliseconds of the last modification date for testing whether a source needs recompilation.
+    */
+   @Parameter(property = "lastModGranularityMs", defaultValue = "0")
+   private int staleMillis;
 
-    /**
-     * Version of the compiler to use, ex. "1.3", "1.5", if {@link #fork} is set to <code>true</code>.
-     */
-    @Parameter(property = "maven.compiler.compilerVersion")
-    private String compilerVersion;
+   /**
+    * The compiler id of the compiler to use. See this
+    * <a href="non-javac-compilers.html">guide</a> for more information.
+    */
+   @Parameter(property = "maven.compiler.compilerId", defaultValue = "javac")
+   private String compilerId;
 
-    /**
-     * Allows running the compiler in a separate process.
-     * If <code>false</code> it uses the built in compiler, while if <code>true</code> it will use an executable.
-     */
-    @Parameter(property = "maven.compiler.fork", defaultValue = "false")
-    private boolean fork;
+   /**
+    * Version of the compiler to use, ex. "1.3", "1.5", if {@link #fork} is set to <code>true</code>.
+    */
+   @Parameter(property = "maven.compiler.compilerVersion")
+   private String compilerVersion;
 
-    /**
-     * Initial size, in megabytes, of the memory allocation pool, ex. "64", "64m"
-     * if {@link #fork} is set to <code>true</code>.
-     *
-     * @since 2.0.1
-     */
-    @Parameter(property = "maven.compiler.meminitial")
-    private String meminitial;
+   /**
+    * Allows running the compiler in a separate process. If <code>false</code> it uses the built in compiler, while if <code>true</code> it
+    * will use an executable.
+    */
+   @Parameter(property = "maven.compiler.fork", defaultValue = "false")
+   private boolean fork;
 
-    /**
-     * Sets the maximum size, in megabytes, of the memory allocation pool, ex. "128", "128m"
-     * if {@link #fork} is set to <code>true</code>.
-     *
-     * @since 2.0.1
-     */
-    @Parameter(property = "maven.compiler.maxmem")
-    private String maxmem;
+   /**
+    * Initial size, in megabytes, of the memory allocation pool, ex. "64", "64m" if {@link #fork} is set to <code>true</code>.
+    *
+    * @since 2.0.1
+    */
+   @Parameter(property = "maven.compiler.meminitial")
+   private String meminitial;
 
-    /**
-     * Sets the executable of the compiler to use when {@link #fork} is <code>true</code>.
-     */
-    @Parameter(property = "maven.compiler.executable")
-    private String executable;
+   /**
+    * Sets the maximum size, in megabytes, of the memory allocation pool, ex. "128", "128m" if {@link #fork} is set to <code>true</code>.
+    *
+    * @since 2.0.1
+    */
+   @Parameter(property = "maven.compiler.maxmem")
+   private String maxmem;
 
-    /**
-     * <p>
-     * Sets whether annotation processing is performed or not. Only applies to JDK 1.6+
-     * If not set, both compilation and annotation processing are performed at the same time.
-     * </p>
-     * <p>Allowed values are:</p>
-     * <ul>
-     * <li><code>none</code> - no annotation processing is performed.</li>
-     * <li><code>only</code> - only annotation processing is done, no compilation.</li>
-     * </ul>
-     *
-     * @since 2.2
-     */
-    @Parameter
-    private String proc;
+   /**
+    * Sets the executable of the compiler to use when {@link #fork} is <code>true</code>.
+    */
+   @Parameter(property = "maven.compiler.executable")
+   private String executable;
 
-    /**
-     * <p>
-     * Names of annotation processors to run. Only applies to JDK 1.6+
-     * If not set, the default annotation processors discovery process applies.
-     * </p>
-     *
-     * @since 2.2
-     */
-    @Parameter
-    private String[] annotationProcessors;
+   /**
+    * <p>
+    * Sets whether annotation processing is performed or not. Only applies to JDK 1.6+ If not set, both compilation and annotation
+    * processing are performed at the same time.
+    * </p>
+    * <p>
+    * Allowed values are:</p>
+    * <ul>
+    * <li><code>none</code> - no annotation processing is performed.</li>
+    * <li><code>only</code> - only annotation processing is done, no compilation.</li>
+    * </ul>
+    *
+    * @since 2.2
+    */
+   @Parameter
+   private String proc;
 
-    /**
-     * <p>
-     * Sets the arguments to be passed to the compiler (prepending a dash) if {@link #fork} is set to <code>true</code>.
-     * </p>
-     * <p>
-     * This is because the list of valid arguments passed to a Java compiler
-     * varies based on the compiler version.
-     * </p>
-     * <p>
-     * To pass <code>-Xmaxerrs 1000 -Xlint -Xlint:-path -Averbose=true</code> you should include the following:
-     * </p>
-     * <pre>
-     * &lt;compilerArguments&gt;
-     *   &lt;Xmaxerrs&gt;1000&lt;/Xmaxerrs&gt;
-     *   &lt;Xlint/&gt;
-     *   &lt;Xlint:-path/&gt;
-     *   &lt;Averbose&gt;true&lt;/Averbose&gt;
-     * &lt;/compilerArguments&gt;
-     * </pre>
-     *
-     * @since 2.0.1
-     * @deprecated use {@link #compilerArgs} instead. 
-     */
-    @Parameter
-    @Deprecated
-    protected Map<String, String> compilerArguments;
+   /**
+    * <p>
+    * Names of annotation processors to run. Only applies to JDK 1.6+ If not set, the default annotation processors discovery process
+    * applies.
+    * </p>
+    *
+    * @since 2.2
+    */
+   @Parameter
+   private String[] annotationProcessors;
 
-    /**
-     * <p>
-     * Sets the arguments to be passed to the compiler if {@link #fork} is set to <code>true</code>.
-     * Example:
-     * <pre>
-     * &lt;compilerArgs&gt;
-     *   &lt;arg&gt;-Xmaxerrs=1000&lt;/arg&gt;
-     *   &lt;arg&gt;-Xlint&lt;/arg&gt;
-     * &lt;/compilerArgs&gt;
-     * </pre>
-     *
-     * @since 3.1
-     */
-    @Parameter
-    protected List<String> compilerArgs;
-    
-    /**
-     * <p>
-     * Sets the unformatted single argument string to be passed to the compiler if {@link #fork} is set to <code>true</code>.
-     * To pass multiple arguments such as <code>-Xmaxerrs 1000</code> (which are actually two arguments) you have to use {@link #compilerArguments}.
-     * </p>
-     * <p>
-     * This is because the list of valid arguments passed to a Java compiler
-     * varies based on the compiler version.
-     * </p>
-     */
-    @Parameter
-    protected String compilerArgument;
+   /**
+    * <p>
+    * Sets the arguments to be passed to the compiler (prepending a dash) if {@link #fork} is set to <code>true</code>.
+    * </p>
+    * <p>
+    * This is because the list of valid arguments passed to a Java compiler varies based on the compiler version.
+    * </p>
+    * <p>
+    * To pass <code>-Xmaxerrs 1000 -Xlint -Xlint:-path -Averbose=true</code> you should include the following:
+    * </p>
+    * <pre>
+    * &lt;compilerArguments&gt;
+    *   &lt;Xmaxerrs&gt;1000&lt;/Xmaxerrs&gt;
+    *   &lt;Xlint/&gt;
+    *   &lt;Xlint:-path/&gt;
+    *   &lt;Averbose&gt;true&lt;/Averbose&gt;
+    * &lt;/compilerArguments&gt;
+    * </pre>
+    *
+    * @since 2.0.1
+    * @deprecated use {@link #compilerArgs} instead.
+    */
+   @Parameter
+   @Deprecated
+   protected Map<String, String> compilerArguments;
 
-    /**
-     * Sets the name of the output file when compiling a set of
-     * sources to a single file.
-     * <p/>
-     * expression="${project.build.finalName}"
-     */
-    @Parameter
-    private String outputFileName;
+   /**
+    * <p>
+    * Sets the arguments to be passed to the compiler if {@link #fork} is set to <code>true</code>. Example:
+    * <pre>
+    * &lt;compilerArgs&gt;
+    *   &lt;arg&gt;-Xmaxerrs=1000&lt;/arg&gt;
+    *   &lt;arg&gt;-Xlint&lt;/arg&gt;
+    * &lt;/compilerArgs&gt;
+    * </pre>
+    *
+    * @since 3.1
+    */
+   @Parameter
+   protected List<String> compilerArgs;
 
-    /**
-     * Keyword list to be appended to the <code>-g</code> command-line switch. Legal values are none or a
-     * comma-separated list of the following keywords: <code>lines</code>, <code>vars</code>, and <code>source</code>.
-     * If debug level is not specified, by default, nothing will be appended to <code>-g</code>.
-     * If debug is not turned on, this attribute will be ignored.
-     *
-     * @since 2.1
-     */
-    @Parameter(property = "maven.compiler.debuglevel")
-    private String debuglevel;
+   /**
+    * <p>
+    * Sets the unformatted single argument string to be passed to the compiler if {@link #fork} is set to <code>true</code>. To pass
+    * multiple arguments such as <code>-Xmaxerrs 1000</code> (which are actually two arguments) you have to use {@link #compilerArguments}.
+    * </p>
+    * <p>
+    * This is because the list of valid arguments passed to a Java compiler varies based on the compiler version.
+    * </p>
+    */
+   @Parameter
+   protected String compilerArgument;
 
-    /**
-     *
-     */
-    @Component
-    private ToolchainManager toolchainManager;
+   /**
+    * Sets the name of the output file when compiling a set of sources to a single file.
+    * <p/>
+    * expression="${project.build.finalName}"
+    */
+   @Parameter
+   private String outputFileName;
 
-    // ----------------------------------------------------------------------
-    // Read-only parameters
-    // ----------------------------------------------------------------------
+   /**
+    * Keyword list to be appended to the <code>-g</code> command-line switch. Legal values are none or a comma-separated list of the
+    * following keywords: <code>lines</code>, <code>vars</code>, and <code>source</code>. If debug level is not specified, by default,
+    * nothing will be appended to <code>-g</code>. If debug is not turned on, this attribute will be ignored.
+    *
+    * @since 2.1
+    */
+   @Parameter(property = "maven.compiler.debuglevel")
+   private String debuglevel;
 
-    /**
-     * The directory to run the compiler from if fork is true.
-     */
-    @Parameter(defaultValue = "${basedir}", required = true, readonly = true)
-    private File basedir;
+   /**
+    *
+    */
+   @Component
+   private ToolchainManager toolchainManager;
 
-    /**
-     * The target directory of the compiler if fork is true.
-     */
-    @Parameter(defaultValue = "${project.build.directory}", required = true, readonly = true)
-    private File buildDirectory;
+   // ----------------------------------------------------------------------
+   // Read-only parameters
+   // ----------------------------------------------------------------------
+   /**
+    * The directory to run the compiler from if fork is true.
+    */
+   @Parameter(defaultValue = "${basedir}", required = true, readonly = true)
+   private File basedir;
 
-    /**
-     * Plexus compiler manager.
-     */
-    @Component
-    private CompilerManager compilerManager;
+   /**
+    * The target directory of the compiler if fork is true.
+    */
+   @Parameter(defaultValue = "${project.build.directory}", required = true, readonly = true)
+   private File buildDirectory;
 
-    /**
-     * The current build session instance. This is used for toolchain manager API calls.
-     */
-    @Component
-    private MavenSession session;
+   /**
+    * Plexus compiler manager.
+    */
+   @Component
+   private CompilerManager compilerManager;
 
-    /**
-     * Strategy to re use javacc class created:
-     * <ul>
-     * <li><code>reuseCreated</code> (default): will reuse already created but in case of multi-threaded builds,
-     * each thread will have its own instance</li>
-     * <li><code>reuseSame</code>: the same Javacc class will be used for each compilation even for multi-threaded build</li>
-     * <li><code>alwaysNew</code>: a new Javacc class will be created for each compilation</li>
-     * </ul>
-     * Note this parameter value depends on the os/jdk you are using, but the default value should work on most of env.
-     *
-     * @since 2.5
-     */
-    @Parameter(defaultValue = "${reuseCreated}", property = "maven.compiler.compilerReuseStrategy")
-    private String compilerReuseStrategy = "reuseCreated";
+   /**
+    * The current build session instance. This is used for toolchain manager API calls.
+    */
+   @Component
+   private MavenSession session;
 
-    /**
-     * @since 2.5
-     */
-    @Parameter(defaultValue = "false", property = "maven.compiler.skipMultiThreadWarning")
-    private boolean skipMultiThreadWarning;
+   /**
+    * Strategy to re use javacc class created:
+    * <ul>
+    * <li><code>reuseCreated</code> (default): will reuse already created but in case of multi-threaded builds, each thread will have its
+    * own instance</li>
+    * <li><code>reuseSame</code>: the same Javacc class will be used for each compilation even for multi-threaded build</li>
+    * <li><code>alwaysNew</code>: a new Javacc class will be created for each compilation</li>
+    * </ul>
+    * Note this parameter value depends on the os/jdk you are using, but the default value should work on most of env.
+    *
+    * @since 2.5
+    */
+   @Parameter(defaultValue = "${reuseCreated}", property = "maven.compiler.compilerReuseStrategy")
+   private String compilerReuseStrategy = "reuseCreated";
 
-    /**
-     * compiler can now use javax.tools if available in your current jdk, you can disable this feature
-     * using -Dmaven.compiler.forceJavacCompilerUse=true or in the plugin configuration
-     *
-     * @since 3.0
-     */
-    @Parameter(defaultValue = "false", property = "maven.compiler.forceJavacCompilerUse")
-    private boolean forceJavacCompilerUse;
+   /**
+    * @since 2.5
+    */
+   @Parameter(defaultValue = "false", property = "maven.compiler.skipMultiThreadWarning")
+   private boolean skipMultiThreadWarning;
 
-    /**
-     * @since 3.0 needed for storing the status for the incremental build support.
-     */
-    @Parameter(property = "mojoExecution")
-    private MojoExecution mojoExecution;
+   /**
+    * compiler can now use javax.tools if available in your current jdk, you can disable this feature using
+    * -Dmaven.compiler.forceJavacCompilerUse=true or in the plugin configuration
+    *
+    * @since 3.0
+    */
+   @Parameter(defaultValue = "false", property = "maven.compiler.forceJavacCompilerUse")
+   private boolean forceJavacCompilerUse;
 
-    /**
-     * We need this to determine the start timestamp of the build.
-     *
-     * @since 3.0
-     */
-    @Component
-    protected MavenSession mavenSession;
+   /**
+    * @since 3.0 needed for storing the status for the incremental build support.
+    */
+   @Parameter(property = "mojoExecution")
+   private MojoExecution mojoExecution;
 
-    /**
-     * file extensions to check timestamp for incremental build
-     * <b>default contains only <code>.class</code></b>
-     *
-     * @since 3.1
-     */
-    @Parameter
-    private List<String> fileExtensions;
+   /**
+    * We need this to determine the start timestamp of the build.
+    *
+    * @since 3.0
+    */
+   @Component
+   protected MavenSession mavenSession;
 
-    /**
-     * to enable/disable incrementation compilation feature
-     * @since 3.1
-     */
-    @Parameter(defaultValue = "true", property = "maven.compiler.useIncrementalCompilation")
-    private boolean useIncrementalCompilation = true;
+   /**
+    * file extensions to check timestamp for incremental build
+    * <b>default contains only <code>.class</code></b>
+    *
+    * @since 3.1
+    */
+   @Parameter
+   private List<String> fileExtensions;
 
-    protected abstract SourceInclusionScanner getSourceInclusionScanner( int staleMillis );
+   /**
+    * to enable/disable incrementation compilation feature
+    *
+    * @since 3.1
+    */
+   @Parameter(defaultValue = "true", property = "maven.compiler.useIncrementalCompilation")
+   private boolean useIncrementalCompilation = true;
 
-    protected abstract SourceInclusionScanner getSourceInclusionScanner( String inputFileEnding );
+   protected abstract SourceInclusionScanner getSourceInclusionScanner(int staleMillis);
 
-    protected abstract List<String> getClasspathElements();
+   protected abstract SourceInclusionScanner getSourceInclusionScanner(String inputFileEnding);
 
-    protected abstract List<String> getCompileSourceRoots();
+   protected abstract List<String> getClasspathElements();
 
-    protected abstract File getOutputDirectory();
+   protected abstract List<String> getCompileSourceRoots();
 
-    protected abstract String getSource();
+   protected abstract File getOutputDirectory();
 
-    protected abstract String getTarget();
+   protected abstract String getSource();
 
-    protected abstract String getCompilerArgument();
+   protected abstract String getTarget();
 
-    protected abstract Map<String, String> getCompilerArguments();
+   protected abstract String getCompilerArgument();
 
-    protected abstract File getGeneratedSourcesDirectory();
+   protected abstract Map<String, String> getCompilerArguments();
 
-    public void execute()
-        throws MojoExecutionException, CompilationFailureException
-    {
-        // ----------------------------------------------------------------------
-        // Look up the compiler. This is done before other code than can
-        // cause the mojo to return before the lookup is done possibly resulting
-        // in misconfigured POMs still building.
-        // ----------------------------------------------------------------------
+   protected abstract File getGeneratedSourcesDirectory();
 
-        Compiler compiler;
+   public void execute()
+           throws MojoExecutionException, CompilationFailureException
+   {
+      // ----------------------------------------------------------------------
+      // Look up the compiler. This is done before other code than can
+      // cause the mojo to return before the lookup is done possibly resulting
+      // in misconfigured POMs still building.
+      // ----------------------------------------------------------------------
 
-        getLog().debug( "Using compiler '" + compilerId + "'." );
+      Compiler compiler;
 
-        try
-        {
-            compiler = compilerManager.getCompiler( compilerId );
-        }
-        catch ( NoSuchCompilerException e )
-        {
-            throw new MojoExecutionException( "No such compiler '" + e.getCompilerId() + "'." );
-        }
+      getLog().debug("Using compiler '" + compilerId + "'.");
 
-        //-----------toolchains start here ----------------------------------
-        //use the compilerId as identifier for toolchains as well.
-        Toolchain tc = getToolchain();
-        if ( tc != null )
-        {
-            getLog().info( "Toolchain in compiler-plugin: " + tc );
-            if ( executable != null )
-            {
-                getLog().warn( "Toolchains are ignored, 'executable' parameter is set to " + executable );
-            }
-            else
-            {
-                fork = true;
-                //TODO somehow shaky dependency between compilerId and tool executable.
-                executable = tc.findTool( compilerId );
-            }
-        }
-        // ----------------------------------------------------------------------
-        //
-        // ----------------------------------------------------------------------
+      try
+      {
+         compiler = compilerManager.getCompiler(compilerId);
+      }
+      catch (NoSuchCompilerException e)
+      {
+         throw new MojoExecutionException("No such compiler '" + e.getCompilerId() + "'.");
+      }
 
-        List<String> compileSourceRoots = removeEmptyCompileSourceRoots( getCompileSourceRoots() );
+      //-----------toolchains start here ----------------------------------
+      //use the compilerId as identifier for toolchains as well.
+      Toolchain tc = getToolchain();
+      if (tc != null)
+      {
+         getLog().info("Toolchain in compiler-plugin: " + tc);
+         if (executable != null)
+         {
+            getLog().warn("Toolchains are ignored, 'executable' parameter is set to " + executable);
+         }
+         else
+         {
+            fork = true;
+            //TODO somehow shaky dependency between compilerId and tool executable.
+            executable = tc.findTool(compilerId);
+         }
+      }
+      // ----------------------------------------------------------------------
+      //
+      // ----------------------------------------------------------------------
 
-        if ( compileSourceRoots.isEmpty() )
-        {
-            getLog().info( "No sources to compile" );
+      List<String> compileSourceRoots = removeEmptyCompileSourceRoots(getCompileSourceRoots());
 
-            return;
-        }
+      if (compileSourceRoots.isEmpty())
+      {
+         getLog().info("No sources to compile");
 
-        if ( getLog().isDebugEnabled() )
-        {
-            getLog().debug( "Source directories: " + compileSourceRoots.toString().replace( ',', '\n' ) );
-            getLog().debug( "Classpath: " + getClasspathElements().toString().replace( ',', '\n' ) );
-            getLog().debug( "Output directory: " + getOutputDirectory() );
-        }
+         return;
+      }
 
-        // ----------------------------------------------------------------------
-        // Create the compiler configuration
-        // ----------------------------------------------------------------------
+      if (getLog().isDebugEnabled())
+      {
+         getLog().debug("Source directories: " + compileSourceRoots.toString().replace(',', '\n'));
+         getLog().debug("Classpath: " + getClasspathElements().toString().replace(',', '\n'));
+         getLog().debug("Output directory: " + getOutputDirectory());
+      }
 
-        CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
+      // ----------------------------------------------------------------------
+      // Create the compiler configuration
+      // ----------------------------------------------------------------------
+      CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
 
-        compilerConfiguration.setOutputLocation( getOutputDirectory().getAbsolutePath() );
+      compilerConfiguration.setOutputLocation(getOutputDirectory().getAbsolutePath());
 
-        compilerConfiguration.setClasspathEntries( getClasspathElements() );
+      compilerConfiguration.setClasspathEntries(getClasspathElements());
 
-        compilerConfiguration.setSourceLocations( compileSourceRoots );
+      compilerConfiguration.setSourceLocations(compileSourceRoots);
 
-        compilerConfiguration.setOptimize( optimize );
+      compilerConfiguration.setOptimize(optimize);
 
-        compilerConfiguration.setDebug( debug );
+      compilerConfiguration.setDebug(debug);
 
-        if ( debug && StringUtils.isNotEmpty( debuglevel ) )
-        {
-            String[] split = StringUtils.split( debuglevel, "," );
-            for ( int i = 0; i < split.length; i++ )
+      if (debug && StringUtils.isNotEmpty(debuglevel))
+      {
+         String[] split = StringUtils.split(debuglevel, ",");
+         for (int i = 0; i < split.length; i++)
+         {
+            if (!(split[i].equalsIgnoreCase("none") || split[i].equalsIgnoreCase("lines")
+                    || split[i].equalsIgnoreCase("vars") || split[i].equalsIgnoreCase("source")))
             {
-                if ( !( split[i].equalsIgnoreCase( "none" ) || split[i].equalsIgnoreCase( "lines" )
-                    || split[i].equalsIgnoreCase( "vars" ) || split[i].equalsIgnoreCase( "source" ) ) )
-                {
-                    throw new IllegalArgumentException( "The specified debug level: '" + split[i] + "' is unsupported. "
-                                                            + "Legal values are 'none', 'lines', 'vars', and 'source'." );
-                }
+               throw new IllegalArgumentException("The specified debug level: '" + split[i] + "' is unsupported. "
+                       + "Legal values are 'none', 'lines', 'vars', and 'source'.");
             }
-            compilerConfiguration.setDebugLevel( debuglevel );
-        }
+         }
+         compilerConfiguration.setDebugLevel(debuglevel);
+      }
 
-        compilerConfiguration.setVerbose( verbose );
+      compilerConfiguration.setVerbose(verbose);
 
-        compilerConfiguration.setShowWarnings( showWarnings );
+      compilerConfiguration.setShowWarnings(showWarnings);
 
-        compilerConfiguration.setShowDeprecation( showDeprecation );
+      compilerConfiguration.setShowDeprecation(showDeprecation);
 
-        compilerConfiguration.setSourceVersion( getSource() );
+      compilerConfiguration.setSourceVersion(getSource());
 
-        compilerConfiguration.setTargetVersion( getTarget() );
+      compilerConfiguration.setTargetVersion(getTarget());
 
-        compilerConfiguration.setProc( proc );
+      compilerConfiguration.setProc(proc);
 
-        compilerConfiguration.setGeneratedSourcesDirectory( getGeneratedSourcesDirectory() );
+      compilerConfiguration.setGeneratedSourcesDirectory(getGeneratedSourcesDirectory());
 
-        compilerConfiguration.setAnnotationProcessors( annotationProcessors );
+      compilerConfiguration.setAnnotationProcessors(annotationProcessors);
 
-        compilerConfiguration.setSourceEncoding( encoding );
+      compilerConfiguration.setSourceEncoding(encoding);
 
-        Map<String, String> effectiveCompilerArguments = getCompilerArguments();
+      Map<String, String> effectiveCompilerArguments = getCompilerArguments();
 
-        String effectiveCompilerArgument = getCompilerArgument();
+      String effectiveCompilerArgument = getCompilerArgument();
 
-        if ( ( effectiveCompilerArguments != null ) || ( effectiveCompilerArgument != null ) || ( compilerArgs != null ) )
-        {
-            LinkedHashMap<String, String> cplrArgsCopy = new LinkedHashMap<String, String>();
-            if ( effectiveCompilerArguments != null )
+      if ((effectiveCompilerArguments != null) || (effectiveCompilerArgument != null) || (compilerArgs != null))
+      {
+         LinkedHashMap<String, String> cplrArgsCopy = new LinkedHashMap<String, String>();
+         if (effectiveCompilerArguments != null)
+         {
+            for (Map.Entry<String, String> me : effectiveCompilerArguments.entrySet())
             {
-                for ( Map.Entry<String, String> me : effectiveCompilerArguments.entrySet() )
-                {
-                    String key = me.getKey();
-                    String value = me.getValue();
-                    if ( !key.startsWith( "-" ) )
-                    {
-                        key = "-" + key;
-                    }
+               String key = me.getKey();
+               String value = me.getValue();
+               if (!key.startsWith("-"))
+               {
+                  key = "-" + key;
+               }
 
-                    if ( key.startsWith( "-A" ) && StringUtils.isNotEmpty( value ) )
-                    {
-                        cplrArgsCopy.put( key + "=" + value, null );
-                    }
-                    else
-                    {
-                        cplrArgsCopy.put( key, value );
-                    }
-                }
+               if (key.startsWith("-A") && StringUtils.isNotEmpty(value))
+               {
+                  cplrArgsCopy.put(key + "=" + value, null);
+               }
+               else
+               {
+                  cplrArgsCopy.put(key, value);
+               }
             }
-            if ( !StringUtils.isEmpty( effectiveCompilerArgument ) )
+         }
+         if (!StringUtils.isEmpty(effectiveCompilerArgument))
+         {
+            cplrArgsCopy.put(effectiveCompilerArgument, null);
+         }
+         if (compilerArgs != null)
+         {
+            for (String arg : compilerArgs)
             {
-                cplrArgsCopy.put( effectiveCompilerArgument, null );
+               cplrArgsCopy.put(arg, null);
             }
-            if ( compilerArgs != null )
+         }
+         compilerConfiguration.setCustomCompilerArguments(cplrArgsCopy);
+      }
+
+      compilerConfiguration.setFork(fork);
+
+      if (fork)
+      {
+         if (!StringUtils.isEmpty(meminitial))
+         {
+            String value = getMemoryValue(meminitial);
+
+            if (value != null)
             {
-                for ( String arg : compilerArgs )
-                {
-                    cplrArgsCopy.put( arg, null );
-                }
+               compilerConfiguration.setMeminitial(value);
             }
-            compilerConfiguration.setCustomCompilerArguments( cplrArgsCopy );
-        }
+            else
+            {
+               getLog().info("Invalid value for meminitial '" + meminitial + "'. Ignoring this option.");
+            }
+         }
 
-        compilerConfiguration.setFork( fork );
+         if (!StringUtils.isEmpty(maxmem))
+         {
+            String value = getMemoryValue(maxmem);
 
-        if ( fork )
-        {
-            if ( !StringUtils.isEmpty( meminitial ) )
+            if (value != null)
             {
-                String value = getMemoryValue( meminitial );
-
-                if ( value != null )
-                {
-                    compilerConfiguration.setMeminitial( value );
-                }
-                else
-                {
-                    getLog().info( "Invalid value for meminitial '" + meminitial + "'. Ignoring this option." );
-                }
+               compilerConfiguration.setMaxmem(value);
             }
-
-            if ( !StringUtils.isEmpty( maxmem ) )
+            else
             {
-                String value = getMemoryValue( maxmem );
-
-                if ( value != null )
-                {
-                    compilerConfiguration.setMaxmem( value );
-                }
-                else
-                {
-                    getLog().info( "Invalid value for maxmem '" + maxmem + "'. Ignoring this option." );
-                }
+               getLog().info("Invalid value for maxmem '" + maxmem + "'. Ignoring this option.");
             }
-        }
+         }
+      }
 
-        compilerConfiguration.setExecutable( executable );
+      compilerConfiguration.setExecutable(executable);
 
-        compilerConfiguration.setWorkingDirectory( basedir );
+      compilerConfiguration.setWorkingDirectory(basedir);
 
-        compilerConfiguration.setCompilerVersion( compilerVersion );
+      compilerConfiguration.setCompilerVersion(compilerVersion);
 
-        compilerConfiguration.setBuildDirectory( buildDirectory );
+      compilerConfiguration.setBuildDirectory(buildDirectory);
 
-        compilerConfiguration.setOutputFileName( outputFileName );
+      compilerConfiguration.setOutputFileName(outputFileName);
 
-        if ( CompilerConfiguration.CompilerReuseStrategy.AlwaysNew.getStrategy().equals( this.compilerReuseStrategy ) )
-        {
-            compilerConfiguration.setCompilerReuseStrategy( CompilerConfiguration.CompilerReuseStrategy.AlwaysNew );
-        }
-        else if ( CompilerConfiguration.CompilerReuseStrategy.ReuseSame.getStrategy().equals(
-            this.compilerReuseStrategy ) )
-        {
-            if ( getRequestThreadCount() > 1 )
+      if (CompilerConfiguration.CompilerReuseStrategy.AlwaysNew.getStrategy().equals(this.compilerReuseStrategy))
+      {
+         compilerConfiguration.setCompilerReuseStrategy(CompilerConfiguration.CompilerReuseStrategy.AlwaysNew);
+      }
+      else if (CompilerConfiguration.CompilerReuseStrategy.ReuseSame.getStrategy().equals(
+              this.compilerReuseStrategy))
+      {
+         if (getRequestThreadCount() > 1)
+         {
+            if (!skipMultiThreadWarning)
             {
-                if ( !skipMultiThreadWarning )
-                {
-                    StringBuilder sb = new StringBuilder(
-                        "You are in a multi-thread build and compilerReuseStrategy is set to reuseSame. This can cause issues in some environments (os/jdk)! Consider using reuseCreated strategy." );
-                    sb.append( System.getProperty( "line.separator" ) );
-                    sb.append(
-                        "If your env is fine with reuseSame, you can skip this warning with the configuration field skipMultiThreadWarning or -Dmaven.compiler.skipMultiThreadWarning=true" );
-                    getLog().warn( sb.toString() );
-                }
+               StringBuilder sb = new StringBuilder(
+                       "You are in a multi-thread build and compilerReuseStrategy is set to reuseSame. This can cause issues in some environments (os/jdk)! Consider using reuseCreated strategy.");
+               sb.append(System.getProperty("line.separator"));
+               sb.append(
+                       "If your env is fine with reuseSame, you can skip this warning with the configuration field skipMultiThreadWarning or -Dmaven.compiler.skipMultiThreadWarning=true");
+               getLog().warn(sb.toString());
             }
-            compilerConfiguration.setCompilerReuseStrategy( CompilerConfiguration.CompilerReuseStrategy.ReuseSame );
-        }
-        else
-        {
+         }
+         compilerConfiguration.setCompilerReuseStrategy(CompilerConfiguration.CompilerReuseStrategy.ReuseSame);
+      }
+      else
+      {
 
-            compilerConfiguration.setCompilerReuseStrategy( CompilerConfiguration.CompilerReuseStrategy.ReuseCreated );
-        }
+         compilerConfiguration.setCompilerReuseStrategy(CompilerConfiguration.CompilerReuseStrategy.ReuseCreated);
+      }
 
-        getLog().debug( "CompilerReuseStrategy: " + compilerConfiguration.getCompilerReuseStrategy().getStrategy() );
+      getLog().debug("CompilerReuseStrategy: " + compilerConfiguration.getCompilerReuseStrategy().getStrategy());
 
-        compilerConfiguration.setForceJavacCompilerUse( forceJavacCompilerUse );
+      compilerConfiguration.setForceJavacCompilerUse(forceJavacCompilerUse);
 
-        boolean canUpdateTarget;
+      boolean canUpdateTarget;
 
-        IncrementalBuildHelper incrementalBuildHelper = new IncrementalBuildHelper( mojoExecution, mavenSession );
+      IncrementalBuildHelper incrementalBuildHelper = new IncrementalBuildHelper(mojoExecution, mavenSession);
 
-        Set<File> sources = null;
+      Set<File> sources = null;
 
-        IncrementalBuildHelperRequest incrementalBuildHelperRequest = null;
+      IncrementalBuildHelperRequest incrementalBuildHelperRequest = null;
+      Map<File, byte[]> dependencyInfo = null;
 
-        if ( useIncrementalCompilation )
-        {
-            getLog().debug( "useIncrementalCompilation enabled" );
-            try
-            {
-                canUpdateTarget = compiler.canUpdateTarget( compilerConfiguration );
+      if (useIncrementalCompilation)
+      {
+         getLog().debug("useIncrementalCompilation enabled");
+         try
+         {
+            canUpdateTarget = compiler.canUpdateTarget(compilerConfiguration);
 
-                sources = getCompileSources( compiler, compilerConfiguration );
+            sources = getCompileSources(compiler, compilerConfiguration);
 
-                incrementalBuildHelperRequest = new IncrementalBuildHelperRequest().inputFiles( sources );
+            incrementalBuildHelperRequest = new IncrementalBuildHelperRequest().inputFiles(sources);
+            dependencyInfo = createDependencyInfo();
 
-                if ( ( compiler.getCompilerOutputStyle().equals( CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
-                    && !canUpdateTarget ) || isDependencyChanged() || isSourceChanged( compilerConfiguration, compiler )
-                    || incrementalBuildHelper.inputFileTreeChanged( incrementalBuildHelperRequest ) )
-                {
-                    getLog().info( "Changes detected - recompiling the module!" );
+            if ((compiler.getCompilerOutputStyle().equals(CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES)
+                    && !canUpdateTarget) || isDependencyChanged(incrementalBuildHelper, dependencyInfo)
+                    || isSourceChanged(compilerConfiguration, compiler)
+                    || incrementalBuildHelper.inputFileTreeChanged(incrementalBuildHelperRequest))
+            {
+               getLog().info("Changes detected - recompiling the module!");
 
-                    compilerConfiguration.setSourceFiles( sources );
-                }
-                else
-                {
-                    getLog().info( "Nothing to compile - all classes are up to date" );
-
-                    return;
-                }
+               compilerConfiguration.setSourceFiles(sources);
             }
-            catch ( CompilerException e )
+            else
             {
-                throw new MojoExecutionException( "Error while computing stale sources.", e );
+               getLog().info("Nothing to compile - all classes are up to date");
+
+               return;
             }
-        }
-        else
-        {
-            getLog().debug( "useIncrementalCompilation disabled" );
-            Set<File> staleSources;
-            try
-            {
-                staleSources =
-                    computeStaleSources( compilerConfiguration, compiler, getSourceInclusionScanner( staleMillis ) );
+         }
+         catch (CompilerException e)
+         {
+            throw new MojoExecutionException("Error while computing stale sources.", e);
+         }
+      }
+      else
+      {
+         getLog().debug("useIncrementalCompilation disabled");
+         Set<File> staleSources;
+         try
+         {
+            staleSources
+                    = computeStaleSources(compilerConfiguration, compiler, getSourceInclusionScanner(staleMillis));
 
-                canUpdateTarget = compiler.canUpdateTarget( compilerConfiguration );
+            canUpdateTarget = compiler.canUpdateTarget(compilerConfiguration);
 
-                if ( compiler.getCompilerOutputStyle().equals( CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
-                    && !canUpdateTarget )
-                {
-                    getLog().info( "RESCANNING!" );
-                    // TODO: This second scan for source files is sub-optimal
-                    String inputFileEnding = compiler.getInputFileEnding( compilerConfiguration );
+            if (compiler.getCompilerOutputStyle().equals(CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES)
+                    && !canUpdateTarget)
+            {
+               getLog().info("RESCANNING!");
+               // TODO: This second scan for source files is sub-optimal
+               String inputFileEnding = compiler.getInputFileEnding(compilerConfiguration);
 
-                    sources = computeStaleSources( compilerConfiguration, compiler,
-                                                             getSourceInclusionScanner( inputFileEnding ) );
+               sources = computeStaleSources(compilerConfiguration, compiler,
+                       getSourceInclusionScanner(inputFileEnding));
 
-                    compilerConfiguration.setSourceFiles( sources );
-                }
-                else
-                {
-                    compilerConfiguration.setSourceFiles( staleSources );
-                }
+               compilerConfiguration.setSourceFiles(sources);
             }
-            catch ( CompilerException e )
+            else
             {
-                throw new MojoExecutionException( "Error while computing stale sources.", e );
+               compilerConfiguration.setSourceFiles(staleSources);
             }
+         }
+         catch (CompilerException e)
+         {
+            throw new MojoExecutionException("Error while computing stale sources.", e);
+         }
 
-            if ( staleSources.isEmpty() )
-            {
-                getLog().info( "Nothing to compile - all classes are up to date" );
+         if (staleSources.isEmpty())
+         {
+            getLog().info("Nothing to compile - all classes are up to date");
 
-                return;
-            }
-        }
-        // ----------------------------------------------------------------------
-        // Dump configuration
-        // ----------------------------------------------------------------------
+            return;
+         }
+      }
+      // ----------------------------------------------------------------------
+      // Dump configuration
+      // ----------------------------------------------------------------------
 
-        if ( getLog().isDebugEnabled() )
-        {
-            getLog().debug( "Classpath:" );
+      if (getLog().isDebugEnabled())
+      {
+         getLog().debug("Classpath:");
 
-            for ( String s : getClasspathElements() )
-            {
-                getLog().debug( " " + s );
-            }
+         for (String s : getClasspathElements())
+         {
+            getLog().debug(" " + s);
+         }
 
-            getLog().debug( "Source roots:" );
+         getLog().debug("Source roots:");
 
-            for ( String root : getCompileSourceRoots() )
+         for (String root : getCompileSourceRoots())
+         {
+            getLog().debug(" " + root);
+         }
+
+         try
+         {
+            if (fork)
             {
-                getLog().debug( " " + root );
+               if (compilerConfiguration.getExecutable() != null)
+               {
+                  getLog().debug("Excutable: ");
+                  getLog().debug(" " + compilerConfiguration.getExecutable());
+               }
             }
 
-            try
+            String[] cl = compiler.createCommandLine(compilerConfiguration);
+            if (cl != null && cl.length > 0)
             {
-                if ( fork )
-                {
-                    if ( compilerConfiguration.getExecutable() != null )
-                    {
-                        getLog().debug( "Excutable: " );
-                        getLog().debug( " " + compilerConfiguration.getExecutable() );
-                    }
-                }
-
-                String[] cl = compiler.createCommandLine( compilerConfiguration );
-                if ( cl != null && cl.length > 0 )
-                {
-                    StringBuilder sb = new StringBuilder();
-                    sb.append( cl[0] );
-                    for ( int i = 1; i < cl.length; i++ )
-                    {
-                        sb.append( " " );
-                        sb.append( cl[i] );
-                    }
-                    getLog().debug( "Command line options:" );
-                    getLog().debug( sb );
-                }
+               StringBuilder sb = new StringBuilder();
+               sb.append(cl[0]);
+               for (int i = 1; i < cl.length; i++)
+               {
+                  sb.append(" ");
+                  sb.append(cl[i]);
+               }
+               getLog().debug("Command line options:");
+               getLog().debug(sb);
             }
-            catch ( CompilerException ce )
-            {
-                getLog().debug( ce );
-            }
-        }
+         }
+         catch (CompilerException ce)
+         {
+            getLog().debug(ce);
+         }
+      }
 
-        // ----------------------------------------------------------------------
-        // Compile!
-        // ----------------------------------------------------------------------
+      // ----------------------------------------------------------------------
+      // Compile!
+      // ----------------------------------------------------------------------
+      if (StringUtils.isEmpty(compilerConfiguration.getSourceEncoding()))
+      {
+         getLog().warn("File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
+                 + ", i.e. build is platform dependent!");
+      }
 
-        if ( StringUtils.isEmpty( compilerConfiguration.getSourceEncoding() ) )
-        {
-            getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
-                               + ", i.e. build is platform dependent!" );
-        }
+      CompilerResult compilerResult;
 
-        CompilerResult compilerResult;
+      if (useIncrementalCompilation)
+      {
+         incrementalBuildHelperRequest.outputDirectory(getOutputDirectory());
 
+         incrementalBuildHelper.beforeRebuildExecution(incrementalBuildHelperRequest);
 
-        if ( useIncrementalCompilation )
-        {
-            incrementalBuildHelperRequest.outputDirectory( getOutputDirectory() );
+         getLog().debug("incrementalBuildHelper#beforeRebuildExecution");
+      }
 
-            incrementalBuildHelper.beforeRebuildExecution( incrementalBuildHelperRequest );
+      try
+      {
+         try
+         {
+            compilerResult = compiler.performCompile(compilerConfiguration);
+         }
+         catch (CompilerNotImplementedException cnie)
+         {
+            List<CompilerError> messages = compiler.compile(compilerConfiguration);
+            compilerResult = convertToCompilerResult(messages);
+         }
+      }
+      catch (Exception e)
+      {
+         // TODO: don't catch Exception
+         throw new MojoExecutionException("Fatal error compiling", e);
+      }
 
-            getLog().debug( "incrementalBuildHelper#beforeRebuildExecution" );
-        }
+      if (useIncrementalCompilation)
+      {
+         if (incrementalBuildHelperRequest.getOutputDirectory().exists())
+         {
+            getLog().debug("incrementalBuildHelper#afterRebuildExecution");
+            // now scan the same directory again and create a diff
+            incrementalBuildHelper.afterRebuildExecution(incrementalBuildHelperRequest);
+            keepDependencyInfo(incrementalBuildHelper, dependencyInfo);
+         }
+         else
+         {
+            getLog().debug(
+                    "skip incrementalBuildHelper#afterRebuildExecution as the output directory doesn't exist");
+         }
+      }
 
-        try
-        {
-            try
-            {
-                compilerResult = compiler.performCompile( compilerConfiguration );
-            }
-            catch ( CompilerNotImplementedException cnie )
-            {
-                List<CompilerError> messages = compiler.compile( compilerConfiguration );
-                compilerResult = convertToCompilerResult( messages );
-            }
-        }
-        catch ( Exception e )
-        {
-            // TODO: don't catch Exception
-            throw new MojoExecutionException( "Fatal error compiling", e );
-        }
+      List<CompilerMessage> warnings = new ArrayList<CompilerMessage>();
+      List<CompilerMessage> errors = new ArrayList<CompilerMessage>();
+      for (CompilerMessage message : compilerResult.getCompilerMessages())
+      {
+         if (message.isError())
+         {
+            errors.add(message);
+         }
+         else
+         {
+            warnings.add(message);
+         }
+      }
 
-        if ( useIncrementalCompilation )
-        {
-            if ( incrementalBuildHelperRequest.getOutputDirectory().exists() )
+      if (failOnError && !compilerResult.isSuccess())
+      {
+         if (!warnings.isEmpty())
+         {
+            getLog().info("-------------------------------------------------------------");
+            getLog().warn("COMPILATION WARNING : ");
+            getLog().info("-------------------------------------------------------------");
+            for (CompilerMessage warning : warnings)
             {
-                getLog().debug( "incrementalBuildHelper#afterRebuildExecution" );
-                // now scan the same directory again and create a diff
-                incrementalBuildHelper.afterRebuildExecution( incrementalBuildHelperRequest );
+               getLog().warn(warning.toString());
             }
-            else
-            {
-                getLog().debug(
-                    "skip incrementalBuildHelper#afterRebuildExecution as the output directory doesn't exist" );
-            }
-        }
+            getLog().info(warnings.size() + ((warnings.size() > 1) ? " warnings " : " warning"));
+            getLog().info("-------------------------------------------------------------");
+         }
 
-        List<CompilerMessage> warnings = new ArrayList<CompilerMessage>();
-        List<CompilerMessage> errors = new ArrayList<CompilerMessage>();
-        for ( CompilerMessage message : compilerResult.getCompilerMessages() )
-        {
-            if ( message.isError() )
+         if (!errors.isEmpty())
+         {
+            getLog().info("-------------------------------------------------------------");
+            getLog().error("COMPILATION ERROR : ");
+            getLog().info("-------------------------------------------------------------");
+            for (CompilerMessage error : errors)
             {
-                errors.add( message );
+               getLog().error(error.toString());
             }
-            else
-            {
-                warnings.add( message );
-            }
-        }
+            getLog().info(errors.size() + ((errors.size() > 1) ? " errors " : " error"));
+            getLog().info("-------------------------------------------------------------");
+         }
 
-        if ( failOnError && !compilerResult.isSuccess() )
-        {
-            if ( !warnings.isEmpty() )
-            {
-                getLog().info( "-------------------------------------------------------------" );
-                getLog().warn( "COMPILATION WARNING : " );
-                getLog().info( "-------------------------------------------------------------" );
-                for ( CompilerMessage warning : warnings )
-                {
-                    getLog().warn( warning.toString() );
-                }
-                getLog().info( warnings.size() + ( ( warnings.size() > 1 ) ? " warnings " : " warning" ) );
-                getLog().info( "-------------------------------------------------------------" );
-            }
+         if (!errors.isEmpty())
+         {
+            throw new CompilationFailureException(errors);
+         }
+         else
+         {
+            throw new CompilationFailureException(warnings);
+         }
+      }
+      else
+      {
+         for (CompilerMessage message : compilerResult.getCompilerMessages())
+         {
+            getLog().warn(message.toString());
+         }
+      }
+   }
 
-            if ( !errors.isEmpty() )
-            {
-                getLog().info( "-------------------------------------------------------------" );
-                getLog().error( "COMPILATION ERROR : " );
-                getLog().info( "-------------------------------------------------------------" );
-                for ( CompilerMessage error : errors )
-                {
-                    getLog().error( error.toString() );
-                }
-                getLog().info( errors.size() + ( ( errors.size() > 1 ) ? " errors " : " error" ) );
-                getLog().info( "-------------------------------------------------------------" );
-            }
+   protected CompilerResult convertToCompilerResult(List<CompilerError> compilerErrors)
+   {
+      if (compilerErrors == null)
+      {
+         return new CompilerResult();
+      }
+      List<CompilerMessage> messages = new ArrayList<CompilerMessage>(compilerErrors.size());
+      boolean success = true;
+      for (CompilerError compilerError : compilerErrors)
+      {
+         messages.add(
+                 new CompilerMessage(compilerError.getFile(), compilerError.getKind(), compilerError.getStartLine(),
+                         compilerError.getStartColumn(), compilerError.getEndLine(),
+                         compilerError.getEndColumn(), compilerError.getMessage()));
+         if (compilerError.isError())
+         {
+            success = false;
+         }
+      }
 
-            if ( !errors.isEmpty() )
-            {
-                throw new CompilationFailureException( errors );
-            }
-            else
-            {
-                throw new CompilationFailureException( warnings );
-            }
-        }
-        else
-        {
-            for ( CompilerMessage message : compilerResult.getCompilerMessages() )
-            {
-                getLog().warn( message.toString() );
-            }
-        }
-    }
+      return new CompilerResult(success, messages);
+   }
 
-    protected CompilerResult convertToCompilerResult( List<CompilerError> compilerErrors )
-    {
-        if ( compilerErrors == null )
-        {
-            return new CompilerResult();
-        }
-        List<CompilerMessage> messages = new ArrayList<CompilerMessage>( compilerErrors.size() );
-        boolean success = true;
-        for ( CompilerError compilerError : compilerErrors )
-        {
-            messages.add(
-                new CompilerMessage( compilerError.getFile(), compilerError.getKind(), compilerError.getStartLine(),
-                                     compilerError.getStartColumn(), compilerError.getEndLine(),
-                                     compilerError.getEndColumn(), compilerError.getMessage() ) );
-            if ( compilerError.isError() )
-            {
-                success = false;
-            }
-        }
+   /**
+    * @return all source files for the compiler
+    */
+   private Set<File> getCompileSources(Compiler compiler, CompilerConfiguration compilerConfiguration)
+           throws MojoExecutionException, CompilerException
+   {
+      String inputFileEnding = compiler.getInputFileEnding(compilerConfiguration);
+      if (StringUtils.isEmpty(inputFileEnding))
+      {
+         // see MCOMPILER-199 GroovyEclipseCompiler doesn't set inputFileEnding
+         // so we can presume it's all files from the source directory
+         inputFileEnding = ".*";
+      }
+      SourceInclusionScanner scanner = getSourceInclusionScanner(inputFileEnding);
 
-        return new CompilerResult( success, messages );
-    }
+      SourceMapping mapping = getSourceMapping(compilerConfiguration, compiler);
 
-    /**
-     * @return all source files for the compiler
-     */
-    private Set<File> getCompileSources( Compiler compiler, CompilerConfiguration compilerConfiguration )
-        throws MojoExecutionException, CompilerException
-    {
-        String inputFileEnding = compiler.getInputFileEnding( compilerConfiguration );
-        if ( StringUtils.isEmpty( inputFileEnding ) )
-        {
-            // see MCOMPILER-199 GroovyEclipseCompiler doesn't set inputFileEnding
-            // so we can presume it's all files from the source directory
-            inputFileEnding = ".*";
-        }
-        SourceInclusionScanner scanner = getSourceInclusionScanner( inputFileEnding );
+      scanner.addSourceMapping(mapping);
 
-        SourceMapping mapping = getSourceMapping( compilerConfiguration, compiler );
+      Set<File> compileSources = new HashSet<File>();
 
-        scanner.addSourceMapping( mapping );
+      for (String sourceRoot : getCompileSourceRoots())
+      {
+         File rootFile = new File(sourceRoot);
 
-        Set<File> compileSources = new HashSet<File>();
+         if (!rootFile.isDirectory())
+         {
+            continue;
+         }
 
-        for ( String sourceRoot : getCompileSourceRoots() )
-        {
-            File rootFile = new File( sourceRoot );
+         try
+         {
+            compileSources.addAll(scanner.getIncludedSources(rootFile, null));
+         }
+         catch (InclusionScanException e)
+         {
+            throw new MojoExecutionException(
+                    "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e);
+         }
+      }
 
-            if ( !rootFile.isDirectory() )
-            {
-                continue;
-            }
+      return compileSources;
+   }
 
-            try
-            {
-                compileSources.addAll( scanner.getIncludedSources( rootFile, null ) );
-            }
-            catch ( InclusionScanException e )
-            {
-                throw new MojoExecutionException(
-                    "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e );
-            }
-        }
+   /**
+    * @param compilerConfiguration
+    * @param compiler
+    * @return <code>true</code> if at least a single source file is newer than it's class file
+    */
+   private boolean isSourceChanged(CompilerConfiguration compilerConfiguration, Compiler compiler)
+           throws CompilerException, MojoExecutionException
+   {
+      Set<File> staleSources
+              = computeStaleSources(compilerConfiguration, compiler, getSourceInclusionScanner(staleMillis));
 
-        return compileSources;
-    }
+      if (getLog().isDebugEnabled())
+      {
+         for (File f : staleSources)
+         {
+            getLog().debug("Stale source detected: " + f.getAbsolutePath());
+         }
+      }
+      return staleSources != null && staleSources.size() > 0;
+   }
 
-    /**
-     * @param compilerConfiguration
-     * @param compiler
-     * @return <code>true</code> if at least a single source file is newer than it's class file
-     */
-    private boolean isSourceChanged( CompilerConfiguration compilerConfiguration, Compiler compiler )
-        throws CompilerException, MojoExecutionException
-    {
-        Set<File> staleSources =
-            computeStaleSources( compilerConfiguration, compiler, getSourceInclusionScanner( staleMillis ) );
+   /**
+    * try to get thread count if a Maven 3 build, using reflection as the plugin must not be maven3 api dependant
+    *
+    * @return number of thread for this build or 1 if not multi-thread build
+    */
+   protected int getRequestThreadCount()
+   {
+      try
+      {
+         Method getRequestMethod = session.getClass().getMethod("getRequest");
+         Object mavenExecutionRequest = getRequestMethod.invoke(this.session);
+         Method getThreadCountMethod = mavenExecutionRequest.getClass().getMethod("getThreadCount");
+         String threadCount = (String) getThreadCountMethod.invoke(mavenExecutionRequest);
+         return Integer.valueOf(threadCount);
+      }
+      catch (Exception e)
+      {
+         getLog().debug("unable to get threadCount for the current build: " + e.getMessage());
+      }
+      return 1;
+   }
 
-        if ( getLog().isDebugEnabled() )
-        {
-            for ( File f : staleSources )
-            {
-                getLog().debug( "Stale source detected: " + f.getAbsolutePath() );
-            }
-        }
-        return staleSources != null && staleSources.size() > 0;
-    }
+   protected Date getBuildStartTime()
+   {
+      try
+      {
+         Method getRequestMethod = session.getClass().getMethod("getRequest");
+         Object mavenExecutionRequest = getRequestMethod.invoke(session);
+         Method getStartTimeMethod = mavenExecutionRequest.getClass().getMethod("getStartTime");
+         Date buildStartTime = (Date) getStartTimeMethod.invoke(mavenExecutionRequest);
+         return buildStartTime;
+      }
+      catch (Exception e)
+      {
+         getLog().debug("unable to get start time for the current build: " + e.getMessage());
+      }
 
+      return new Date();
+   }
 
-    /**
-     * try to get thread count if a Maven 3 build, using reflection as the plugin must not be maven3 api dependant
-     *
-     * @return number of thread for this build or 1 if not multi-thread build
-     */
-    protected int getRequestThreadCount()
-    {
-        try
-        {
-            Method getRequestMethod = session.getClass().getMethod( "getRequest" );
-            Object mavenExecutionRequest = getRequestMethod.invoke( this.session );
-            Method getThreadCountMethod = mavenExecutionRequest.getClass().getMethod( "getThreadCount" );
-            String threadCount = (String) getThreadCountMethod.invoke( mavenExecutionRequest );
-            return Integer.valueOf( threadCount );
-        }
-        catch ( Exception e )
-        {
-            getLog().debug( "unable to get threadCount for the current build: " + e.getMessage() );
-        }
-        return 1;
-    }
+   private String getMemoryValue(String setting)
+   {
+      String value = null;
 
-    protected Date getBuildStartTime()
-    {
-        try
-        {
-            Method getRequestMethod = session.getClass().getMethod( "getRequest" );
-            Object mavenExecutionRequest = getRequestMethod.invoke( session );
-            Method getStartTimeMethod = mavenExecutionRequest.getClass().getMethod( "getStartTime" );
-            Date buildStartTime = (Date) getStartTimeMethod.invoke( mavenExecutionRequest );
-            return buildStartTime;
-        }
-        catch ( Exception e )
-        {
-            getLog().debug( "unable to get start time for the current build: " + e.getMessage() );
-        }
+      // Allow '128' or '128m'
+      if (isDigits(setting))
+      {
+         value = setting + "m";
+      }
+      else if ((isDigits(setting.substring(0, setting.length() - 1))) && (setting.toLowerCase().endsWith(
+              "m")))
+      {
+         value = setting;
+      }
+      return value;
+   }
 
-        return new Date();
-    }
+   //TODO remove the part with ToolchainManager lookup once we depend on
+   //3.0.9 (have it as prerequisite). Define as regular component field then.
+   private Toolchain getToolchain()
+   {
+      Toolchain tc = null;
+      if (toolchainManager != null)
+      {
+         tc = toolchainManager.getToolchainFromBuildContext("jdk", session);
+      }
+      return tc;
+   }
 
+   private boolean isDigits(String string)
+   {
+      for (int i = 0; i < string.length(); i++)
+      {
+         if (!Character.isDigit(string.charAt(i)))
+         {
+            return false;
+         }
+      }
+      return true;
+   }
 
-    private String getMemoryValue( String setting )
-    {
-        String value = null;
+   private Set<File> computeStaleSources(CompilerConfiguration compilerConfiguration, Compiler compiler,
+           SourceInclusionScanner scanner)
+           throws MojoExecutionException, CompilerException
+   {
+      SourceMapping mapping = getSourceMapping(compilerConfiguration, compiler);
 
-        // Allow '128' or '128m'
-        if ( isDigits( setting ) )
-        {
-            value = setting + "m";
-        }
-        else if ( ( isDigits( setting.substring( 0, setting.length() - 1 ) ) ) && ( setting.toLowerCase().endsWith(
-            "m" ) ) )
-        {
-            value = setting;
-        }
-        return value;
-    }
+      File outputDirectory;
+      CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
+      if (outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES)
+      {
+         outputDirectory = buildDirectory;
+      }
+      else
+      {
+         outputDirectory = getOutputDirectory();
+      }
 
-    //TODO remove the part with ToolchainManager lookup once we depend on
-    //3.0.9 (have it as prerequisite). Define as regular component field then.
-    private Toolchain getToolchain()
-    {
-        Toolchain tc = null;
-        if ( toolchainManager != null )
-        {
-            tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
-        }
-        return tc;
-    }
+      scanner.addSourceMapping(mapping);
 
-    private boolean isDigits( String string )
-    {
-        for ( int i = 0; i < string.length(); i++ )
-        {
-            if ( !Character.isDigit( string.charAt( i ) ) )
+      Set<File> staleSources = new HashSet<File>();
+
+      for (String sourceRoot : getCompileSourceRoots())
+      {
+         File rootFile = new File(sourceRoot);
+
+         if (!rootFile.isDirectory())
+         {
+            continue;
+         }
+
+         try
+         {
+            staleSources.addAll(scanner.getIncludedSources(rootFile, outputDirectory));
+         }
+         catch (InclusionScanException e)
+         {
+            throw new MojoExecutionException(
+                    "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e);
+         }
+      }
+
+      return staleSources;
+   }
+
+   private SourceMapping getSourceMapping(CompilerConfiguration compilerConfiguration, Compiler compiler)
+           throws CompilerException, MojoExecutionException
+   {
+      CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
+
+      SourceMapping mapping;
+      if (outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE)
+      {
+         mapping = new SuffixMapping(compiler.getInputFileEnding(compilerConfiguration),
+                 compiler.getOutputFileEnding(compilerConfiguration));
+      }
+      else if (outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES)
+      {
+         mapping = new SingleTargetSourceMapping(compiler.getInputFileEnding(compilerConfiguration),
+                 compiler.getOutputFile(compilerConfiguration));
+
+      }
+      else
+      {
+         throw new MojoExecutionException("Unknown compiler output style: '" + outputStyle + "'.");
+      }
+      return mapping;
+   }
+
+   /**
+    * @todo also in ant plugin. This should be resolved at some point so that it does not need to be calculated continuously - or should the
+    * plugins accept empty source roots as is?
+    */
+   private static List<String> removeEmptyCompileSourceRoots(List<String> compileSourceRootsList)
+   {
+      List<String> newCompileSourceRootsList = new ArrayList<String>();
+      if (compileSourceRootsList != null)
+      {
+         // copy as I may be modifying it
+         for (String srcDir : compileSourceRootsList)
+         {
+            if (!newCompileSourceRootsList.contains(srcDir) && new File(srcDir).exists())
             {
-                return false;
+               newCompileSourceRootsList.add(srcDir);
             }
-        }
-        return true;
-    }
+         }
+      }
+      return newCompileSourceRootsList;
+   }
 
-    private Set<File> computeStaleSources( CompilerConfiguration compilerConfiguration, Compiler compiler,
-                                           SourceInclusionScanner scanner )
-        throws MojoExecutionException, CompilerException
-    {
-        SourceMapping mapping = getSourceMapping( compilerConfiguration, compiler );
+   /**
+    * We just compare the timestamps of all local dependency files (inter-module dependency classpath) and the own generated classes and if
+    * we got a file which is >= the buid-started timestamp, then we catched a file which got changed during this build.
+    *
+    * @return <code>true</code> if at least one single dependency has changed.
+    */
+   protected boolean isDependencyChanged(IncrementalBuildHelper incrementalBuildHelper, Map<File, byte[]> dependencyInfo) throws MojoExecutionException
+   {
+      if (mavenSession == null)
+      {
+         // we just cannot determine it, so don't do anything beside logging
+         getLog().info("Cannot determine build start date, skipping incremental build detection.");
+         return false;
+      }
 
-        File outputDirectory;
-        CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
-        if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
-        {
-            outputDirectory = buildDirectory;
-        }
-        else
-        {
-            outputDirectory = getOutputDirectory();
-        }
+      if (fileExtensions == null || fileExtensions.isEmpty())
+      {
+         fileExtensions = new ArrayList<String>();
+         fileExtensions.add(".class");
+      }
 
-        scanner.addSourceMapping( mapping );
+      Date buildStartTime = getBuildStartTime();
 
-        Set<File> staleSources = new HashSet<File>();
+      final File mojoConfigFile = new File(incrementalBuildHelper.getMojoStatusDirectory(), DEPENDENCY_INFO_FILENAME);
+      if (!mojoConfigFile.exists())
+      {
+         getLog().debug("No file " + DEPENDENCY_INFO_FILENAME + " - assume rebuild.");
+         return true;
+      }
 
-        for ( String sourceRoot : getCompileSourceRoots() )
-        {
-            File rootFile = new File( sourceRoot );
+      Map<File, byte[]> origDependencyInfo;
+      try
+      {
+         FileInputStream fis = new FileInputStream(mojoConfigFile);
+         ObjectInputStream ois = new ObjectInputStream(fis);
+         origDependencyInfo = (Map<File, byte[]>) ois.readObject();
+         ois.close();
+      }
+      catch (FileNotFoundException ex)
+      {
+         getLog().debug("No file " + DEPENDENCY_INFO_FILENAME + " - assume rebuild.", ex);
+         return true;
+      }
+      catch (IOException ex)
+      {
+         getLog().debug("Can't read file " + DEPENDENCY_INFO_FILENAME + " - assume rebuild.", ex);
+         return true;
+      }
+      catch (ClassNotFoundException ex)
+      {
+         getLog().debug("Unexpected exception - assume rebuild.", ex);
+         return true;
+      }
 
-            if ( !rootFile.isDirectory() )
+      for (String classPathElement : getClasspathElements())
+      {
+         File artifactPath = new File(classPathElement);
+         if (artifactPath.isDirectory())
+         {
+            // ProjectArtifacts are artifacts which are available in the local project
+            // that's the only ones we are interested in now.
+            if (hasNewFile(artifactPath, buildStartTime))
             {
-                continue;
+               getLog().debug("New dependency detected: " + artifactPath.getAbsolutePath());
+               return true;
             }
-
-            try
+         }
+         else if (artifactPath.isFile())
+         {
+            // + dependent jar files and class files.
+            final File checksum_file = new File(artifactPath.getAbsolutePath() + ".sha1");
+            byte[] checksum = dependencyInfo.get(checksum_file);
+            if (checksum == null)
             {
-                staleSources.addAll( scanner.getIncludedSources( rootFile, outputDirectory ) );
+               // ignore such dependency.
             }
-            catch ( InclusionScanException e )
+            
+            byte[] origChecksum = origDependencyInfo.get(checksum_file);
+            if (checksum == null)
             {
-                throw new MojoExecutionException(
-                    "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e );
+               // ignore such dependency.
             }
-        }
+            if (origChecksum == null  ||  !Arrays.equals(origChecksum, checksum))
+            {
+               getLog().debug("New dependency detected: " + artifactPath.getAbsolutePath());
+               return true;
+            }
+         }
+      }
 
-        return staleSources;
-    }
+      // obviously there was no new file detected.
+      return false;
+   }
 
-    private SourceMapping getSourceMapping( CompilerConfiguration compilerConfiguration, Compiler compiler )
-        throws CompilerException, MojoExecutionException
-    {
-        CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
+   /**
+    * @param classPathEntry entry to check
+    * @param buildStartTime time build start
+    * @return if any changes occured
+    */
+   private boolean hasNewFile(File classPathEntry, Date buildStartTime)
+   {
+      if (!classPathEntry.exists())
+      {
+         return false;
+      }
 
-        SourceMapping mapping;
-        if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE )
-        {
-            mapping = new SuffixMapping( compiler.getInputFileEnding( compilerConfiguration ),
-                                         compiler.getOutputFileEnding( compilerConfiguration ) );
-        }
-        else if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
-        {
-            mapping = new SingleTargetSourceMapping( compiler.getInputFileEnding( compilerConfiguration ),
-                                                     compiler.getOutputFile( compilerConfiguration ) );
+      if (classPathEntry.isFile())
+      {
+         return classPathEntry.lastModified() >= buildStartTime.getTime() && fileExtensions.contains(
+                 FileUtils.getExtension(classPathEntry.getName()));
+      }
 
-        }
-        else
-        {
-            throw new MojoExecutionException( "Unknown compiler output style: '" + outputStyle + "'." );
-        }
-        return mapping;
-    }
+      File[] children = classPathEntry.listFiles();
 
-    /**
-     * @todo also in ant plugin. This should be resolved at some point so that it does not need to
-     * be calculated continuously - or should the plugins accept empty source roots as is?
-     */
-    private static List<String> removeEmptyCompileSourceRoots( List<String> compileSourceRootsList )
-    {
-        List<String> newCompileSourceRootsList = new ArrayList<String>();
-        if ( compileSourceRootsList != null )
-        {
-            // copy as I may be modifying it
-            for ( String srcDir : compileSourceRootsList )
-            {
-                if ( !newCompileSourceRootsList.contains( srcDir ) && new File( srcDir ).exists() )
-                {
-                    newCompileSourceRootsList.add( srcDir );
-                }
-            }
-        }
-        return newCompileSourceRootsList;
-    }
+      for (File child : children)
+      {
+         if (hasNewFile(child, buildStartTime))
+         {
+            return true;
+         }
+      }
 
-    /**
-     * We just compare the timestamps of all local dependency files (inter-module dependency classpath)
-     * and the own generated classes
-     * and if we got a file which is >= the buid-started timestamp, then we catched a file which got
-     * changed during this build.
-     *
-     * @return <code>true</code> if at least one single dependency has changed.
-     */
-    protected boolean isDependencyChanged()
-    {
-        if ( mavenSession == null )
-        {
-            // we just cannot determine it, so don't do anything beside logging
-            getLog().info( "Cannot determine build start date, skipping incremental build detection." );
-            return false;
-        }
+      return false;
+   }
 
-        if ( fileExtensions == null || fileExtensions.isEmpty() )
-        {
-            fileExtensions = new ArrayList<String>();
-            fileExtensions.add( ".class" );
-        }
+   private Map<File, byte[]> createDependencyInfo()
+   {
+      Map<File, byte[]> dependencyInfo = new HashMap<File, byte[]>();
 
-        Date buildStartTime = getBuildStartTime();
+      for (String classPathElement : getClasspathElements())
+      {
+         File artifactPath = new File(classPathElement);
+         if (artifactPath.isFile())
+         {
+            // + dependent jar files and class files.
+            File checksum_file = new File(artifactPath.getAbsolutePath() + ".sha1");
+            if (!checksum_file.exists())
+            {
+               continue; // jar files without checksum are not supported.
+            }
+            byte[] checksum = new byte[(int) checksum_file.length()];
+            try
+            {
+               FileInputStream fis = new FileInputStream(checksum_file);
+               fis.read(checksum, 0, (int) checksum_file.length());
+               fis.close();
 
-        for ( String classPathElement : getClasspathElements() )
-        {
-            // ProjectArtifacts are artifacts which are available in the local project
-            // that's the only ones we are interested in now.
-            File artifactPath = new File( classPathElement );
-            if ( artifactPath.isDirectory() )
+               dependencyInfo.put(checksum_file, checksum);
+            }
+            catch (FileNotFoundException ex)
             {
-                if ( hasNewFile( artifactPath, buildStartTime ) )
-                {
-                    getLog().debug( "New dependency detected: " + artifactPath.getAbsolutePath() );
-                    return true;
-                }
+               getLog().debug("Can't read md5 file " + checksum_file + " - ignore it.", ex);
             }
-        }
+            catch (IOException ex)
+            {
+               getLog().debug("Can't read md5 file " + checksum_file + " - ignore it.", ex);
+            }
+         }
+      }
 
-        // obviously there was no new file detected.
-        return false;
-    }
+      return dependencyInfo;
+   }
 
-    /**
-     * @param classPathEntry entry to check
-     * @param buildStartTime time build start
-     * @return if any changes occured
-     */
-    private boolean hasNewFile( File classPathEntry, Date buildStartTime )
-    {
-        if ( !classPathEntry.exists() )
-        {
-            return false;
-        }
+   private void keepDependencyInfo(IncrementalBuildHelper incrementalBuildHelper, Map<File, byte[]> dependencyInfo) throws MojoExecutionException
+   {
+      final File mojoConfigFile = new File(incrementalBuildHelper.getMojoStatusDirectory(), DEPENDENCY_INFO_FILENAME);
+      
+      if (dependencyInfo == null)
+      {
+         if (mojoConfigFile.exists())
+         {
+            mojoConfigFile.delete();
+         }
+         return;
+      }
 
-        if ( classPathEntry.isFile() )
-        {
-            return classPathEntry.lastModified() >= buildStartTime.getTime() && fileExtensions.contains(
-                FileUtils.getExtension( classPathEntry.getName() ) );
-        }
-
-        File[] children = classPathEntry.listFiles();
-
-        for ( File child : children )
-        {
-            if ( hasNewFile( child, buildStartTime ) )
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
+      try
+      {
+         FileOutputStream fos = new FileOutputStream(mojoConfigFile);
+         ObjectOutputStream oos = new ObjectOutputStream(fos);
+         oos.writeObject(dependencyInfo);
+         oos.close();
+      }
+      catch (FileNotFoundException ex)
+      {
+         getLog().debug("Unexpected exception", ex);
+      }
+      catch (IOException ex)
+      {
+         getLog().debug("Can't write file " + DEPENDENCY_INFO_FILENAME, ex);
+      }
+   }
 }


> Incremental build does not track inter-module dependencies.
> -----------------------------------------------------------
>
>                 Key: MCOMPILER-278
>                 URL: https://issues.apache.org/jira/browse/MCOMPILER-278
>             Project: Maven Compiler Plugin
>          Issue Type: Bug
>    Affects Versions: 3.1
>            Reporter: Michael Zav'yalov
>
> When useIncrementalCompilation=true the plugin actually assumes that this incremental compilation is supported by compiler itself (I state it because of all source files are always sent to compiler).
> But plugin provides an additional optimization - it can detect that there are no changes at all, so calling compiler can be skipped. It is especially critical for javac that does not support incremental build since 1.3.
> Unfortunately, plugin ignores claspath dependencies that are not directory, i.e. - jars, so when dependent jar is modified (in incompatible way) - our project is not re-compiled.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)