はい、適切に実装する限り、これは完全に可能ですForwardingJavaFileManager
。最も重要な 2 つのメソッドは、inferBinaryName()とlist()です。これら 2 つを適切に設定すると、コンパイラは以前にコンパイルしたクラスを解決できるようになります。
inferBinaryName()
クラスの単純な名前を返さなければなりません(たとえば、 の推測されたバイナリ名はcom.test.Test
ただ になりますTest
)。これが私の実装です(のサブクラスJavaFileObject
は呼び出されInAppJavaFileObject
ます):
@Override
public String inferBinaryName(Location location, JavaFileObject javaFileObject) {
if(location == StandardLocation.CLASS_PATH && javaFileObject instanceof InAppJavaFileObject) {
return StringUtils.substringBeforeLast(javaFileObject.getName(), ".java");
}
return super.inferBinaryName(location, javaFileObject);
}
最後から「.java」を取り除いていることに注意してください。を構築するときJavaFileObject
、ファイル名は「.java」で終わる必要がありますが、後で接尾辞を削除しないと、コンパイラはクラスを見つけられません。
list()
デリゲート ファイル マネージャーとうまく連携するように注意する必要があるため、もう少し複雑です。私の実装では、完全修飾クラス名からサブクラスへのマップを保持しており、JavaFileObject
それを繰り返し処理できます。
@Override
public Iterable<JavaFileObject> list(Location action, String pkg, Set<JavaFileObject.Kind> kind, boolean recurse) throws IOException {
Iterable<JavaFileObject> superFiles = super.list(action, pkg, kind, recurse);
// see if there's anything in our cache that matches the criteria.
if(action == StandardLocation.CLASS_PATH && (kind.contains(JavaFileObject.Kind.CLASS) || kind.contains(JavaFileObject.Kind.SOURCE))) {
List<JavaFileObject> ourFiles = new ArrayList<JavaFileObject>();
for(Map.Entry<String,InAppJavaFileObject> entry : files.entrySet()) {
String className = entry.getKey();
if(className.startsWith(pkg) && ("".equals(pkg) || pkg.equals(className.substring(0, className.lastIndexOf('.'))))) {
ourFiles.add(entry.getValue());
}
}
if(ourFiles.size() > 0) {
for(JavaFileObject javaFileObject : superFiles) {
ourFiles.add(javaFileObject);
}
return ourFiles;
}
}
// nothing found in our hash map that matches the criteria... return
// whatever super came up with.
return superFiles;
}
これらのメソッドを適切に実装すると、残りは機能します。楽しみ!