Spring 4 included major enhancements to generic type resolution, but I'm having trouble with autowiring a generic type when the type argument is parameterized on the containing bean class.
I am needing to track the status of jobs submitted to an outside service, and I want to create an entry for each job when it starts and clear or update it when I receive postbacks. I generally try to keep my persistence strategy separated from the service interface, so I have an interface JobStatus
and a Spring Data Mongo class MongoJobStatus implements JobStatus
. Since a job might fail before the outside service gets a chance to assign it an ID (e.g., an HTTP 502), I need to pass the JobStatus
back to the service to identify for updates:
interface JobStatusService<S extends JobStatus> {
S beginJob(...);
S updateJobStatus(S targetJob, Status newStatus);
void finishJob(S targetJob);
}
Accordingly, my Spring controller that handles firing off the jobs and recording the postbacks looks like this; the controller class carries a type parameter so that I can store the new status object and pass it back to the service:
@Controller
public class JobController<JS extends JobStatus> {
@Autowired JobStatusService<JS> jobService;
... handler method ...
JS status = jobService.createJob(info, goes, here);
// submit job via HTTP
jobService.updateJobStatus(status, Status.PROCESSING);
...
}
My MongoDB-backed implementation looks like this:
public class MongoJobStatusService implements JobStatusService<MongoJobStatus> {
MongoJobStatus beginJob(...) {...}
MongoJobStatus updateJobStatus(MongoJobStatus job, Status newStatus) {...}
}
When I try to launch, the Spring context fails with NoSuchBeanDefinitionException
for JobStatusService
. I have confirmed that if I set required=false
, the MongoJobStatusService
bean is properly component-scanned and installed in the context, but Spring doesn't seem to be able to understand that the class implements that parameterized generic interface.
Is there any way to specify to Spring that I need a bean implementing a generic interface with a type argument that is parameterized at the containing bean level instead of embedded as a literal type argument on the field level?
Try to add:
And specify the name of
MongoJobStatusService
bean.The Spring container does not appear to be able to solve for acceptable type parameters on the controller class, but it can solve for the injected field if those type parameters are supplied explicitly. I have been able to suboptimally work around the problem by subclassing the controller class with a literal type:
I have opened a JIRA issue for this and have a minimal example on GitHub.
In fact Spring doesn't found matching Bean, maybe cause JobStatusService is to high level.
Try to put an other interface between MongoJobStatusService and JobStatusService, like this
I'had the same problem (Spring autowire trouble with generic parameter), and I solved it like that ...