views:

1159

answers:

2

I'm trying to use @Autowired annotation with my generic Dao interface like this:

public interface DaoContainer<E extends DomainObject> {
    public int numberOfItems();
    // Other methods omitted for brevity 
}

I use this interface in my Controller in following fashion:

@Configurable
public class HelloWorld {
    @Autowired
    private DaoContainer<Notification> notificationContainer;

    @Autowired
    private DaoContainer<User> userContainer;

    // Implementation omitted for brevity
}

I've configured my application context with following configuration

<context:spring-configured />
<context:component-scan base-package="com.organization.sample">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
   type="annotation" />
</context:component-scan>
<tx:annotation-driven />

This works only partially, since Spring creates and injects only one instance of my DaoContainer, namely DaoContainer. In other words, if I ask userContainer.numberOfItems(); I get the number of notificationContainer.numberOfItems()

I've tried to use strongly typed interfaces to mark the correct implementation like this:

public interface NotificationContainer extends DaoContainer<Notification> { }
public interface UserContainer extends DaoContainer<User> { }

And then used these interfaces like this:

@Configurable
public class HelloWorld {
    @Autowired
    private NotificationContainer notificationContainer;
    @Autowired
    private UserContainer userContainer;
    // Implementation omitted...
}

Sadly this fails to BeanCreationException:

org.springframework.beans.factory.BeanCreationException: Could not autowire field:   private com.organization.sample.dao.NotificationContainer com.organization.sample.HelloWorld.notificationContainer; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.organization.sample.NotificationContainer] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Now, I'm a little confused how should I proceed or is using multiple Dao's even possible. Any help would be greatly appreciated :)

A: 

It's possible to autowire as many bean as you like.

But when you're using autowiring by type, it can be only one of bean of each interface. Your error message says you have none bean available in the Spring container of given interface.

A solution:

Your missing DAO implementations:

@Repository
public class NotificationContainerImpl implements NotificationContainer {}

@Repository
public class UserContainerImpl implements UserContainer {}

Your service class:

@Service
public class HelloWorld {
    @Autowired
    private NotificationContainer notificationContainer;
    @Autowired
    private UserContainer userContainer;
    // Implementation omitted...
}

I replaced the @Configurable annotation with @Service. @Configurable is used together with AspectJ and is not what you want here. You must use @Component or a specialization of it like @Service.

Also remember to have all your Spring components inside your com.organization.sample package to enable the Spring container to find them.

I hope this helps!

Espen
+1  A: 

Ok, I think I've found a fairly reasonable solution for this puzzle. One way of dealing with this would be creating interface and implementations for each and every entity in my domain model (as Espen pointed out in his answer earlier). Now, consider having hundreds of entities and respectively hundreds of implementations. That wouldn't feel right, would it?

I've discarded strongly typed sub-interfaces and I'm using generic interface instead:

@Service // Using @Service annotation instead @Configurable as Espen pointed out
public class HelloWorld {
    @Autowired
    private DaoContainer<Notification> notificationContainer;

    @Autowired
    private DaoContainer<User> userContainer;

    // Implementation omitted
}

Implementation for my DaoContainer interface would look something like this:

@Repository
public class DaoContainerImpl<E extends DomainObject> implements DaoContainer<E> {

    // This is something I need in my application logic
    protected Class<E> type;

    public int getNumberOfItems() {
       // implementation omitted
    }
    // getters and setters for fields omitted

}

And finally application context:

<context:spring-configured />
<context:component-scan base-package="com.organization.sample">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
    type="annotation" />
</context:component-scan>

<bean class="com.organization.sample.dao.DaoContainerImpl" id="userContainer">
    <property name="type" value="com.organization.sample.domain.DiaryUser" />
</bean>
<bean class="com.organization.sample.dao.DaoContainerImpl" id="notificationContainer">
    <property name="type" value="com.organization.sample.domain.DiaryNotification" />
</bean>

So basically I couldn't get pure generic autowiring to work, but this solution works for me (at least for now) :)

Peders
I know this is an old issue, but your solution is quite similar to using marker interfaces as described in http://stackoverflow.com/questions/502994/spring-ioc-and-generic-interface-type/503011#503011. I suppose it comes up to a personal preference to pollute either the Spring configuration file or the java source tree.
Tuukka Mustonen