[MAGNOLIA-8958] Guice method interceptions fails with "Unsupported class file major version 61" on JRE 17 Created: 16/Jun/23  Updated: 16/Jan/24  Resolved: 28/Jun/23

Status: Closed
Project: Magnolia
Component/s: None
Affects Version/s: 6.2.35
Fix Version/s: 6.2.37

Type: Bug Priority: Neutral
Reporter: Michael Duerig Assignee: Michael Duerig
Resolution: Done Votes: 0
Labels: maintenance
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Problem/Incident
Relates
causality
dependency
depends upon ANALYTICS-487 Update Guice to 5.1.0 Closed
depends upon BLOSSOM-315 Update Guice to 5.1.0 Closed
depends upon BUILD-1093 Update Guice to 5.1.0 Closed
depends upon ECOMMERCE-574 Update Guice to 5.1.0 Closed
depends upon MAGNOLIA-8959 Update Guice to 5.1.0 Closed
depends upon MGNLCE-351 Update Guice to 5.1.0 Closed
depends upon MGNLFORM-390 Update Guice to 5.1.0 Closed
depends upon MGNLRES-397 Update Guice to 5.1.0 Closed
depends upon MGNLSSO-295 Update Guice to 5.1.0 Closed
depends upon MGNLUI-8125 Update Guice to 5.1.0 Closed
depends upon SECURITY-66 Update Guice to 5.1.0 Closed
Template:
Acceptance criteria:
Empty
Task DoD:
[X]* Doc/release notes changes? Comment present?
[X]* Downstream builds green?
[X]* Solution information and context easily available?
[X]* Tests
[X]* FixVersion filled and not yet released
[ ]  Architecture Decision Record (ADR)
Bug DoR:
[X]* Steps to reproduce, expected, and actual results filled
[X]* Affected version filled
Testcase included:
Yes
Release notes required:
Yes
Date of First Response:
Team: Foundation
Work Started:
Approved:
Yes

 Description   

Steps to reproduce

public class InterceptorTest {

    interface Base<T>{
        void foo(T arg);
    }

    // Inheriting from a parametrized base class causes the JVM to generate a bridge method, which in
    // turn will trigger the code path in bindInterceptor() that leads to the problem.
    public static class Impl implements Base<String > {
        @Override
        public void foo(String arg) { }
    }

    @Test
    void test() {
        Injector injector = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bindInterceptor(
                    Matchers.any(),
                    Matchers.any(),
                    invocation -> null
                );
                bind(Impl.class);
            }
        });
    }
}

Compile and run InterceptorTest with Java 17.

Note: it is not clear how to automate this test as Magnolia 6.2 does not compile and build against Java 17 currently.

Expected results

The test passes.

Actual results

The test fails:

com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalArgumentException: Unsupported class file major version 61    at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2051)
    at com.google.common.cache.LocalCache.get(LocalCache.java:3951)
    at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3974)
    at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4958)
    at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4964)
    at com.google.inject.internal.FailableCache.get(FailableCache.java:51)
    at com.google.inject.internal.ConstructorInjectorStore.get(ConstructorInjectorStore.java:48)
    at com.google.inject.internal.ConstructorBindingImpl.initialize(ConstructorBindingImpl.java:155)
    at com.google.inject.internal.InjectorImpl.initializeBinding(InjectorImpl.java:581)
    at com.google.inject.internal.AbstractBindingProcessor$Processor$1.run(AbstractBindingProcessor.java:176)
    at com.google.inject.internal.ProcessedBindingData.initializeBindings(ProcessedBindingData.java:49)
    at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:122)
    at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:106)
    at com.google.inject.Guice.createInjector(Guice.java:87)
    at com.google.inject.Guice.createInjector(Guice.java:69)
    at com.google.inject.Guice.createInjector(Guice.java:59)
    at info.magnolia.addon.commons.cache.InterceptorTest.test(InterceptorTest.java:37)
    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.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: java.lang.IllegalArgumentException: Unsupported class file major version 61
    at com.google.inject.internal.asm.$ClassReader.<init>(ClassReader.java:184)
    at com.google.inject.internal.asm.$ClassReader.<init>(ClassReader.java:166)
    at com.google.inject.internal.asm.$ClassReader.<init>(ClassReader.java:152)
    at com.google.inject.internal.asm.$ClassReader.<init>(ClassReader.java:273)
    at com.google.inject.internal.cglib.core.$DuplicatesPredicate.<init>(DuplicatesPredicate.java:93)
    at com.google.inject.internal.cglib.proxy.$Enhancer.getMethods(Enhancer.java:557)
    at com.google.inject.internal.cglib.proxy.$Enhancer.getMethods(Enhancer.java:535)
    at com.google.inject.internal.ProxyFactory.<init>(ProxyFactory.java:87)
    at com.google.inject.internal.ConstructorInjectorStore.createConstructor(ConstructorInjectorStore.java:82)
    at com.google.inject.internal.ConstructorInjectorStore.access$000(ConstructorInjectorStore.java:29)
    at com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjectorStore.java:37)
    at com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjectorStore.java:33)
    at com.google.inject.internal.FailableCache$1.load(FailableCache.java:40)
    at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3529)
    at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2278)
    at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2155)
    at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2045)
    ... 81 more
 

Workaround

Use Java 11.

Development notes

  • This happens to customer projects using @Cacheable annotations. See SUPPORT-16042 and this reproducer.
  • According to mgeljic  " if a customer successfully builds a module w/ 17 and puts it on the classpath, our runtime should support it, even if we ourselves are not building with 17."

Root cause analysis

The is caused by Guice 4.2.2's shaded version of asm not being compatible with Java 17. In ClassFileReader it checks the class file version and fails:

if (checkClassVersion && this.readShort(classFileOffset + 6) > 58) {
    throw new IllegalArgumentException("Unsupported class file major version " + this.readShort(classFileOffset + 6)); 
}

To fix this we need to upgrade to Guice 5.1.0. See  DEV-2014 for the related effort on 6.3.


Generated at Mon Feb 12 04:37:20 CET 2024 using Jira 9.4.2#940002-sha1:46d1a51de284217efdcb32434eab47a99af2938b.