groovy
  1. groovy
  2. GROOVY-2303

Upgrading to Groovy 1.1 final snapshot causes LinkageError in Grails

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Blocker Blocker
    • Resolution: Won't Fix
    • Affects Version/s: 1.1-rc-2
    • Fix Version/s: 1.1-rc-3
    • Component/s: None
    • Labels:
      None
    • Number of attachments :
      0

      Description

      I have a clean Grails project with the following changeset where the Groovy jar is the latest build of 1.1 final:

      the project i have has the following svn changeset
      A lib/groovy-all-1.1-final-SNAPSHOT.jar
      D lib/groovy-all-1.1-rc-1.jar
      M bin/startGrails

      When I run any Gant script in Grails (such as grails list-plugins) that depends on a W3C DOM class i get the error

      java.lang.LinkageError: Class org/w3c/dom/UserDataHandler violates loader constraints
         at java.lang.ClassLoader.defineClass1(Native Method)
         at java.lang.ClassLoader.defineClass(ClassLoader.java:675)
         at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
         at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
         at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
         at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
         at java.security.AccessController.doPrivileged(Native Method)
         at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
         at org.codehaus.groovy.tools.RootLoader.oldFindClass(RootLoader.java:142)
         at org.codehaus.groovy.tools.RootLoader.loadClass(RootLoader.java:114)
         at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
         at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
         at java.lang.Class.getDeclaredMethods0(Native Method)
         at java.lang.Class.privateGetDeclaredMethods(Class.java:2395)
         at java.lang.Class.getDeclaredMethods(Class.java:1763)
         at org.codehaus.groovy.reflection.CachedClass.getMethods(CachedClass.java:131)
         at groovy.lang.MetaClassImpl.populateMethods(MetaClassImpl.java:238)
         at groovy.lang.MetaClassImpl.fillMethodIndex(MetaClassImpl.java:217)
         at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:2380)
         at groovy.lang.ExpandoMetaClass.initialize(ExpandoMetaClass.java:355)
         at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:164)
         at org.codehaus.groovy.runtime.Invoker.getProperty(Invoker.java:172)
         at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:157)
         at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:500)
         at ListPlugins_groovy.run(ListPlugins_groovy:61)
      

      It appears to originate from a MetaClass look-up. This was not a problem before upgrading Groovy.

        Activity

        Hide
        Guillaume Laforge added a comment -

        Does it mean we can't have anymore the same class in two different jars?
        This is the kind of situation that happens all the time in app servers where the web app overrides the XML jars that are also availble in the app server.

        Show
        Guillaume Laforge added a comment - Does it mean we can't have anymore the same class in two different jars? This is the kind of situation that happens all the time in app servers where the web app overrides the XML jars that are also availble in the app server.
        Hide
        blackdrag blackdrag added a comment -

        after extensive analysis I come to the concllusion that.. it really is jaxen which is the evil one here. RootLoader does not follow completely the constrains that a classloader should follow and because of that not all things are working that would work when using only normal classloaders. As far as I can tell jaxen includes the UserDataHandler for compatibility with 1.4, in java5 jaxen duplicates this class. As long as the same loader which is loading the xml stuff is also loading the jaxen.jar, there is no problem. But in our case RootLoader loads the jaxen jar and the system loader loads the xml stuff. Because of the special construction of the RootLoader we get the problem above... As a result the jaxen classes will use the jaxen UserDataHandler and the XML classes in rt.jar will use the UserDataHandler class from rt.jar. And that is not working.

        I see several possible workarounds, but they all don't sound very good...

        one would be to enforce the loading of UserDataHandler through the system loader. For this RootLoader would have to not to include the jaxen.jar yet, and gets it added later. That's something a gant script could do.

        Another way would be to remove the UserDataHandler class from the jaxen.jar. You could still have it loaded for java1.4 when you say you set a property "java.v4.compatibility.path" for example and a line like this to the conf file:

        load ${java.v4.compatibility.path}/*.jar

        of course that means, that this should be in a directory that is normally not loaded. This directory would then for example contain a jar with the UserDataHandler class, while the normal jaxen.jar (without that class) would be in the standard lib directory.

        And the last way would be to not to add jaxen.jar to the paths RootLoader handles, but to add jaxen.jar to the classpath the system classloader gets. Of course any xml stuff would have to be in this classpath as well.

        And the last workaround would be to define a custom system classloader, by setting java.system.class.loader. That ClassLoader would have to extend RootLoader and would need to configure itself. Such a loader could prefer the classes in the conf file.. but for this the startup process of Groovy would need adaption. So it is no solution you can do quickly

        Show
        blackdrag blackdrag added a comment - after extensive analysis I come to the concllusion that.. it really is jaxen which is the evil one here. RootLoader does not follow completely the constrains that a classloader should follow and because of that not all things are working that would work when using only normal classloaders. As far as I can tell jaxen includes the UserDataHandler for compatibility with 1.4, in java5 jaxen duplicates this class. As long as the same loader which is loading the xml stuff is also loading the jaxen.jar, there is no problem. But in our case RootLoader loads the jaxen jar and the system loader loads the xml stuff. Because of the special construction of the RootLoader we get the problem above... As a result the jaxen classes will use the jaxen UserDataHandler and the XML classes in rt.jar will use the UserDataHandler class from rt.jar. And that is not working. I see several possible workarounds, but they all don't sound very good... one would be to enforce the loading of UserDataHandler through the system loader. For this RootLoader would have to not to include the jaxen.jar yet, and gets it added later. That's something a gant script could do. Another way would be to remove the UserDataHandler class from the jaxen.jar. You could still have it loaded for java1.4 when you say you set a property "java.v4.compatibility.path" for example and a line like this to the conf file: load ${java.v4.compatibility.path}/*.jar of course that means, that this should be in a directory that is normally not loaded. This directory would then for example contain a jar with the UserDataHandler class, while the normal jaxen.jar (without that class) would be in the standard lib directory. And the last way would be to not to add jaxen.jar to the paths RootLoader handles, but to add jaxen.jar to the classpath the system classloader gets. Of course any xml stuff would have to be in this classpath as well. And the last workaround would be to define a custom system classloader, by setting java.system.class.loader. That ClassLoader would have to extend RootLoader and would need to configure itself. Such a loader could prefer the classes in the conf file.. but for this the startup process of Groovy would need adaption. So it is no solution you can do quickly
        Hide
        Alex Tkachman added a comment -

        Graeme, I think what Jochen says is that we can do nothing on Groovy side but should solve the issue on Grails side.

        Show
        Alex Tkachman added a comment - Graeme, I think what Jochen says is that we can do nothing on Groovy side but should solve the issue on Grails side.
        Hide
        Guillaume Laforge added a comment -

        So, at this point, I think we can't do too much regarding this error.
        I'm closing it as won't fix for now, crossing fingers for the problem not to be bigger than what we expect – as having two libraries in different classloaders is a pretty common scenario in app servers I'm afraid.
        We'll reopen the issue if a fix is needed that no workaround would solve.

        Show
        Guillaume Laforge added a comment - So, at this point, I think we can't do too much regarding this error. I'm closing it as won't fix for now, crossing fingers for the problem not to be bigger than what we expect – as having two libraries in different classloaders is a pretty common scenario in app servers I'm afraid. We'll reopen the issue if a fix is needed that no workaround would solve.
        Hide
        Ganesh Krishnan added a comment -

        Deleting the .ivy2/cache folder fixes the problem for me.

        Show
        Ganesh Krishnan added a comment - Deleting the .ivy2/cache folder fixes the problem for me.

          People

          • Assignee:
            Graeme Rocher
            Reporter:
            Graeme Rocher
          • Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: