1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
Backported changeset ensuring that package-info.class is
created/touched when package-info.java is compiled.
Originally derived from these changesets:
r743910 #43114: ensuring that package-info.class is created/touched
when package-info.java is compiled.
r744132 JDK 1.4 - unfortunately
svn diff -r 738761:744132 http://svn.apache.org/repos/asf/ant/core/\
trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java
2009-03-15 John W. Eckhart
2009-03-17 Martin von Gagern
References:
https://bugs.gentoo.org/262511
https://jira.jboss.org/jira/browse/JBSEAM-3386
https://issues.apache.org/bugzilla/show_bug.cgi?id=43114
--- apache-ant-1.7.1.orig/src/main/org/apache/tools/ant/taskdefs/Javac.java
+++ apache-ant-1.7.1/src/main/org/apache/tools/ant/taskdefs/Javac.java
@@ -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;
@@ -86,9 +88,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 Path src;
private File destDir;
private Path compileClasspath;
@@ -115,6 +114,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;
@@ -124,7 +124,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.
@@ -892,6 +891,7 @@
*/
protected void resetFileLists() {
compileList = new File[0];
+ packageInfos = new HashMap();
}
/**
@@ -909,8 +909,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,
@@ -1063,10 +1063,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
@@ -1100,72 +1102,69 @@
}
}
- // ----------------------------------------------------------------
- // 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 = relativePath(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, new Long(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 = relativePath(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
+ };
private String relativePath(File src, File file) {
return file.getAbsolutePath().substring(
|