앞에서 만들었던 GenericService에는 버그가 있었습니다. 저걸 적용한 뒤에 애플리케이션을 실행해보니까 제대로 동작하지 않더군요. 제길... 테스트를 만들껄.. 후회했습니다.  대부분의 코드가 단순 위임이라고 해서 테스트를 무시하면 안됩니다. 사실 Service 코드에서 하는 일은 DAO로 단순 위임하는 코드밖에 없어 보이지만 그 이상으로 복잡합니다.

그 중 하나가 DAO를 주입 받는 일이죠. '주입 하는 일'도 아니고 '주입 받는 일'을 무시했네요. 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/testContext.xml")
@Transactional
public class CodeServiceImplTest {
    @Autowired CodeService codeService;
    @Test
    public void di(){
        assertThat(codeService, is(notNullValue()));
    }
}
초간단 테스트를 만듭니다. codeService 자체를 DI 받을 수 있는지... 빈 팩토리에서 저 빈을 만들 수 있는지 확인합니다.
에러가 납니다.. ㅋ
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [osaf.dao.GenericDao] is defined: expected single matching bean but found 2: [codeDaoImpl, memberDaoImpl]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:779)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:686)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
... 43 common frames omitted
핵심적인 에러 메시지는 이 부분이다. 뭔 내용인지는 해설하지 않겠습니다. 퀴즈 삼아 맞춰보시죠.
public class GenericServiceImpl<D extends GenericDao<E, S>, E, S> implements GenericService<E, S> {
    @Autowired ApplicationContext applicationContext;
    private Class<D> daoClass;
    GenericDao<E, S> dao;
    public GenericServiceImpl(){
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        Type type = genericSuperclass.getActualTypeArguments()[0];
        if (type instanceof ParameterizedType) {
            this.daoClass = (Class<D>) ((ParameterizedType) type).getRawType();
        } else {
            this.daoClass = (Class<D>) type;
        }
    }
    public void add(E e) {
        dao.add(e);
    }
    public List<E> list(PageParam pageParam, S s) {
        pageParam.initCurrentPageInfosWith(dao.totalSize(s));
        return dao.list(pageParam, s);
    }
    public E getById(int id) {
        return dao.getById(id);
    }
    public void update(E e) {
        dao.update(e);
    }
    public void deleteBy(int id) {
        dao.deleteBy(id);
    }
    @PostConstruct
    public void setUpDao(){
        this.dao = this.applicationContext.getBean(daoClass);
    }
}
GenericService 구현체를 위와같이 수정했습니다. dao를 생성자에서 바로 연결하지 않고 @PostConstruct에서 연결한 것도 설명하지 않겠습니다. 요것도 심심하신 분 계시면 퀴즈 삼아 맞춰보시기 바랍니다.
퀴즈1. 에러가 난 원인은?
퀴즈2. 왜 생성자에서 applicationContext.getBean(daoClass)를 하면 안된느가?