[MJAVADOC-716] Fix stale files detection failing because of the added newline at the end of the file
This closes #144
diff --git a/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java b/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java
index ebea9b1..fb2d928 100644
--- a/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java
+++ b/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java
@@ -5083,11 +5083,11 @@
      */
     private boolean isUpToDate(Commandline cmd) throws MavenReportException {
         try {
-            String curdata = StaleHelper.getStaleData(cmd);
+            List<String> curdata = StaleHelper.getStaleData(cmd);
             Path cacheData = staleDataPath.toPath();
-            String prvdata;
+            List<String> prvdata;
             if (Files.isRegularFile(cacheData)) {
-                prvdata = new String(Files.readAllBytes(cacheData), StandardCharsets.UTF_8);
+                prvdata = Files.lines(cacheData, StandardCharsets.UTF_8).collect(Collectors.toList());
             } else {
                 prvdata = null;
             }
@@ -5099,6 +5099,18 @@
                     getLog().info("No previous run data found, generating javadoc.");
                 } else {
                     getLog().info("Configuration changed, re-generating javadoc.");
+                    if (getLog().isDebugEnabled()) {
+                        List<String> newStrings = new ArrayList<>(curdata);
+                        List<String> remStrings = new ArrayList<>(prvdata);
+                        newStrings.removeAll(prvdata);
+                        remStrings.removeAll(curdata);
+                        if (!remStrings.isEmpty()) {
+                            getLog().debug("     Removed: " + String.join(", ", remStrings));
+                        }
+                        if (!newStrings.isEmpty()) {
+                            getLog().debug("     Added: " + String.join(", ", newStrings));
+                        }
+                    }
                 }
             }
         } catch (IOException e) {
diff --git a/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java b/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java
index 86cc52a..aabe984 100644
--- a/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java
+++ b/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java
@@ -32,7 +32,6 @@
 
 import org.apache.maven.reporting.MavenReportException;
 import org.codehaus.plexus.languages.java.version.JavaVersion;
-import org.codehaus.plexus.util.StringUtils;
 import org.codehaus.plexus.util.cli.Commandline;
 
 /**
@@ -48,7 +47,7 @@
      * @return the stale data
      * @throws MavenReportException if an error occurs
      */
-    public static String getStaleData(Commandline cmd) throws MavenReportException {
+    public static List<String> getStaleData(Commandline cmd) throws MavenReportException {
         try {
             List<String> ignored = new ArrayList<>();
             List<String> options = new ArrayList<>();
@@ -101,7 +100,7 @@
                     state.add(p + " = " + lastmod(p));
                 }
             }
-            return StringUtils.join(state.iterator(), SystemUtils.LINE_SEPARATOR);
+            return state;
         } catch (Exception e) {
             throw new MavenReportException("Unable to compute stale date", e);
         }
@@ -116,9 +115,9 @@
      */
     public static void writeStaleData(Commandline cmd, Path path) throws MavenReportException {
         try {
-            String curdata = getStaleData(cmd);
+            List<String> curdata = getStaleData(cmd);
             Files.createDirectories(path.getParent());
-            Files.write(path, Collections.singleton(curdata), Charset.defaultCharset());
+            Files.write(path, curdata, StandardCharsets.UTF_8);
         } catch (IOException e) {
             throw new MavenReportException("Error checking stale data", e);
         }
diff --git a/src/test/java/org/apache/maven/plugins/javadoc/JavadocJarTest.java b/src/test/java/org/apache/maven/plugins/javadoc/JavadocJarTest.java
index 1e0aa19..5f36edd 100644
--- a/src/test/java/org/apache/maven/plugins/javadoc/JavadocJarTest.java
+++ b/src/test/java/org/apache/maven/plugins/javadoc/JavadocJarTest.java
@@ -19,8 +19,10 @@
 package org.apache.maven.plugins.javadoc;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
@@ -28,6 +30,7 @@
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugin.testing.AbstractMojoTestCase;
 import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
 import org.apache.maven.project.MavenProject;
@@ -191,4 +194,116 @@
                         "META-INF/maven/org.apache.maven.plugins.maven-javadoc-plugin.unit/javadocjar-archive-config/pom.xml",
                         "META-INF/maven/org.apache.maven.plugins.maven-javadoc-plugin.unit/javadocjar-archive-config/pom.properties");
     }
+
+    public void testStale() throws Exception {
+        File testPom = new File(getBasedir(), "src/test/resources/unit/stale-test/stale-test-plugin-config.xml");
+        JavadocJar mojo = lookupMojo(testPom);
+        BufferingLog log = new BufferingLog();
+        mojo.setLog(log);
+
+        Thread.sleep(500);
+
+        new File(getBasedir(), "target/test/unit/stale-test/target/maven-javadoc-plugin-stale-data.txt").delete();
+        mojo.execute();
+        assertThat(log.getMessages()).contains("[INFO] No previous run data found, generating javadoc.");
+
+        Thread.sleep(500);
+
+        log.getMessages().clear();
+        mojo.execute();
+        assertThat(log.getMessages()).contains("[INFO] Skipping javadoc generation, everything is up to date.");
+    }
+
+    private static class BufferingLog implements Log {
+        private final List<String> messages = new ArrayList<>();
+
+        public List<String> getMessages() {
+            return messages;
+        }
+
+        @Override
+        public boolean isDebugEnabled() {
+            return true;
+        }
+
+        @Override
+        public void debug(CharSequence charSequence) {
+            debug(charSequence, null);
+        }
+
+        @Override
+        public void debug(CharSequence charSequence, Throwable throwable) {
+            message("DEBUG", charSequence, throwable);
+        }
+
+        @Override
+        public void debug(Throwable throwable) {
+            debug(null, throwable);
+        }
+
+        @Override
+        public boolean isInfoEnabled() {
+            return true;
+        }
+
+        @Override
+        public void info(CharSequence charSequence) {
+            info(charSequence, null);
+        }
+
+        @Override
+        public void info(CharSequence charSequence, Throwable throwable) {
+            message("INFO", charSequence, throwable);
+        }
+
+        @Override
+        public void info(Throwable throwable) {
+            info(null, throwable);
+        }
+
+        @Override
+        public boolean isWarnEnabled() {
+            return true;
+        }
+
+        @Override
+        public void warn(CharSequence charSequence) {
+            warn(charSequence, null);
+        }
+
+        @Override
+        public void warn(CharSequence charSequence, Throwable throwable) {
+            message("WARN", charSequence, throwable);
+        }
+
+        @Override
+        public void warn(Throwable throwable) {
+            warn(null, throwable);
+        }
+
+        @Override
+        public boolean isErrorEnabled() {
+            return true;
+        }
+
+        @Override
+        public void error(CharSequence charSequence) {
+            error(charSequence, null);
+        }
+
+        @Override
+        public void error(CharSequence charSequence, Throwable throwable) {
+            message("ERROR", charSequence, throwable);
+        }
+
+        @Override
+        public void error(Throwable throwable) {
+            error(null, throwable);
+        }
+
+        private void message(String level, CharSequence message, Throwable throwable) {
+            messages.add("[" + level + "]" + (message != null ? " " + message : "")
+                    + (throwable != null ? " " + throwable : ""));
+        }
+    }
 }
diff --git a/src/test/resources/unit/stale-test/src/main/java/maven/App.java b/src/test/resources/unit/stale-test/src/main/java/maven/App.java
new file mode 100644
index 0000000..35e299c
--- /dev/null
+++ b/src/test/resources/unit/stale-test/src/main/java/maven/App.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package maven;
+
+/**
+ * Hello world!
+ *
+ */
+public class App
+{
+    public static void main( String[] args )
+    {
+        System.out.println( "Hello World!" );
+    }
+}
diff --git a/src/test/resources/unit/stale-test/stale-test-plugin-config.xml b/src/test/resources/unit/stale-test/stale-test-plugin-config.xml
new file mode 100644
index 0000000..699bc08
--- /dev/null
+++ b/src/test/resources/unit/stale-test/stale-test-plugin-config.xml
@@ -0,0 +1,63 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.maven.plugins.maven-javadoc-plugin.unit</groupId>
+  <artifactId>pom-test</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <name>project1</name>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <configuration>
+          <project implementation="org.apache.maven.plugins.javadoc.stubs.JavadocJarArchiveConfigProjectStub"/>
+          <outputDirectory>${basedir}/target/test/unit/stale-test/target/site/apidocs</outputDirectory>
+          <javadocOptionsDir>${basedir}/target/test/unit/stale-test/target/javadoc-bundle-options</javadocOptionsDir>
+          <show>protected</show>
+          <encoding>ISO-8859-1</encoding>
+          <groups/>
+          <tags/>
+          <windowtitle>Maven Pom 1.0-SNAPSHOT API</windowtitle>
+          <quiet>true</quiet>
+          <javadocDirectory>${basedir}/src/test/resources/unit/stale-test/src/java/javadoc</javadocDirectory>
+          <stylesheet>java</stylesheet>
+          <debug>true</debug>
+          <failOnError>true</failOnError>
+          <reactorProjects>
+            <project implementation="org.apache.maven.plugins.javadoc.stubs.AggregateNotInSubFolderTestMavenProjectStub"/>
+          </reactorProjects>
+          <staleDataPath>${basedir}/target/test/unit/stale-test/target/maven-javadoc-plugin-stale-data.txt</staleDataPath>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>