Martin Matejovic b9042c
--- src/main/org/apache/tools/ant/taskdefs/Javac.java.orig	2009/01/29 05:23:52	738761
Martin Matejovic b9042c
+++ src/main/org/apache/tools/ant/taskdefs/Javac.java	2009/02/12 22:35:18	743910
Martin Matejovic b9042c
@@ -20,9 +20,12 @@
Martin Matejovic b9042c
 
Martin Matejovic b9042c
 import java.io.File;
Martin Matejovic b9042c
 
Martin Matejovic b9042c
-import java.util.ArrayList;
Martin Matejovic b9042c
+import java.io.FileOutputStream;
Martin Matejovic b9042c
+import java.io.IOException;
Martin Matejovic b9042c
+import java.io.OutputStream;
Martin Matejovic b9042c
+import java.util.HashMap;
Martin Matejovic b9042c
 import java.util.Iterator;
Martin Matejovic b9042c
-import java.util.List;
Martin Matejovic b9042c
+import java.util.Map;
Martin Matejovic b9042c
 
Martin Matejovic b9042c
 import org.apache.tools.ant.BuildException;
Martin Matejovic b9042c
 import org.apache.tools.ant.DirectoryScanner;
Martin Matejovic b9042c
@@ -32,6 +35,7 @@
Martin Matejovic b9042c
 import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory;
Martin Matejovic b9042c
 import org.apache.tools.ant.types.Path;
Martin Matejovic b9042c
 import org.apache.tools.ant.types.Reference;
Martin Matejovic b9042c
+import org.apache.tools.ant.util.FileUtils;
Martin Matejovic b9042c
 import org.apache.tools.ant.util.GlobPatternMapper;
Martin Matejovic b9042c
 import org.apache.tools.ant.util.JavaEnvUtils;
Martin Matejovic b9042c
 import org.apache.tools.ant.util.SourceFileScanner;
Martin Matejovic b9042c
@@ -86,8 +90,7 @@
Martin Matejovic b9042c
     private static final String CLASSIC = "classic";
Martin Matejovic b9042c
     private static final String EXTJAVAC = "extJavac";
Martin Matejovic b9042c
 
Martin Matejovic b9042c
-    private static final String PACKAGE_INFO_JAVA = "package-info.java";
Martin Matejovic b9042c
-    private static final String PACKAGE_INFO_CLASS = "package-info.class";
Martin Matejovic b9042c
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
Martin Matejovic b9042c
 
Martin Matejovic b9042c
     private Path src;
Martin Matejovic b9042c
     private File destDir;
Martin Matejovic b9042c
@@ -115,6 +118,7 @@
Martin Matejovic b9042c
     protected boolean failOnError = true;
Martin Matejovic b9042c
     protected boolean listFiles = false;
Martin Matejovic b9042c
     protected File[] compileList = new File[0];
Martin Matejovic b9042c
+    private Map/*<String,Long>*/ packageInfos = new HashMap();
Martin Matejovic b9042c
     // CheckStyle:VisibilityModifier ON
Martin Matejovic b9042c
 
Martin Matejovic b9042c
     private String source;
Martin Matejovic b9042c
@@ -124,7 +128,6 @@
Martin Matejovic b9042c
     private String errorProperty;
Martin Matejovic b9042c
     private boolean taskSuccess = true; // assume the best
Martin Matejovic b9042c
     private boolean includeDestClasses = true;
Martin Matejovic b9042c
-    private List    updateDirList = new ArrayList();
Martin Matejovic b9042c
 
Martin Matejovic b9042c
     /**
Martin Matejovic b9042c
      * Javac task for compilation of Java files.
Martin Matejovic b9042c
@@ -892,6 +895,7 @@
Martin Matejovic b9042c
      */
Martin Matejovic b9042c
     protected void resetFileLists() {
Martin Matejovic b9042c
         compileList = new File[0];
Martin Matejovic b9042c
+        packageInfos = new HashMap();
Martin Matejovic b9042c
     }
Martin Matejovic b9042c
 
Martin Matejovic b9042c
     /**
Martin Matejovic b9042c
@@ -909,8 +913,8 @@
Martin Matejovic b9042c
         SourceFileScanner sfs = new SourceFileScanner(this);
Martin Matejovic b9042c
         File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m);
Martin Matejovic b9042c
 
Martin Matejovic b9042c
-        newFiles = removePackageInfoFiles(newFiles, srcDir, destDir);
Martin Matejovic b9042c
         if (newFiles.length > 0) {
Martin Matejovic b9042c
+            lookForPackageInfos(srcDir, newFiles);
Martin Matejovic b9042c
             File[] newCompileList
Martin Matejovic b9042c
                 = new File[compileList.length + newFiles.length];
Martin Matejovic b9042c
             System.arraycopy(compileList, 0, newCompileList, 0,
Martin Matejovic b9042c
@@ -1063,10 +1067,12 @@
Martin Matejovic b9042c
 
Martin Matejovic b9042c
             // finally, lets execute the compiler!!
Martin Matejovic b9042c
             if (adapter.execute()) {
Martin Matejovic b9042c
-                // Success - check
Martin Matejovic b9042c
-                for (Iterator i = updateDirList.iterator(); i.hasNext();) {
Martin Matejovic b9042c
-                    File file = (File) i.next();
Martin Matejovic b9042c
-                    file.setLastModified(System.currentTimeMillis());
Martin Matejovic b9042c
+                // Success
Martin Matejovic b9042c
+                try {
Martin Matejovic b9042c
+                    generateMissingPackageInfoClasses();
Martin Matejovic b9042c
+                } catch (IOException x) {
Martin Matejovic b9042c
+                    // Should this be made a nonfatal warning?
Martin Matejovic b9042c
+                    throw new BuildException(x, getLocation());
Martin Matejovic b9042c
                 }
Martin Matejovic b9042c
             } else {
Martin Matejovic b9042c
                 // Fail path
Martin Matejovic b9042c
@@ -1100,75 +1106,74 @@
Martin Matejovic b9042c
         }
Martin Matejovic b9042c
     }
Martin Matejovic b9042c
 
Martin Matejovic b9042c
-    // ----------------------------------------------------------------
Martin Matejovic b9042c
-    //  Code to remove package-info.java files from compilation
Martin Matejovic b9042c
-    //  Since Ant 1.7.1.
Martin Matejovic b9042c
-    //
Martin Matejovic b9042c
-    //    package-info.java are files that contain package level
Martin Matejovic b9042c
-    //    annotations. They may or may not have corresponding .class
Martin Matejovic b9042c
-    //    files.
Martin Matejovic b9042c
-    //
Martin Matejovic b9042c
-    //    The following code uses the algorithm:
Martin Matejovic b9042c
-    //     * on entry we have the files that need to be compiled
Martin Matejovic b9042c
-    //     * if the filename is not package-info.java compile it
Martin Matejovic b9042c
-    //     * if a corresponding .class file exists compile it
Martin Matejovic b9042c
-    //     * if the corresponding class directory does not exist compile it
Martin Matejovic b9042c
-    //     * if the corresponding directory lastmodifed time is
Martin Matejovic b9042c
-    //       older than the java file, compile the java file and
Martin Matejovic b9042c
-    //       touch the corresponding class directory (on successful
Martin Matejovic b9042c
-    //       compilation).
Martin Matejovic b9042c
-    //
Martin Matejovic b9042c
-    // ----------------------------------------------------------------
Martin Matejovic b9042c
-    private File[] removePackageInfoFiles(
Martin Matejovic b9042c
-        File[] newFiles, File srcDir, File destDir) {
Martin Matejovic b9042c
-        if (!hasPackageInfo(newFiles)) {
Martin Matejovic b9042c
-            return newFiles;
Martin Matejovic b9042c
-        }
Martin Matejovic b9042c
-        List ret = new ArrayList();
Martin Matejovic b9042c
-        for (int i = 0; i < newFiles.length; ++i) {
Martin Matejovic b9042c
-            if (needsCompilePackageFile(newFiles[i], srcDir, destDir)) {
Martin Matejovic b9042c
-                ret.add(newFiles[i]);
Martin Matejovic b9042c
+    private void lookForPackageInfos(File srcDir, File[] newFiles) {
Martin Matejovic b9042c
+        for (int i = 0; i < newFiles.length; i++) {
Martin Matejovic b9042c
+            File f = newFiles[i];
Martin Matejovic b9042c
+            if (!f.getName().equals("package-info.java")) {
Martin Matejovic b9042c
+                continue;
Martin Matejovic b9042c
             }
Martin Matejovic b9042c
-        }
Martin Matejovic b9042c
-        return (File[]) ret.toArray(new File[0]);
Martin Matejovic b9042c
-    }
Martin Matejovic b9042c
-
Martin Matejovic b9042c
-    private boolean hasPackageInfo(File[] newFiles) {
Martin Matejovic b9042c
-        for (int i = 0; i < newFiles.length; ++i) {
Martin Matejovic b9042c
-            if (newFiles[i].getName().equals(PACKAGE_INFO_JAVA)) {
Martin Matejovic b9042c
-                return true;
Martin Matejovic b9042c
+            String path = FILE_UTILS.removeLeadingPath(srcDir, f).
Martin Matejovic b9042c
+                    replace(File.separatorChar, '/');
Martin Matejovic b9042c
+            String suffix = "/package-info.java";
Martin Matejovic b9042c
+            if (!path.endsWith(suffix)) {
Martin Matejovic b9042c
+                continue;
Martin Matejovic b9042c
             }
Martin Matejovic b9042c
+            String pkg = path.substring(0, path.length() - suffix.length());
Martin Matejovic b9042c
+            packageInfos.put(pkg, Long.valueOf(f.lastModified()));
Martin Matejovic b9042c
         }
Martin Matejovic b9042c
-        return false;
Martin Matejovic b9042c
     }
Martin Matejovic b9042c
 
Martin Matejovic b9042c
-    private boolean needsCompilePackageFile(
Martin Matejovic b9042c
-        File file, File srcDir, File destDir) {
Martin Matejovic b9042c
-        if (!file.getName().equals(PACKAGE_INFO_JAVA)) {
Martin Matejovic b9042c
-            return true;
Martin Matejovic b9042c
-        }
Martin Matejovic b9042c
-        // return true if destDir contains the file
Martin Matejovic b9042c
-        String rel = relativePath(srcDir, file);
Martin Matejovic b9042c
-        File destFile = new File(destDir, rel);
Martin Matejovic b9042c
-        File parent = destFile.getParentFile();
Martin Matejovic b9042c
-        destFile = new File(parent, PACKAGE_INFO_CLASS);
Martin Matejovic b9042c
-        File sourceFile = new File(srcDir, rel);
Martin Matejovic b9042c
-        if (destFile.exists()) {
Martin Matejovic b9042c
-            return true;
Martin Matejovic b9042c
-        }
Martin Matejovic b9042c
-        // Dest file does not exist
Martin Matejovic b9042c
-        // Compile Source file if sourceFile is newer that destDir
Martin Matejovic b9042c
-        // TODO - use fs
Martin Matejovic b9042c
-        if (sourceFile.lastModified()
Martin Matejovic b9042c
-            > destFile.getParentFile().lastModified()) {
Martin Matejovic b9042c
-            updateDirList.add(destFile.getParentFile());
Martin Matejovic b9042c
-            return true;
Martin Matejovic b9042c
+    /**
Martin Matejovic b9042c
+     * Ensure that every {@code package-info.java} produced a {@code package-info.class}.
Martin Matejovic b9042c
+     * Otherwise this task's up-to-date tracking mechanisms do not work.
Martin Matejovic b9042c
+     * @see Bug #43114
Martin Matejovic b9042c
+     */
Martin Matejovic b9042c
+    private void generateMissingPackageInfoClasses() throws IOException {
Martin Matejovic b9042c
+        for (Iterator i = packageInfos.entrySet().iterator(); i.hasNext(); ) {
Martin Matejovic b9042c
+            Map.Entry entry = (Map.Entry) i.next();
Martin Matejovic b9042c
+            String pkg = (String) entry.getKey();
Martin Matejovic b9042c
+            Long sourceLastMod = (Long) entry.getValue();
Martin Matejovic b9042c
+            File pkgBinDir = new File(destDir, pkg.replace('/', File.separatorChar));
Martin Matejovic b9042c
+            pkgBinDir.mkdirs();
Martin Matejovic b9042c
+            File pkgInfoClass = new File(pkgBinDir, "package-info.class");
Martin Matejovic b9042c
+            if (pkgInfoClass.isFile() && pkgInfoClass.lastModified() >= sourceLastMod.longValue()) {
Martin Matejovic b9042c
+                continue;
Martin Matejovic b9042c
+            }
Martin Matejovic b9042c
+            log("Creating empty " + pkgInfoClass);
Martin Matejovic b9042c
+            OutputStream os = new FileOutputStream(pkgInfoClass);
Martin Matejovic b9042c
+            try {
Martin Matejovic b9042c
+                os.write(PACKAGE_INFO_CLASS_HEADER);
Martin Matejovic b9042c
+                byte[] name = pkg.getBytes("UTF-8");
Martin Matejovic b9042c
+                int length = name.length + /* "/package-info" */ 13;
Martin Matejovic b9042c
+                os.write((byte) length / 256);
Martin Matejovic b9042c
+                os.write((byte) length % 256);
Martin Matejovic b9042c
+                os.write(name);
Martin Matejovic b9042c
+                os.write(PACKAGE_INFO_CLASS_FOOTER);
Martin Matejovic b9042c
+            } finally {
Martin Matejovic b9042c
+                os.close();
Martin Matejovic b9042c
+            }
Martin Matejovic b9042c
         }
Martin Matejovic b9042c
-        return false;
Martin Matejovic b9042c
     }
Martin Matejovic b9042c
 
Martin Matejovic b9042c
     private String relativePath(File src, File file) {
Martin Matejovic b9042c
         return file.getAbsolutePath().substring(
Martin Matejovic b9042c
             src.getAbsolutePath().length() + 1);
Martin Matejovic b9042c
     }
Martin Matejovic b9042c
+
Martin Matejovic b9042c
+    private static final byte[] PACKAGE_INFO_CLASS_HEADER = {
Martin Matejovic b9042c
+        (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, 0x00, 0x00, 0x00,
Martin Matejovic b9042c
+        0x31, 0x00, 0x07, 0x07, 0x00, 0x05, 0x07, 0x00, 0x06, 0x01, 0x00, 0x0a,
Martin Matejovic b9042c
+        0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x00,
Martin Matejovic b9042c
+        0x11, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
Martin Matejovic b9042c
+        0x6f, 0x2e, 0x6a, 0x61, 0x76, 0x61, 0x01
Martin Matejovic b9042c
+    };
Martin Matejovic b9042c
+    private static final byte[] PACKAGE_INFO_CLASS_FOOTER = {
Martin Matejovic b9042c
+        0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
Martin Matejovic b9042c
+        0x6f, 0x01, 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e,
Martin Matejovic b9042c
+        0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x02, 0x00, 0x00, 0x01,
Martin Matejovic b9042c
+        0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
Martin Matejovic b9042c
+        0x00, 0x00, 0x00, 0x02, 0x00, 0x04
Martin Matejovic b9042c
+    };
Martin Matejovic b9042c
+
Martin Matejovic b9042c
 }
Martin Matejovic b9042c
+