Ronny Shibley
Ronny Shibley

Reputation: 2155

How to Autowire an interface or abstract class without implementation in Spring

I need to Autowire an interface without an implementation, somehow like the @Repository tag functionality.

@QueryRepository
public interface EddressBookDao {

    @ReportQuery
    public List<EddressBookDto> loadEddresses(@EqFilter("id") Long id);

}

@Autowired
private EddressBookDao eddressBookDao;

Result result = eddressBookDao.loadEddresses(1L);

I'm thinking of somehow detecting my @QueryRepository Annotation during ClassPathScan and injecting a Proxy of EddressBookDao object on eddressBookDao Autowire.

Right now I am achieving this functionality in a cumbersome way using the following:

@Autowired
public ReportQueryInvocationHandler reportQuery;

private EddressBookDao eddressBookDao;

public EddressBookDao eddressBook(){
    if (eddressBookDao == null) eddressBookDao = reportQuery.handle(EddressBookDao.class);
    return eddressBookDao;
}

Here is my Handler creating the Proxy:

@Component
public class ReportQueryInvocationHandler implements InvocationHandler {
public <T> T handle(Class<T> clazz){
    return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, this);
}

public Object invoke(Object proxy, Method method, Object[] args) throws NoSuchFieldException, IllegalAccessException {

    Type returnType = method.getReturnType();

    Annotation[][] annotations = method.getParameterAnnotations();
    Report report = dao.createReport();

    for (int i = 0; i < args.length; i++) {
        Object argument = args[i];
        Annotation[] annotationList = annotations[i];
        if (annotationList.length == 0) continue;

        for (Annotation annotation : annotationList) {
            Class<? extends Annotation> annotationType = annotation.annotationType();
            String path = null;

            if (annotationType.equals(EqFilter.class)) {
                path = ((EqFilter) annotation).value();
                report.equalsFilter(path, argument);
                break;
            } 
        }
    } 
    return report.list((Class<?>) returnType);
}

And here is how I'm calling my it:

List<EddressBookDto> addressed = dao.eddressBook().loadEddresses(8305L);

All I want is to avoid writing this code

private EddressBookDao eddressBookDao;
public EddressBookDao eddressBook(){
    if (eddressBookDao == null) eddressBookDao = reportQuery.handle(EddressBookDao.class);
    return eddressBookDao;
}

And write this instead:

@Autowired
private EddressBookDao eddressBookDao;

Upvotes: 1

Views: 1191

Answers (1)

Jens Schauder
Jens Schauder

Reputation: 81907

Spring Data doesn't autowire interfaces although it might look this way. It registers factories which produce proxies implementing the interface.

To do something similar you have to implement the FactoryBean interface. See the JavaDoc for details. There are also tutorials available.

Upvotes: 1

Related Questions