Reputation: 762
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
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