byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

ByteBuddy is incompatible with CDS due to the Java 6 baseline

Open sdeleuze opened this issue 1 year ago • 4 comments

When running an application and Spring Boot 3.3 CDS support and Bytebuddy (typically Spring Data JPA applications like Petclinic), a lot of warnings are visible in the logs like [warning][cds] Skipping net/bytebuddy/description/type/TypeDefinition: Old class has been linked. I think this is due to the Java 6 baseline used by ByteBuddy, a Java 8 baseline would make ByteBuddy CDS compliant.

sdeleuze avatar Jun 17 '24 07:06 sdeleuze

Byte Buddy is used in a lot of tooling which normally needs to support older VMs, too. Not sure why the class data sharing excludes old class files, but for now I think the benefits of an old class file format out weight the negatives.

raphw avatar Jun 17 '24 11:06 raphw

Would a multi-release JAR be a path out of this?

odrotbohm avatar Jun 17 '24 15:06 odrotbohm

That would work, would however double the jar size. Possibly I could offer two artifacts. I will look into that.

Does class data sharing even support MR jars?

raphw avatar Jun 17 '24 16:06 raphw

Yes, I got the confirmation from the Java Platform team that MR jars would solve this. See also the related issue https://bugs.openjdk.org/browse/JDK-8288334.

sdeleuze avatar Jul 03 '24 08:07 sdeleuze

As I understand it: The JDK might support older class files at some point?

raphw avatar Aug 29 '24 19:08 raphw

Short term no, in Java 25 potentially (see https://bugs.openjdk.org/browse/JDK-8317269) but I still think publishing a JDK8 version of Bytebuddy is a good idea as it brings other benefits to all users by making the class verification faster when CDS is not in use (that's a guidance that comes from directly from the Java platform team) and that would avoid requiring the latest JDK so those improvements would reach a much larger audience.

BTW this is what Netty plan to do short term, they were until now using old bytecode in Netty 4.1 and they are going to switch to JDK8 (without using MR jars) very soon in Netty 4.2.

sdeleuze avatar Sep 13 '24 16:09 sdeleuze

I agree, generally speaking I would like to offer Byte Buddy as 1.8 class files. But I would want to allow adding a classifier or some other dependency configuration option, to allow tool vendor (typically for Java agents), to switch back to another artifact.

I will investigate how this could work and try to offer a solution. And please offer a solution if you already have an idea, I have to read up on this myself, too.

raphw avatar Sep 13 '24 18:09 raphw

I made an attempt now with byte-buddy-agent and byte-buddy-dep. I compile the sources twice and create additional jars with the classifier java8. Would that work? Could you build Byte Buddy from the multiple-jars branch with the java8Artifact profile active, and try (with byte-buddy-agent or byte-buddy-dep)? This should work in theory. This could be activated in the dependency configurations, for example, and solve the problem for those in need.

I have not yet made up my mind if I might invert this, but maybe I will start this way at least, especially since the problem might be temporary. Unfortunately, there is still quite some Java 5/6 in banks and insurances, so I am not sure when I give up on supporting such old JVMs.

raphw avatar Sep 14 '24 19:09 raphw

On a side note: ASM will always be compiled to Java 5. Will that be a problem?

raphw avatar Sep 14 '24 20:09 raphw

Using the java8 classifier artifact allows to go from 879 to 46 CDS warnings on Spring Petclinic so I guess that's worth even if a few ASM classes are indeed still mentioned.

The question now is to see if Hibernate is willing to update their build to use this potential this java8 classifier artifact, since we would like to avoid asking users to do it manually. Is it something we can check with them or should we?

sdeleuze avatar Oct 15 '24 09:10 sdeleuze

Possibly, I can merge this in as a MR jar. This would blow up the artifact size, but I wonder if this really matters in today's world. Would make it an implicit default, too, what I'd think is preferable.

raphw avatar Oct 15 '24 10:10 raphw

Happy to test a MR jar locally if you add that to a brancg, I agree that getting the implicit default would be much better.

sdeleuze avatar Oct 15 '24 12:10 sdeleuze

Try the mr-java8 branch. The JAR is 8 MB now, that is somewhat a concern, but I would not think that is an actual problem but rather a cosmetic one.

raphw avatar Oct 15 '24 20:10 raphw

Works as expected, I just had to override the version of the net.bytebuddy:byte-buddy dependency with the one locally built, and I just had the 46 CDS warnings instead of the 879 ones.

sdeleuze avatar Oct 16 '24 08:10 sdeleuze

I think I will implement this then. Normally jar size is not important as dependencies are cached. For agents, the mr feature can be unrolled as one can strip one of the versions out. Byte Buddy is already large as it covers the entire Java language and its instrumentation features, so the few people who have an issue with this will likely be able to address it.

raphw avatar Oct 16 '24 14:10 raphw

Just FYI: I worked out a small Maven plugin that takes the shaded ASM dependency, computes stack map frames and stores a Java 8 version of ASM in the multi-release jar, alongside the Byte Buddy classes. This should take care of the remaining 46 CDS warnings for you.

raphw avatar Oct 21 '24 08:10 raphw

Still edging out some things, but this will not take too long to figure out.

raphw avatar Oct 21 '24 08:10 raphw

@sdeleuze Could you give this another try and:

Build https://github.com/raphw/bytecode-update-maven-plugin Then build this branch: https://github.com/raphw/byte-buddy/tree/asm-multi-release

After that, CDS should work with byte-buddy.jar without any warnings.

raphw avatar Oct 21 '24 12:10 raphw

That would be super cool to include a shaded CDS friendly ASM dependency.

I try what you suggested, and updated my Petclinic application to use the locally build net.bytebuddy:byte-buddy:1.15.6-SNAPSHOT dependency, but I still see the same warnings, for example:

[4.292s][warning][cds] Skipping net/bytebuddy/jar/asm/MethodVisitor: Old class has been linked
[4.292s][warning][cds] Skipping net/bytebuddy/jar/asm/AnnotationWriter: Old class has been linked

To double check, I then checked the bytecode version of an ASM class:

asm$ javap -v MethodVisitor.class | grep major
  major version: 49

Which means Java 5.

Could you please double check if everything works as expected on your side and if I should modify something in the repos to get the ASM classes compiled with Java 8.

sdeleuze avatar Oct 21 '24 13:10 sdeleuze

Sorry, add the -Pmulti-release profile when building Byte Buddy.

PS: can you link me to how I can check this myself?

raphw avatar Oct 21 '24 13:10 raphw

Ah, all good now, thanks!

In order to reproduce:

git clone https://github.com/spring-projects/spring-petclinic
cd spring-petclinic
nano pom.xml # Here add a dependency to net.bytebuddy:byte-buddy:1.15.6-SNAPSHOT to override the version
mvn clean package -DskipTests
java -Djarmode=tools -jar target/spring-petclinic-3.3.0-SNAPSHOT.jar extract --destination target/application
java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar target/application/spring-petclinic-3.3.0-SNAPSHOT.jar
java -XX:SharedArchiveFile=application.jsa -jar target/application/spring-petclinic-3.3.0-SNAPSHOT.jar

The remaining warnings for proxies are expected and harmless.

See https://docs.spring.io/spring-boot/reference/packaging/efficient.html#packaging.efficient.unpacking and https://docs.spring.io/spring-boot/reference/packaging/class-data-sharing.html related documentations.

sdeleuze avatar Oct 21 '24 13:10 sdeleuze

Hey everyone, I just stumbled upon this issue while trying out CDS/AOT caching. In the latest petclicin with ByteBuddy 1.17.5 there is a non-proxy-related warning now:

[12,390s][warning][cds] Skipping net/bytebuddy/utility/Invoker$Dispatcher: Old class has been linked

Not sure why this started to appear and why CDS is complaining about it. Could this be added to the newer baseline as well? Or should I open a new ticket for this? Reproduction case is basically the same as above:

git clone https://github.com/spring-projects/spring-petclinic
cd spring-petclinic
mvn clean package -DskipTests
java -Djarmode=tools -jar target/spring-petclinic-3.5.0-SNAPSHOT.jar extract --destination target/application
java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar target/application/spring-petclinic-3.5.0-SNAPSHOT.jar

Edit: I just saw that the Invoker.class is actually included in META-INF/versions/9/net/bytebuddy/utility already. Not sure if 9 is too old now or if it's not using this class for some reason, my Java knowledge is not good enough for this unfortunately.

der-eismann avatar Oct 02 '25 14:10 der-eismann

The dispatcher classes are runtime generated and use Java 5 as a format. I'll adjust it to use the current VM format instead to avoid this message.

raphw avatar Oct 02 '25 20:10 raphw

This is fixed on master now. Could you build the current version and try it?

raphw avatar Oct 05 '25 20:10 raphw

So I built byte-buddy locally (commit a1e2055fd643985786318dd9861bf3706a234b6e) with Java 21 and the class in question disappeared from the output indeed, however there's a bunch of new stuff there that I'm sure I didn't see with 1.17.5:

[38,035s][warning][aot] Skipping net/bytebuddy/jar/asm/signature/SignatureWriter: Old class has been linked
[38,035s][warning][aot] Skipping net/bytebuddy/jar/asm/signature/SignatureVisitor: Old class has been linked
[38,037s][warning][aot] Skipping net/bytebuddy/jar/asm/Type: Old class has been linked
[38,038s][warning][aot] Skipping net/bytebuddy/utility/AsmClassWriter$FrameComputingClassWriter: Old class has been linked
[38,061s][warning][aot] Skipping net/bytebuddy/jar/asm/MethodWriter: Old class has been linked
[38,062s][warning][aot] Skipping net/bytebuddy/jar/asm/ClassReader: Old class has been linked
[38,063s][warning][aot] Skipping net/bytebuddy/jar/asm/ClassWriter: Old class has been linked
[38,063s][warning][aot] Skipping net/bytebuddy/jar/asm/MethodVisitor: Old class has been linked
[38,063s][warning][aot] Skipping net/bytebuddy/jar/asm/Attribute: Old class has been linked
[38,064s][warning][aot] Skipping net/bytebuddy/jar/asm/ClassVisitor: Old class has been linked
[38,064s][warning][aot] Skipping net/bytebuddy/jar/asm/SymbolTable: Old class has been linked
[38,064s][warning][aot] Skipping net/bytebuddy/jar/asm/ByteVector: Old class has been linked
[38,064s][warning][aot] Skipping net/bytebuddy/jar/asm/Symbol: Old class has been linked
[38,066s][warning][aot] Skipping net/bytebuddy/jar/asm/AnnotationWriter: Old class has been linked
[38,067s][warning][aot] Skipping net/bytebuddy/jar/asm/SymbolTable$Entry: Old class has been linked
[38,068s][warning][aot] Skipping net/bytebuddy/jar/asm/Handler: Old class has been linked
[38,068s][warning][aot] Skipping net/bytebuddy/jar/asm/TypeReference: Old class has been linked
[38,068s][warning][aot] Skipping net/bytebuddy/jar/asm/AnnotationVisitor: Old class has been linked
[38,073s][warning][aot] Skipping net/bytebuddy/dynamic/scaffold/TypeWriter$Default$ValidatingClassVisitor: Old class has been linked

der-eismann avatar Oct 07 '25 10:10 der-eismann

You will have to build with -Pmulti-release to generate a multi-release jar file that translates ASM over to Java 8. Could you try once more with this option?

raphw avatar Oct 07 '25 16:10 raphw