groovy
  1. groovy
  2. GROOVY-3451

Script returns "interface groovy.lang.Category" when evaluating "Category"

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: 1.6
    • Fix Version/s: None
    • Component/s: class generator
    • Labels:
      None
    • Environment:
      XP or linux. Reproduces with a simple java program using embeddable groovy.
    • Testcase included:
      yes
    • Number of attachments :
      0

      Description

      If a script is simply "Category" where the binding has capability to resolve a variable of that name, Groovy returns "interface groovy.lang.Category" instead of the value of the variable "Category" from the given binding object. Here's a java code that reproduces this issue:

      import groovy.lang.Binding;
      import groovy.lang.GroovyShell;
      import groovy.lang.Script;
      
      public class testCategory {
      
          public static void main(String[] args) {
              Binding binding = new Binding() {
                  public Object getVariable(String key) {
                      if (key.equals("Category")) {
                          return new Long(210);
                      }
                      return super.getVariable(key);
                  }
              };
              GroovyShell shell =
                  new GroovyShell(Thread.currentThread().getContextClassLoader());
              String expr = "Category";
              Script scr = shell.parse(expr);
              System.out.println(expr);
              scr.setBinding(binding);
              Object value = scr.run();
              System.out.println(value);
          }
      }
      

      The output of the above code is expected to be:
      Category
      210

      instead, what we get is:
      Category
      interface groovy.lang.Category

        Activity

        Hide
        blackdrag blackdrag added a comment -

        you see, you would get that problem even in Java if variables and classes would share a name space and if you compile from source each time. But well, it is still possible that something happens in Java, for example if a method gets overloaded and you call suddenly a different method than before causing a breaking change. The solution for this in Java is to compile not against the new Java, but the old Java, meaning cross compilation.

        Now for Groovy this is much more difficult. But you know, there is a class loader that you give in to GroovyShell, GroovyClassLoader or CompilationUnit (whatever you use to compile at runtime). in that loader you could black or white list classes from groovy.lang and groovy.util. Or you could attach a phase operation to the compiler (using CompilationUnit or GroovyClassLoader) to transform ClassExpressions into VariableExpressions.

        Is one of these ways suitable for you?

        Show
        blackdrag blackdrag added a comment - you see, you would get that problem even in Java if variables and classes would share a name space and if you compile from source each time. But well, it is still possible that something happens in Java, for example if a method gets overloaded and you call suddenly a different method than before causing a breaking change. The solution for this in Java is to compile not against the new Java, but the old Java, meaning cross compilation. Now for Groovy this is much more difficult. But you know, there is a class loader that you give in to GroovyShell, GroovyClassLoader or CompilationUnit (whatever you use to compile at runtime). in that loader you could black or white list classes from groovy.lang and groovy.util. Or you could attach a phase operation to the compiler (using CompilationUnit or GroovyClassLoader) to transform ClassExpressions into VariableExpressions. Is one of these ways suitable for you?
        Hide
        Steve Muench added a comment -

        Is the black/white listing in the classloader we pass in a Groovy feature or a classloader feature? Can you suggest how our example code above would need to change to adopt your black/white list suggestion as a workaround?

        Thanks.

        Show
        Steve Muench added a comment - Is the black/white listing in the classloader we pass in a Groovy feature or a classloader feature? Can you suggest how our example code above would need to change to adopt your black/white list suggestion as a workaround? Thanks.
        Hide
        blackdrag blackdrag added a comment - - edited

        Well, instead of feeding in the context loader you do

        GroovyClassLoader gcl = new GroovyClassLoader(contextLoader) {
          public Class loadClass(String name, boolean resolve) {
            if (name in blackllist) throw new ClassNotFoundException(...)
            return super.loadClass(name,resolve)
          }
        }
        

        It does not have to be a GroovyClassLoader, it can be any ClassLoader. anyway, you use this loader and give it to the shell, all done.

        Show
        blackdrag blackdrag added a comment - - edited Well, instead of feeding in the context loader you do GroovyClassLoader gcl = new GroovyClassLoader(contextLoader) { public Class loadClass( String name, boolean resolve) { if (name in blackllist) throw new ClassNotFoundException(...) return super .loadClass(name,resolve) } } It does not have to be a GroovyClassLoader, it can be any ClassLoader. anyway, you use this loader and give it to the shell, all done.
        Hide
        Steve Muench added a comment -

        Thanks. Consider a simple example where "groovy.lang.Category" and "java.lang.Long" were in the blacklist. Would this idea above just stop the default resolution of "groovy.lang.Category" and "java.lang.Long" before the script client gets a chance to resolve an unqualified "Category" or "Long" reference, or would it cripple the runtime from every loading/using (even a fully-qualified) instance of groovy.lang.Category or java.lang.Long?

        Show
        Steve Muench added a comment - Thanks. Consider a simple example where "groovy.lang.Category" and "java.lang.Long" were in the blacklist. Would this idea above just stop the default resolution of "groovy.lang.Category" and "java.lang.Long" before the script client gets a chance to resolve an unqualified "Category" or "Long" reference, or would it cripple the runtime from every loading/using (even a fully-qualified) instance of groovy.lang.Category or java.lang.Long?
        Hide
        blackdrag blackdrag added a comment -

        It works if you don't use these classes in your code. If you blacklist java.util.Category, then you must not use it in your code or else you are screwed.

        Show
        blackdrag blackdrag added a comment - It works if you don't use these classes in your code. If you blacklist java.util.Category, then you must not use it in your code or else you are screwed.

          People

          • Assignee:
            blackdrag blackdrag
            Reporter:
            S Vinayaka
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: