I updated our codebase from JDK 15 to JDK 16. On JDK 15 all was working fine with or without ProGuard. Running the code in development on JDK 16 works totally fine. However, going through ProGuard 7.1.1, there is an exception when run:
cannot link Java class com.company.SomeClass Preview features are not enabled for com/company/SomeClass (class file version 60.65535). Try running with '--enable-preview'
I don’t see a reason for this. I’m not using any preview features. Why is ProGuard generating code that requires that flag?
Add support for records (previewed in Java 15/16, targeted for Java 17).
Which is not true. Records are final in JDK 16, they are not a preview feature there. Not sure if it is relevant to the issue above (although I’m not using Records in my application).
Thank you for asking this question here on the community.
This exception might show up if you use some dependencies who are on their turn using preview features. Could you maybe share the full log and a sample reproducing the issue?
With regards to the note you made, thanks for catching that one! It looks like this release note got mixed up with the one about “sealed classes”.
I’ve been trying to reproduce for the past hour. It’s obviously more difficult than just adding all my dependencies as that works fine. So there must be something else that triggers ProGuard to generate such class files. Is there a way to find which dependency might “turn on” preview features? Or a way to find out why ProGuard decides to generate class files that require the preview-features flag?
package com.company.servlets;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import org.apache.catalina.servlets.DefaultServlet;
@WebServlet(
name = "company-default",
urlPatterns = "/foobar",
loadOnStartup = 2,
initParams = @WebInitParam(name = "precompressed", value = "true"))
public class UIServlet extends DefaultServlet {
}
Run gradle war on this and put the resulting build/libs/company.war file in some Apache Tomcat installation. Run Tomcat and do a curl -vvv localhost:8080/company/foobar. That will lead to:
03-Aug-2021 14:44:14.499 INFO [main] org.apache.catalina.core.ApplicationContext.log Marking servlet [company-default] as unavailable
03-Aug-2021 14:44:14.500 SEVERE [main] org.apache.catalina.core.StandardContext.loadOnStartup Servlet [company-default] in web application [/company] threw load() exception
java.lang.UnsupportedClassVersionError: Preview features are not enabled for a/a/a/a (class file version 60.65535). Try running with '--enable-preview' (unable to load class [a.a.a.a])
at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2424)
at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:865)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1334)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1188)
at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:540)
at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:521)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:150)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1042)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:983)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4871)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5180)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:717)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:690)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:978)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1849)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:123)
at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:773)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:427)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1576)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:309)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123)
at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:423)
at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:366)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:936)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:841)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:421)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:932)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.startup.Catalina.start(Catalina.java:633)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:344)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:475)
I believe this is a bug in ProGuard. Should I open an issue in the repo?
P.S. Forgot to add that it’s because of the keepattributes '*Annotation*' line. If I remove that, the error is gone. Any ideas why?
Dear @boris
Thanks a lot for investing some time into this issue.
I tried to make a sample with the information provided but I am seeing the following error when I run the gradle war task:
Caused by: java.lang.IllegalAccessError: class org.gradle.internal.compiler.java.ClassNameCollector (in unnamed module @0x3531d7a1) cannot access class com.sun.tools.javac.code.Symbol$TypeSymbol (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.code to unnamed module @0x3531d7a1
Google is not really giving me any useful info. I already tried to change my gradle version (JDK is set to 16) in my gradle properties, currently using 7.1.1:
Thanks a lot for sharing your sample with us. We were able to identify the issue. We will most likely include the fix in version 7.2.0-beta2 which we will release soon.