Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-10565

JDK 17: Sealed classes inside a package cause Exception in thread "main" java.lang.ClassFormatError: Illegal class name

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Critical
    • Resolution: Fixed
    • 4.0.0, 4.0.1
    • 4.0.2
    • None

    Description

      I have found an issue with using sealed types that are inside a package. I took the example from the Groovy 4 release notes and I run it successfully - all classes in this example use the default package. However, when I took the same code and I put it in any package (e.g. `example` package), the execution started failing with:

      Exception in thread "main" java.lang.ClassFormatError: Illegal class name "example.Empty" in class file example/Tree
              at java.base/java.lang.ClassLoader.defineClass1(Native Method)
              at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
              at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
              at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862)
              at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)
              at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)
              at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
              at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
              at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
              at java.base/java.lang.ClassLoader.defineClass1(Native Method)
              at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
              at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
              at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862)
              at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)
              at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)
              at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
              at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
              at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
              at example.notworking.run(notworking.groovy:20)
              at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
              at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
              at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
              at java.base/java.lang.reflect.Method.invoke(Method.java:568)
              at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
              at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
              at groovy.lang.MetaClassImpl.doInvokeMethod(MetaClassImpl.java:1369)
              at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1103)
              at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009)
              at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:610)
              at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:593)
              at org.codehaus.groovy.runtime.InvokerHelper.runScript(InvokerHelper.java:413)
              at org.codehaus.groovy.runtime.InvokerHelper$runScript.callStatic(Unknown Source)
              at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:54)
              at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:217)
              at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:240)
              at example.notworking.main(notworking.groovy)
      
      

      Here is the code that produces this error:

      package example
      
      import groovy.transform.Canonical
      
      sealed interface Tree<T> {}
      
      @Singleton final class Empty implements Tree {
          String toString() { 'Empty' }
      }
      
      @Canonical final class Node<T> implements Tree<T> {
          T value
          Tree<T> left, right
      
          String toString() {
              "Node($value, $left, $right)"
          }
      }
      
      Tree<Integer> tree = new Node<Integer>(42, new Node<>(0, Empty.instance, Empty.instance), Empty.instance)
      assert tree.toString() == 'Node(42, Node(0, Empty, Empty), Empty)'
      
      println "IT WORKS!"
      

      One important note: this error shows up when I use Java 17. If I run the same code with Java 8 or Java 11, all works fine.

      Also one thing: this problem does not occur in plain Java (I attached such an example in the repository below).

      I created an exemplary Gradle project that reproduces this issue - https://github.com/wololock/groovy-4-sealed-issue

      Attachments

        Activity

          People

            paulk Paul King
            wololock Szymon Stępniak
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Time Tracking

                Estimated:
                Original Estimate - Not Specified
                Not Specified
                Remaining:
                Remaining Estimate - 0h
                0h
                Logged:
                Time Spent - 0.5h
                0.5h