Resolving classes from (complicated) runtime class loaders (compiling code ad hoc to run)
Compl Yue Still
complystill at gmail.com
Mon Nov 10 06:19:01 PST 2008
Now I've found it's more work to support star and static imports,
worked out so far:
# HG changeset patch
# User Compl<cys at ableverse.org>
# Date 1226326029 -28800
# Node ID d1cd39daf341e52dd12b8944dc3903815bed926a
# Parent eedce2b27b126242ddafbf0023430d38f7eaeae3
star import supports for resolving types from runtime class loaders
diff -r eedce2b27b12 -r d1cd39daf341 src/share/classes/com/sun/tools/
javac/comp/MemberEnter.java
--- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Sat
Nov 08 18:24:08 2008 +0800
+++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Mon
Nov 10 22:07:09 2008 +0800
@@ -129,6 +129,12 @@
private void importAll(int pos,
final TypeSymbol tsym,
Env<AttrContext> env) {
+ // Added code to resolve classes from runtime class loaders {
+ List<TypeSymbol> oldImportPkgs = env.toplevel.starImportedPkgs;
+ env.toplevel.starImportedPkgs = oldImportPkgs==null?
+ List.of(tsym) : oldImportPkgs.prepend(tsym);
+ if(false) // assume any star imported package exists
+ // Added code to resolve classes from runtime class loaders }
// Check that packages imported from exist (JLS ???).
if (tsym.kind == PCK && tsym.members().elems == null && !
tsym.exists()) {
// If we can't find java.lang, exit immediately.
diff -r eedce2b27b12 -r d1cd39daf341 src/share/classes/com/sun/tools/
javac/comp/Resolve.java
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Sat Nov
08 18:24:08 2008 +0800
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Nov
10 22:07:09 2008 +0800
@@ -968,7 +968,38 @@
if (sym.exists()) return sym;
else if (sym.kind < bestSoFar.kind) bestSoFar = sym;
- sym = findGlobalType(env, env.toplevel.starImportScope,
name);
+ // Changed to resolve classes from runtime class loaders {
+ // Original code {
+ // sym = findGlobalType(env,
env.toplevel.starImportScope, name);
+ // Original Code }
+ // New code {
+ // first do normal search
+ for (Scope.Entry e =
env.toplevel.starImportScope.lookup(name);
+ e.scope != null; e = e.next()) {
+ sym = loadClass(env, e.sym.flatName());
+ if (bestSoFar.kind == TYP && sym.kind == TYP &&
+ bestSoFar != sym)
+ return new AmbiguityError(bestSoFar, sym);
+ if (sym.kind < bestSoFar.kind)
+ bestSoFar = sym;
+ }
+ if (sym.exists()) return sym; // return if found in
normal way
+ // so it's not listed by the file manager but possibly
available
+ // from runtime class loaders, let's try harder
+ for(List<TypeSymbol> pkg=env.toplevel.starImportedPkgs;
+ pkg!=null;
+ pkg=pkg.tail) {
+ Name guessedname = TypeSymbol.formFullName(name,
pkg.head);
+ sym = loadClass(env, guessedname);
+ if(!sym.exists()) continue;
+ if (bestSoFar.kind == TYP && sym.kind == TYP &&
+ bestSoFar != sym)
+ return new AmbiguityError(bestSoFar, sym);
+ if (sym.kind < bestSoFar.kind)
+ bestSoFar = sym;
+ }
+ // New code }
+ // Changed to resolve classes from runtime class loaders }
if (sym.exists()) return sym;
else if (sym.kind < bestSoFar.kind) bestSoFar = sym;
}
diff -r eedce2b27b12 -r d1cd39daf341 src/share/classes/com/sun/tools/
javac/tree/JCTree.java
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java Sat Nov
08 18:24:08 2008 +0800
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java Mon Nov
10 22:07:09 2008 +0800
@@ -431,6 +431,9 @@
public PackageSymbol packge;
public Scope namedImportScope;
public Scope starImportScope;
+ // Added code to resolve classes from runtime class loaders {
+ public List<TypeSymbol> starImportedPkgs = null;
+ // Added code to resolve classes from runtime class loaders }
public long flags;
public Position.LineMap lineMap = null;
public Map<JCTree, String> docComments = null;
But this makes javac to accept any star imported package as existing,
does it hurt?
Thanks for reading, and any suggestion appreciated.
Compl
On 2008-11-9, at 上午10:40, Compl Yue Still wrote:
> Hi Gentlemen,
>
> Here comes an issue regarding needs for compiling java code to be
> run within current JVM context (see http://sjsh.dev.java.net for
> concrete).
>
> It works like a charm when running inside a normal (meaning no
> complicated class loading scheme) JavaSE application, prompt the
> user for some java statements, compile them into bytecode/class
> file, then load it as a class and invoke its methods. however
> problems appear when run from a more complex environment, like
> inside a app server, Servlet container or RCP etc, where the
> depended class libraries are not loaded by Launcher$AppClassLoader,
> javax.tools.JavaCompiler just can't resolve classes loaded by a
> Servlet context loader and alikes.
>
> After some investigation, I finally figured out that javac expects
> all depended .class files be listed out by
> javax.tools.JavaFileManager, ahead of type resolution. This is
> pretty okay for the command line tool `javac', but when there comes
> needs for compilation and execution of Java code ad hoc for
> currently running jvm context, by invoking javax.tools.JavaCompiler,
> it just make things way too difficult. My previous effort had worked
> out some ways to guess the -cp parameter to be passed to
> JavaCompiler tool to workaround this issue, but so far limited to
> URLClassLoader and Apache Tomcat loaders, and hardly for Eclipse
> RCP. Obviously this solution can NOT `run anywhere'.
>
> I believe there have been, and will be more and more projects/
> components leveraging javax.tools.JavaCompiler as it became
> standard, and they are to face the same situation. And by far I find
> a simpler solution, by hacking a single javac's source file: src/
> share/classes/com/sun/tools/javac/jvm/ClassReader.java
>
> /** Fill in definition of class `c' from corresponding class or
> * source file.
> */
> private void fillIn(ClassSymbol c) {
> if (completionFailureName == c.fullname) {
> throw new CompletionFailure(c, "user-selected completion
> failure by class name");
> }
> currentOwner = c;
> JavaFileObject classfile = c.classfile;
> + // Added code to resolve classes from runtime class loaders {
> + if(classfile == null) {
> + try {
> + classfile = this.fileManager.getJavaFileForInput(
> + CLASS_PATH,
> + c.fullname.toString(),
> + JavaFileObject.Kind.CLASS);
> + } catch (IOException e) {
> + }
> + }
> + // Added code to resolve classes from runtime class loaders }
> if (classfile != null) {
> JavaFileObject previousClassFile = currentClassFile;
> try {
> .....
>
> This works for me, but I hate the idea to distribute nonstandard
> versions of javac.jar to users. But I'm not an openjdk dev guy,
> neither knowledge nor time to get it pass jtreg and submitted to repo.
>
> Can anybody here evaluate this patch for appropriateness and get it
> upstream? I have examined the tools doc for javac and made sure the
> resolved is not a documented feature or behavior, so should has no
> spec impact.
>
> Thanks for reading.
>
> All the best,
> Compl
>
More information about the compiler-dev
mailing list