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