#Spring 4: Generic type injection
If you have used JBoss Seam 2 and the later CDI/JBoss Seam 3, you could be impressed of producing generic type bean by the @Factory
(in JBoss Seam 2) or @Produces
annotations.
In CDI projects, you can produces a CDI bean simply.
<pre> @Produces List<Conference> availableConfs; </pre>
And inject it in other beans as needed.
<pre> @Inject List<Conference> availableConfs; </pre>
But unfortunately, generic type bean injection dose not work in Spring for a long time.
Spring 4 brings partial features of these.
Reuse the former examples.
Conference
and Signup
are JPA entities, and ConferenceRepository
and SignupRepository
are their JpaRepository
implementations.
<pre> @Repository public interface ConferenceRepository extends JpaRepository<Conference, Long> { Conference findBySlug(String slug); } @Repository public interface SignupRepository extends JpaRepository<Signup, Long> { } </pre>
Inject them via JpaRepository
interfaces.
<pre> @Autowired JpaRepository<Conference, Long> conferenceRepository; @Autowired JpaRepository<Signup, Long> signupRepository; </pre>
Some test codes.
<pre> @Before @org.springframework.transaction.annotation.Transactional public void beforeTestCase() { log.debug("===================before test====================="); Conference conf=new Conference("Spring One 2014", new Date()); Signup user1=new Signup("Hantsy", "Bai", "hantsy@tom.com"); Signup user2=new Signup("Tom", "tom", "hantsy@tom.com"); user1.setConference(conf); user2.setConference(conf); conf.getSignups().add(user1); conf.getSignups().add(user2); conferenceRepository.save(conf); } @After @org.springframework.transaction.annotation.Transactional public void afterTestCase() { log.debug("===================after test====================="); signupRepository.deleteAll(); conferenceRepository.deleteAll(); } @Test public void testGenericTypeInjection() { assertTrue(conferenceRepository!=null); assertTrue(signupRepository!=null); assertTrue(conferenceRepository.findAll().size()==1); assertTrue(signupRepository.findAll().size()==2); } </pre>
The parameterized type of JpaRepository
worked as a form of qualifiers to identify different implementation classes.
But unfortunately, if you create a generic type bean via @Bean
annotation, and inject it in another bean directly, it will throw an exception which complains the bean is not found.
<pre> @Configuration public class AppConfig { @Bean public List<Conference> availableConfs() { return Arrays.asList(new Conference("JavaOne", new Date()), new Conference("SpringOne", new Date()),new Conference("SpringTwo", new Date())); } } </pre>
The following codes will throw an exception.
<pre> @Autowired List<Conference> availableConferences; </pre>
But it can be fetched from ApplicaitonContext
.
<pre> @Test public void testConfs2() { List<Conference> confs2=(List<Conference>)ctx.getBean("availableConferences"); Assert.assertTrue(confs2!=null); Assert.assertTrue(confs2.size()==3); } </pre>
As you see, Spring still does not include type-safe bean producing and injection for generic type bean as CDI provides.