I'm Ronald, the author of JobRunr. JobRunr is a background job scheduling library that uses SerializedLambda and ASM to analyze a Java 8 lambda and converts it to a background job.
Recently, an error was reported and I tried reproducing it in JobRunr so that I can write a test to prevent regression.
The funny thing is that on the same Java version (17.0.2), I cannot reproduce it even if I copy the exact code.
In this project, the generated SerializedLambda has an implMethodKind equal to 5 (REF_invokeVirtual).
Yet, in JobRunr itself, the generated SerializedLambda has an implMethodKind equal to 7 (REF_invokeSpecial).
The actual code to generate the SerializedLambda is as follows:
public class GeoService {
Logger LOG = LoggerFactory.getLogger(GeoService.class);
public void executeGeoTreeJob(JobContext jobContext, long geoNameId, UserId userId) {
LOG.error("Running: " + geoNameId);
}
public void run() {
LOG.error("Starting job");
UserId userId = new UserId();
userId.setValue("test");
long geoNameId = 1234;
JobLambda jobLambda = () -> executeGeoTreeJob(JobContext.Null, geoNameId, userId);
SerializedLambda serializedLambda = SerializedLambdaConverter.toSerializedLambda(jobLambda);
System.out.println("=======");
System.out.println("serializedLambda " + serializedLambda.getImplMethodKind());
System.out.println("=======");
BackgroundJob.enqueue(() -> executeGeoTreeJob(JobContext.Null, geoNameId, userId));
}
}
In this project, the generated SerializedLambda has an implMethodKind equal to 5 (REF_invokeVirtual).
Yet, in JobRunr itself, the generated SerializedLambda has an implMethodKind equal to 7 (REF_invokeSpecial).
Why do I get different values for implMethodKind? Or, put differently, what do I need to do to the setup / JVM / ... to have the same results as in the example project.
Update:
I create the SerializedLambda as follows:
public class SerializedLambdaConverter {
private SerializedLambdaConverter() {
}
public static <T> SerializedLambda toSerializedLambda(T value) {
if (!value.getClass().isSynthetic()) {
throw new IllegalArgumentException("Please provide a lambda expression (e.g. BackgroundJob.enqueue(() -> myService.doWork()) instead of an actual implementation.");
}
if (!(value instanceof Serializable)) {
throw new JobRunrException("The lambda you provided is not Serializable. Please make sure your functional interface is Serializable or use the JobLambda interface instead.");
}
try {
Method writeReplaceMethod = value.getClass().getDeclaredMethod("writeReplace");
makeAccessible(writeReplaceMethod);
return (SerializedLambda) writeReplaceMethod.invoke(value);
} catch (Exception shouldNotHappen) {
throw shouldNotHappenException(shouldNotHappen);
}
}
}
Below the output of javap:
Compiled from "GeoService.java"
public class org.jobrunr.tests.e2e.services.GeoService {
org.slf4j.Logger LOG;
public org.jobrunr.tests.e2e.services.GeoService();
public void executeGeoTreeJob(org.jobrunr.jobs.context.JobContext, long, org.jobrunr.tests.e2e.services.UserId);
public void run();
}
Attached the headers found in the output of javap -verbose (the full output is a bit too much for here in SO):
Classfile /Users/rdehuyss/Projects/Personal/jobrunr/jobrunr/tests/e2e-vm-jdk/build/classes/java/main/org/jobrunr/tests/e2e/services/GeoService.class
Last modified 20 Feb 2024; size 4064 bytes
SHA-256 checksum 595969292bcac503d33a4e54c1b2a4ffa7517f8aa6c50a8a1470400981e08ecb
Compiled from "GeoService.java"
public class org.jobrunr.tests.e2e.services.GeoService
minor version: 0
major version: 52
Just to check, could you try and modify your
.idea/compiler.xml, this part: