Browse Source

#43114: ensuring that package-info.class is created/touched when package-info.java is compiled.

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@743910 13f79535-47bb-0310-9956-ffa450edef68
master
Jesse N. Glick 16 years ago
parent
commit
bba4624fac
2 changed files with 73 additions and 71 deletions
  1. +3
    -0
      WHATSNEW
  2. +70
    -71
      src/main/org/apache/tools/ant/taskdefs/Javac.java

+ 3
- 0
WHATSNEW View File

@@ -137,6 +137,9 @@ Changes that could break older environments:

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.



+ 70
- 71
src/main/org/apache/tools/ant/taskdefs/Javac.java View File

@@ -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 @@ public class Javac extends MatchingTask {
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 @@ public class Javac extends MatchingTask {
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 @@ public class Javac extends MatchingTask {
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 @@ public class Javac extends MatchingTask {
*/
protected void resetFileLists() {
compileList = new File[0];
packageInfos = new HashMap();
}

/**
@@ -915,8 +915,8 @@ public class Javac extends MatchingTask {
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 @@ public class Javac extends MatchingTask {

// 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 @@ public class Javac extends MatchingTask {
}
}

// ----------------------------------------------------------------
// 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
};

}

Loading…
Cancel
Save