QuirkyBit
QuirkyBit

Reputation: 762

Raw use of parameterized class 'ABC'

I have the following interface:

public interface AsynchronousJobRunner<T extends AsynchronousJob> extends Runnable {
    public void kill();
    public void addJobExecutionListener(JobExecutionListener listener);
    public void removeJobExecutionListener(JobExecutionListener listener);
    public AsynchronousJobRunner withJob(T job);
}

AsynchronousJob is an abstract class that can be extended to represent other jobs with a following abstract method:

public abstract class AsynchronousJob implements JSONSerializable, HasId {...}

    /**
     * Returns the class of the {@link AsynchronousJobRunner} that runs this type of job.
     * @return The appropriate class of the job runner for this class.
     */
    public abstract Class<? extends AsynchronousJobRunner> jobRunnerClass();

I also have the following ExportJob that is extending the base class and has the following signature and method:

public class ExportJobRunner extends BaseJobRunner<ExportJob> { ...}

    @Override
    public Class<? extends AsynchronousJobRunner> jobRunnerClass() {
        return ExportJobRunner.class;
    }

Both jobRunnerClass() methods have the Raw use of parameterized class 'AsynchronousJobRunner' warning.

The easy solution to make the warning go away are:

public abstract Class<? extends AsynchronousJobRunner<?>> jobRunnerClass();


@Override
public Class<? extends AsynchronousJobRunner<?> jobRunnerClass() {
    return ExportJobRunner.class;
}

But what would be the right solution and why/how?

EDIT:

I've ended up simply changing the code of the interface to:

public interface AsynchronousJobRunner<T extends AsynchronousJob<T>> extends Runnable {
    void kill();
    void addJobExecutionListener(JobExecutionListener listener);
    void removeJobExecutionListener(JobExecutionListener listener);
    AsynchronousJobRunner<T> withJob(T job);
}

Changes to AsynchronousJob class:

public abstract class AsynchronousJob<T> implements JSONSerializable, HasId { ...
 /**
     * Returns the class of the {@link AsynchronousJobRunner} that runs this type of job.
     * @return The appropriate class of the job runner for this class.
     */
    public abstract Class<? extends AsynchronousJobRunner<? extends AsynchronousJob<T>> jobRunnerClass();

}

ExportJob class:

public public class ExportJob extends AsynchronousJob<ExportJob> {...
    @Override
    public Class<? extends AsynchronousJobRunner<? extends AsynchronousJob<ExportJob>>> jobRunnerClass() {
        return ExportJobRunner.class;
    }
}

And the ExportJobRunner class remained unchanged.

I also forgot to mention that there is some injection magic going on because the jobs are serialized to the database:

    /**
     * Instantiates an {@link AsynchronousJobRunner} instance for the provided job.
     * <p>
     * In order for the creation of the runner to succeed, the {@link AsynchronousJob#jobRunnerClass()}
     * method of the job must specify the appropriate class for its runner.
     *
     * @param job job to create runner for
     * @return job runner configured for the specified {@code job} parameter
     */
    private <T extends AsynchronousJob<T>> AsynchronousJobRunner<T> createJobRunner(T job) {
        return ((AsynchronousJobRunner<T>)injector.getInstance(job.jobRunnerClass())).withJob(job);
    }

I've accepted @Andrew Vershinin answer as he got me on the right track of thoughts.

Upvotes: 3

Views: 4507

Answers (1)

Andrew Vershinin
Andrew Vershinin

Reputation: 1968

I think, you could go with this recursive declaration of AsynchronousJob:

public abstract class AsynchronousJob<T extends AsynchronousJob<T>> 
    implements JSONSerializable, HasId {

    public abstract Class<? extends AsynchronousJobRunner<T>> jobRunnerClass();
//...
}

Don't forget to update AsynchronousJobRunner definition accordingly:

public interface AsynchronousJobRunner<T extends AsynchronousJob<T>> //...

Then, in you job class you can use the class itself in the return type:

public class ExportJob extends AsynchronousJob<ExportJob> {
    @Override
    public Class<? extends AsynchronousJobRunner<ExportJob>> jobRunnerClass() {
        return ExportJobRunner.class;
    }
}

This way you ensure type consistency: a job of type T returns runner types, which run jobs of such type - you cannot ensure this with using ? extends AsynchronousJob in the jobRunnerClass signature, since you could return any runner type and it would compile.

Upvotes: 2

Related Questions