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:
<bytecodeTargetLevel target="17">
<module name="JobRunr.tests.e2e-elasticsearch-gson.test" target="11" />
<module name="JobRunr.tests.e2e-elasticsearch-jackson.test" target="11" />
<module name="JobRunr.tests.e2e-json-gson.test" target="11" />
<module name="JobRunr.tests.e2e-mariadb-gson.test" target="11" />
<module name="JobRunr.tests.e2e-mariadb-jackson.test" target="11" />
<module name="JobRunr.tests.e2e-mongo-gson.test" target="11" />
<module name="JobRunr.tests.e2e-mongo-jackson.test" target="11" />
<module name="JobRunr.tests.e2e-mysql-gson.test" target="11" />
<module name="JobRunr.tests.e2e-mysql-jackson.test" target="11" />
<module name="JobRunr.tests.e2e-oracle-gson.test" target="11" />
<module name="JobRunr.tests.e2e-oracle-jackson.test" target="11" />
<module name="JobRunr.tests.e2e-postgres-gson.test" target="11" />
<module name="JobRunr.tests.e2e-postgres-jackson.test" target="11" />
<module name="JobRunr.tests.e2e-redis-gson.test" target="11" />
<module name="JobRunr.tests.e2e-redis-jackson.test" target="11" />
<module name="JobRunr.tests.e2e-sqlserver-gson.test" target="11" />
<module name="JobRunr.tests.e2e-sqlserver-jackson.test" target="11" />
<module name="JobRunr.tests.e2e-ui.main" target="11" />
<module name="JobRunr.tests.e2e-ui.test" target="11" />
<module name="JobRunr.tests.e2e-vm-jdk.test" target="11" /> <----- here
</bytecodeTargetLevel>