Search code examples
javareflectionconstructorabstract-classjobrunr

JobRunr: InstantiationException in ReflectionUtils.newInstance


I'm using JobRunr 6.3.0 for scheduling recurring background jobs in Java, and I encounter a problem with reflective access.

I'm trying to have an abstract class that implements the job scheduling logic, creating one job that calls an abstract method which is implemented in each child class. Like this:

public abstract class Blubb {

    public Blubb() {
        this(...defaultArgs);
    }

    protected Blubb(defaultArgs) {
        // set up
    }

    protected abstract String name();

    protected abstract Iterator<Object> getObjectsFromExternalSource();

    public void load() {
        JobScheduler scheduler = JobRunr
            .configure()
            .useStorageProvider(new InMemoryStorageProvider())
            .useBackgroundJobServer()
            .initialize()
            .getJobScheduler();

        scheduler.createRecurrently(
            RecurringJobBuilder
                .aRecurringJob()
                .withId(name())
                .withDuration(Duration.ofSeconds(10))
                .withDetails(this::run)
                .withAmountOfRetries(2)
        );
    }

    public void run() {
        Iterator<Object> objects = getObjectsFromExternalSource();

        while (objects.hasNext()) {
            // do stuff
        }
    }
}

Job creation works, and the job in the database looks fine:

{
  "_id": "name",
  "version": 0,
  "jobAsJson": "{\"version\":0,\"jobSignature\":\"org.example.blah.Blubb.run()\",\"jobName\":\"org.example.blah.Blubb.run()\",\"amountOfRetries\":2,\"labels\":[],\"jobDetails\":{\"className\":\"org.example.blah.Blubb\",\"staticFieldName\":null,\"methodName\":\"run\",\"jobParameters\":[],\"cacheable\":true},\"id\":\"name\",\"scheduleExpression\":\"PT10M\",\"zoneId\":\"Etc/UTC\",\"createdAt\":\"2023-08-25T06:39:29.844981739Z\"}",
  "createdAt": {
    "$numberLong": "1692945569844"
  }
}

But everytime it tries to run the job, I get the following exception:

WARN  o.j.server.BackgroundJobPerformer - Job(id=a444fd50-843a-4464-88a1-e51530056b3f, jobName='org.example.blah.Blubb.run()') processing failed: An exception occurred during the performance of the job
org.jobrunr.JobRunrException: JobRunr encountered a problematic exception. Please create a bug report (if possible, provide the code to reproduce this and the stacktrace)
    at org.jobrunr.JobRunrException.shouldNotHappenException(JobRunrException.java:43)
    at org.jobrunr.utils.reflection.ReflectionUtils.newInstance(ReflectionUtils.java:156)
    at org.jobrunr.server.runner.AbstractBackgroundJobRunner$BackgroundJobWorker.getJobToPerform(AbstractBackgroundJobRunner.java:46)
    at org.jobrunr.server.runner.AbstractBackgroundJobRunner$BackgroundJobWorker.run(AbstractBackgroundJobRunner.java:36)
    at org.jobrunr.server.runner.AbstractBackgroundJobRunner.run(AbstractBackgroundJobRunner.java:20)
    at org.jobrunr.server.BackgroundJobPerformer.runActualJob(BackgroundJobPerformer.java:89)
    at org.jobrunr.server.BackgroundJobPerformer.performJob(BackgroundJobPerformer.java:64)
    at org.jobrunr.server.BackgroundJobPerformer.run(BackgroundJobPerformer.java:42)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.InstantiationException: null
    at java.base/jdk.internal.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
    at org.jobrunr.utils.reflection.ReflectionUtils.newInstance(ReflectionUtils.java:154)

Any idea what I'm doing wrong? Is this a problem with the class constructors? As far as I understand it, JobRunr wants a no-args default constructor? (I have a public no-args constructor and an additional protected constructor in both the abstract class above and in the child classes. But I get the same error even if I remove all custom constructors.)


Solution

  • Ronald here - creator of JobRunr.

    The exception you're seeing is because you try to instantiate a Job of type Blubb (mentioned in the json of the job), which is an abstract class. You cannot create instances of Abstract classes hence the exception.

    In your case, I would recommend to look at a framework like Spring and add the @Recurring annotation to the different jobs. This will also make your code probably more readable.

    On top of that, it is important that the JobScheduler instance should be a singleton (for performance reasons).