You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by jg...@apache.org on 2009/02/12 23:35:18 UTC

svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Author: jglick
Date: Thu Feb 12 22:35:18 2009
New Revision: 743910

URL: http://svn.apache.org/viewvc?rev=743910&view=rev
Log:
#43114: ensuring that package-info.class is created/touched when package-info.java is compiled.

Modified:
    ant/core/trunk/WHATSNEW
    ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java

Modified: ant/core/trunk/WHATSNEW
URL: http://svn.apache.org/viewvc/ant/core/trunk/WHATSNEW?rev=743910&r1=743909&r2=743910&view=diff
==============================================================================
--- ant/core/trunk/WHATSNEW (original)
+++ ant/core/trunk/WHATSNEW Thu Feb 12 22:35:18 2009
@@ -137,6 +137,9 @@
 
 Fixed bugs:
 -----------
+
+ * Better handling of package-info.class. Bugzilla Report 43114.
+
  * RPM task needed an inserted space between the define and the value.
    bugzilla Report 46659.
 

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



Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Peter Reilly <pe...@gmail.com>.
The version is 1.5 - and it is not meant to be replaced!

Peter

On Fri, Feb 13, 2009 at 3:04 PM, Dominique Devienne <dd...@gmail.com> wrote:
> On Thu, Feb 12, 2009 at 4:35 PM,  <jg...@apache.org> wrote:
>> +    private static final byte[] PACKAGE_INFO_CLASS_HEADER = {
>> +        (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, 0x00, 0x00, 0x00,
>> +        0x31, 0x00, 0x07, 0x07, 0x00, 0x05, 0x07, 0x00, 0x06, 0x01, 0x00, 0x0a,
>> +        0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x00,
>> +        0x11, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
>> +        0x6f, 0x2e, 0x6a, 0x61, 0x76, 0x61, 0x01
>> +    };
>> +    private static final byte[] PACKAGE_INFO_CLASS_FOOTER = {
>> +        0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
>> +        0x6f, 0x01, 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e,
>> +        0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x02, 0x00, 0x00, 0x01,
>> +        0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
>> +        0x00, 0x00, 0x00, 0x02, 0x00, 0x04
>> +    };
>
> What Java version is this fake class in?
>
> I suppose it doesn't matter much, as it's meant to be replaced, right?
>
> Just curuous. --DD
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
> For additional commands, e-mail: dev-help@ant.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Dominique Devienne <dd...@gmail.com>.
On Thu, Feb 12, 2009 at 4:35 PM,  <jg...@apache.org> wrote:
> +    private static final byte[] PACKAGE_INFO_CLASS_HEADER = {
> +        (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, 0x00, 0x00, 0x00,
> +        0x31, 0x00, 0x07, 0x07, 0x00, 0x05, 0x07, 0x00, 0x06, 0x01, 0x00, 0x0a,
> +        0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x00,
> +        0x11, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
> +        0x6f, 0x2e, 0x6a, 0x61, 0x76, 0x61, 0x01
> +    };
> +    private static final byte[] PACKAGE_INFO_CLASS_FOOTER = {
> +        0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
> +        0x6f, 0x01, 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e,
> +        0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x02, 0x00, 0x00, 0x01,
> +        0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
> +        0x00, 0x00, 0x00, 0x02, 0x00, 0x04
> +    };

What Java version is this fake class in?

I suppose it doesn't matter much, as it's meant to be replaced, right?

Just curuous. --DD

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Stefan Bodewig <bo...@apache.org>.
On 2009-02-18, Peter Reilly <pe...@gmail.com> wrote:

> Perhaps we should check the "target" attribute - but this is very much
> an edge case.

Indeed, we may as well ignore it.

Stefan

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Peter Reilly <pe...@gmail.com>.
Perhaps we should check the "target" attribute - but this is very much
an edge case.

Peter


On Wed, Feb 18, 2009 at 4:32 PM, Stefan Bodewig <bo...@apache.org> wrote:
> On 2009-02-18, Jesse Glick <je...@sun.com> wrote:
>
>> Stefan Bodewig wrote:
>>>> this should be the equivalent of compiling a
>>>> package-info.java containing only SOURCE annotations using JDK 5.
>
>>> Do you know whether a Java 1.4 VM will even try to load the class
>>> file under any circumstances (other than some explicit reflection
>>> invocations)?
>
>> You cannot use package-info.java with JDK 1.4 to begin with.
>
> I know that.  I was wondering whether there might be a situation where
> JDK 1.4 would try to load the class file even though it shouldn't.
>
> Stefan
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
> For additional commands, e-mail: dev-help@ant.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Stefan Bodewig <bo...@apache.org>.
On 2009-02-20, Jesse Glick <je...@sun.com> wrote:

> Stefan Bodewig wrote:
>>>> Do you know whether a Java 1.4 VM will even try to load the class
>>>> file under any circumstances (other than some explicit reflection
>>>> invocations)?

>>> You cannot use package-info.java with JDK 1.4 to begin with.

>> I know that.  I was wondering whether there might be a situation where
>> JDK 1.4 would try to load the class file even though it shouldn't.

> As far as I know JDK 1.4 would never try to load a package-info.class
> even if you called Package.getPackage, since this file was newly
> defined in JDK 5.

Thanks.

> So I am still puzzled by the question.

Given that I'm still mostly in JDK 1.4 land when I do Java at all, I
don't have too much experience with annotations - and no idea about
package level annotations at all.

> I guess we can ignore it.

Yes, please do.

Stefan

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Jesse Glick <je...@sun.com>.
Stefan Bodewig wrote:
>>> Do you know whether a Java 1.4 VM will even try to load the class
>>> file under any circumstances (other than some explicit reflection
>>> invocations)?
> 
>> You cannot use package-info.java with JDK 1.4 to begin with.
> 
> I know that.  I was wondering whether there might be a situation where
> JDK 1.4 would try to load the class file even though it shouldn't.

As far as I know JDK 1.4 would never try to load a package-info.class even if you called Package.getPackage, since this file was newly defined in JDK 5. I suppose if for 
some reason you wrote

   Class.forName("some.pkg.package-info");

in JDK 1.4 then you would get the UnsupportedClassVersionError you deserve... but this would be true of any class in the same codebase, since they would all be using the 
JDK 5 bytecode format. (If you had a package-info.java, then you must have been compiling with at least -source 5, therefore at least -target 5 as well.) So I am still 
puzzled by the question. I guess we can ignore it.


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Stefan Bodewig <bo...@apache.org>.
On 2009-02-18, Jesse Glick <je...@sun.com> wrote:

> Stefan Bodewig wrote:
>>> this should be the equivalent of compiling a
>>> package-info.java containing only SOURCE annotations using JDK 5.

>> Do you know whether a Java 1.4 VM will even try to load the class
>> file under any circumstances (other than some explicit reflection
>> invocations)?

> You cannot use package-info.java with JDK 1.4 to begin with.

I know that.  I was wondering whether there might be a situation where
JDK 1.4 would try to load the class file even though it shouldn't.

Stefan

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Jesse Glick <je...@sun.com>.
Stefan Bodewig wrote:
>> this should be the equivalent of compiling a
>> package-info.java containing only SOURCE annotations using JDK 5.
> 
> Do you know whether a Java 1.4 VM will even try to load the class
> file under any circumstances (other than some explicit reflection
> invocations)?

You cannot use package-info.java with JDK 1.4 to begin with.

> don't the descriptions in bugzilla
> provide enough information to write AntUnit tests?

Probably. I was more talking about some as yet undescribed setups which we would not know to write tests for.


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Stefan Bodewig <bo...@apache.org>.
On 2009-02-13, Jesse Glick <je...@sun.com> wrote:

> Stefan Bodewig wrote:
>>>>            if (!f.getName().equals("package-info.java")) {
>>>>                continue;

>> should that test better be case-insensitive?

> Should it? I don't know.

The rest of javac's uptodate checks is case-sensitive, so we may
better leave it that way.  Sorry for the confusion.

> To Dominique - yes this should be the equivalent of compiling a
> package-info.java containing only SOURCE annotations using JDK 5.

Do you know whether a Java 1.4 VM will even try to load the class
file under any circumstances (other than some explicit reflection
invocations)?

> It would be good to get feedback on whether this trick works for the
> cases users have brought up and introduces no problems.

At the risk of sounding strange: don't the descriptions in bugzilla
provide enough information to write AntUnit tests?

Stefan

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Jesse Glick <je...@sun.com>.
Stefan Bodewig wrote:
>>>            if (!f.getName().equals("package-info.java")) {
>>>                continue;
> 
> should that test better be case-insensitive?

Should it? I don't know. It seemed to work on XP as is. Would someone really specifically create a file PACKAGE-INFO.JAVA? Windows does at least preserve case, after all.

To Dominique - yes this should be the equivalent of compiling a package-info.java containing only SOURCE annotations using JDK 5. (JDK 5 javac creates it as an 
ACC_INTERFACE, by the way. JDK 6 adds ACC_ABSTRACT, and -target 6 besides using the newer bytecode version further adds ACC_SYNTHETIC, but it is otherwise the same.) The 
bytecode is loaded at runtime in case some code requests the java.lang.Package.

It would be good to get feedback on whether this trick works for the cases users have brought up and introduces no problems. The only drawback I know about is the 
creation of an extra class file, though it is small and this only happens for a package-info.java with no annotations, which is probably a very small proportion of 
realistic source bases.

Arguably javac itself should be changed to always generate package-info.class, which would address the issue not just for Ant but also for Maven and any other tools which 
invoke javac for incremental builds. There is no apparent "correct" behavior - JLS 3 talks briefly about package-info.java but the proposed changes to the JVM spec ch. 4 

for JDK 5 do not seem to mention package-info.class at all.

If the package name includes national characters, these are parsed essentially according to what File.absolutePath reports. It would be possible to parse 
package-info.java using the declared encoding, but the placing of the package-info.class to be written would still be at the mercy of the filesystem, so this would not 
seem to be an improvement. javac itself seems to use the declared encoding only for parsing the text contents of files, still relying on the filesystem to locate and 
store files with possibly non-ASCII paths. For a Unicode-safe environment (such as Linux with the normal ext3 & LC_ALL=UTF-8) this should not be an issue.


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Stefan Bodewig <bo...@apache.org>.
good idea!

On 2009-02-12, <jg...@apache.org> wrote:

>>    private void lookForPackageInfos(File srcDir, File[] newFiles) {
>>        for (int i = 0; i < newFiles.length; i++) {
>>            File f = newFiles[i];
>>            if (!f.getName().equals("package-info.java")) {
>>                continue;

should that test better be case-insensitive?

Stefan

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Re: svn commit: r743910 - in /ant/core/trunk: WHATSNEW src/main/org/apache/tools/ant/taskdefs/Javac.java

Posted by Peter Reilly <pe...@gmail.com>.
Neat,
that is a a brilliant solution!

Peter


On Thu, Feb 12, 2009 at 10:35 PM,  <jg...@apache.org> wrote:
> Author: jglick
> Date: Thu Feb 12 22:35:18 2009
> New Revision: 743910
>
> URL: http://svn.apache.org/viewvc?rev=743910&view=rev
> Log:
> #43114: ensuring that package-info.class is created/touched when package-info.java is compiled.
>
> Modified:
>    ant/core/trunk/WHATSNEW
>    ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java
>
> Modified: ant/core/trunk/WHATSNEW
> URL: http://svn.apache.org/viewvc/ant/core/trunk/WHATSNEW?rev=743910&r1=743909&r2=743910&view=diff
> ==============================================================================
> --- ant/core/trunk/WHATSNEW (original)
> +++ ant/core/trunk/WHATSNEW Thu Feb 12 22:35:18 2009
> @@ -137,6 +137,9 @@
>
>  Fixed bugs:
>  -----------
> +
> + * Better handling of package-info.class. Bugzilla Report 43114.
> +
>  * RPM task needed an inserted space between the define and the value.
>    bugzilla Report 46659.
>
>
> Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java
> URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java?rev=743910&r1=743909&r2=743910&view=diff
> ==============================================================================
> --- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java (original)
> +++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java Thu Feb 12 22:35:18 2009
> @@ -19,10 +19,12 @@
>  package org.apache.tools.ant.taskdefs;
>
>  import java.io.File;
> -
> -import java.util.ArrayList;
> +import java.io.FileOutputStream;
> +import java.io.IOException;
> +import java.io.OutputStream;
> +import java.util.HashMap;
>  import java.util.Iterator;
> -import java.util.List;
> +import java.util.Map;
>
>  import org.apache.tools.ant.BuildException;
>  import org.apache.tools.ant.DirectoryScanner;
> @@ -87,9 +89,6 @@
>     private static final String CLASSIC = "classic";
>     private static final String EXTJAVAC = "extJavac";
>
> -    private static final String PACKAGE_INFO_JAVA = "package-info.java";
> -    private static final String PACKAGE_INFO_CLASS = "package-info.class";
> -
>     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
>
>     private Path src;
> @@ -118,6 +117,7 @@
>     protected boolean failOnError = true;
>     protected boolean listFiles = false;
>     protected File[] compileList = new File[0];
> +    private Map/*<String,Long>*/ packageInfos = new HashMap();
>     // CheckStyle:VisibilityModifier ON
>
>     private String source;
> @@ -127,7 +127,6 @@
>     private String errorProperty;
>     private boolean taskSuccess = true; // assume the best
>     private boolean includeDestClasses = true;
> -    private List    updateDirList = new ArrayList();
>
>     /**
>      * Javac task for compilation of Java files.
> @@ -898,6 +897,7 @@
>      */
>     protected void resetFileLists() {
>         compileList = new File[0];
> +        packageInfos = new HashMap();
>     }
>
>     /**
> @@ -915,8 +915,8 @@
>         SourceFileScanner sfs = new SourceFileScanner(this);
>         File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m);
>
> -        newFiles = removePackageInfoFiles(newFiles, srcDir, destDir);
>         if (newFiles.length > 0) {
> +            lookForPackageInfos(srcDir, newFiles);
>             File[] newCompileList
>                 = new File[compileList.length + newFiles.length];
>             System.arraycopy(compileList, 0, newCompileList, 0,
> @@ -1069,10 +1069,12 @@
>
>             // finally, lets execute the compiler!!
>             if (adapter.execute()) {
> -                // Success - check
> -                for (Iterator i = updateDirList.iterator(); i.hasNext();) {
> -                    File file = (File) i.next();
> -                    file.setLastModified(System.currentTimeMillis());
> +                // Success
> +                try {
> +                    generateMissingPackageInfoClasses();
> +                } catch (IOException x) {
> +                    // Should this be made a nonfatal warning?
> +                    throw new BuildException(x, getLocation());
>                 }
>             } else {
>                 // Fail path
> @@ -1106,71 +1108,68 @@
>         }
>     }
>
> -    // ----------------------------------------------------------------
> -    //  Code to remove package-info.java files from compilation
> -    //  Since Ant 1.7.1.
> -    //
> -    //    package-info.java are files that contain package level
> -    //    annotations. They may or may not have corresponding .class
> -    //    files.
> -    //
> -    //    The following code uses the algorithm:
> -    //     * on entry we have the files that need to be compiled
> -    //     * if the filename is not package-info.java compile it
> -    //     * if a corresponding .class file exists compile it
> -    //     * if the corresponding class directory does not exist compile it
> -    //     * if the corresponding directory lastmodifed time is
> -    //       older than the java file, compile the java file and
> -    //       touch the corresponding class directory (on successful
> -    //       compilation).
> -    //
> -    // ----------------------------------------------------------------
> -    private File[] removePackageInfoFiles(
> -        File[] newFiles, File srcDir, File destDir) {
> -        if (!hasPackageInfo(newFiles)) {
> -            return newFiles;
> -        }
> -        List ret = new ArrayList();
> -        for (int i = 0; i < newFiles.length; ++i) {
> -            if (needsCompilePackageFile(newFiles[i], srcDir, destDir)) {
> -                ret.add(newFiles[i]);
> +    private void lookForPackageInfos(File srcDir, File[] newFiles) {
> +        for (int i = 0; i < newFiles.length; i++) {
> +            File f = newFiles[i];
> +            if (!f.getName().equals("package-info.java")) {
> +                continue;
>             }
> -        }
> -        return (File[]) ret.toArray(new File[0]);
> -    }
> -
> -    private boolean hasPackageInfo(File[] newFiles) {
> -        for (int i = 0; i < newFiles.length; ++i) {
> -            if (newFiles[i].getName().equals(PACKAGE_INFO_JAVA)) {
> -                return true;
> +            String path = FILE_UTILS.removeLeadingPath(srcDir, f).
> +                    replace(File.separatorChar, '/');
> +            String suffix = "/package-info.java";
> +            if (!path.endsWith(suffix)) {
> +                log("anomalous package-info.java path: " + path, Project.MSG_WARN);
> +                continue;
>             }
> +            String pkg = path.substring(0, path.length() - suffix.length());
> +            packageInfos.put(pkg, Long.valueOf(f.lastModified()));
>         }
> -        return false;
>     }
>
> -    private boolean needsCompilePackageFile(
> -        File file, File srcDir, File destDir) {
> -        if (!file.getName().equals(PACKAGE_INFO_JAVA)) {
> -            return true;
> -        }
> -        // return true if destDir contains the file
> -        String rel = FILE_UTILS.removeLeadingPath(srcDir, file);
> -        File destFile = new File(destDir, rel);
> -        File parent = destFile.getParentFile();
> -        destFile = new File(parent, PACKAGE_INFO_CLASS);
> -        File sourceFile = new File(srcDir, rel);
> -        if (destFile.exists()) {
> -            return true;
> -        }
> -        // Dest file does not exist
> -        // Compile Source file if sourceFile is newer that destDir
> -        // TODO - use fs
> -        if (sourceFile.lastModified()
> -            > destFile.getParentFile().lastModified()) {
> -            updateDirList.add(destFile.getParentFile());
> -            return true;
> +    /**
> +     * Ensure that every {@code package-info.java} produced a {@code package-info.class}.
> +     * Otherwise this task's up-to-date tracking mechanisms do not work.
> +     * @see <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=43114">Bug #43114</a>
> +     */
> +    private void generateMissingPackageInfoClasses() throws IOException {
> +        for (Iterator i = packageInfos.entrySet().iterator(); i.hasNext(); ) {
> +            Map.Entry entry = (Map.Entry) i.next();
> +            String pkg = (String) entry.getKey();
> +            Long sourceLastMod = (Long) entry.getValue();
> +            File pkgBinDir = new File(destDir, pkg.replace('/', File.separatorChar));
> +            pkgBinDir.mkdirs();
> +            File pkgInfoClass = new File(pkgBinDir, "package-info.class");
> +            if (pkgInfoClass.isFile() && pkgInfoClass.lastModified() >= sourceLastMod.longValue()) {
> +                continue;
> +            }
> +            log("Creating empty " + pkgInfoClass);
> +            OutputStream os = new FileOutputStream(pkgInfoClass);
> +            try {
> +                os.write(PACKAGE_INFO_CLASS_HEADER);
> +                byte[] name = pkg.getBytes("UTF-8");
> +                int length = name.length + /* "/package-info" */ 13;
> +                os.write((byte) length / 256);
> +                os.write((byte) length % 256);
> +                os.write(name);
> +                os.write(PACKAGE_INFO_CLASS_FOOTER);
> +            } finally {
> +                os.close();
> +            }
>         }
> -        return false;
>     }
> +    private static final byte[] PACKAGE_INFO_CLASS_HEADER = {
> +        (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, 0x00, 0x00, 0x00,
> +        0x31, 0x00, 0x07, 0x07, 0x00, 0x05, 0x07, 0x00, 0x06, 0x01, 0x00, 0x0a,
> +        0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x00,
> +        0x11, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
> +        0x6f, 0x2e, 0x6a, 0x61, 0x76, 0x61, 0x01
> +    };
> +    private static final byte[] PACKAGE_INFO_CLASS_FOOTER = {
> +        0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
> +        0x6f, 0x01, 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e,
> +        0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x02, 0x00, 0x00, 0x01,
> +        0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
> +        0x00, 0x00, 0x00, 0x02, 0x00, 0x04
> +    };
>
>  }
>
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org