0
votes

I have the following situation in a Spring 4.0 (using Spring Boot) environment:

Mapping interface:

public interface EntityModelMapper<ENTITY extends AbstractEntity, MODEL extends AbstractModel>{ }

Mapping implementation:

@Component
public class ProductEntityModelMapper implements EntityModelMapper<Product, ProductModel>{ }

Service:

public interface CrudService<MODEL extends AbstractModel>{ }

And I want to do an abstract superclass service like this:

public abstract AbstractCrudService<ENTITY extends AbstractEntity, MODEL extends AbstractModel> implements CrudService<MODEL>{

@Autowired
private EntityModelMapper<ENTITY, MODEL> mapper;

  public EntityModelMapper<ENTITY, MODEL> getMapper(){ 
      return mapper; 
  }
}

So I can have implementations likes this:

@Service
public ProductCrudService extends AbstractCrudService<Product, ProductModel>{

  public void someMethod(Product product){
    ProductModel model = getMapper().map(product);
  }

}

But Spring tells me it can't find qualifying beans of EntityModelMapper to inject in the service classes. Is this scenario possible and I'm doing something wrong or am I pushing the limits of Spring's dependecy injection?

Stacktrace:

org.springframework.beans.factory.BeanCreationException:
 Error creating bean with name 'productCrudService':
 Injection of autowired dependencies failed;
 nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field:
 private com.flycatcher.seagull.mapper.EntityModelMapper 
com.flycatcher.seagull.facade.service.crud.AbstractCrudService.mapper;
 nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
 No qualifying bean of type [com.flycatcher.seagull.mapper.EntityModelMapper] 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)}
1

1 Answers

1
votes

According to this: https://spring.io/blog/2013/12/03/spring-framework-4-0-and-java-generics It is possible since Spring 4.0 version.

That didn't work me either. (same exception and Im using 4.2.3). So try to upgrade to the latest version - 4.2.6.

If it still doesn't work, you can instead use the @Qualifier annotation and autowire EntityModelMapper as an interface in your sub-class, and define getMapper as abstract:

  @Component
  @Qualifier("productEntityModelQualifier")
  public class ProductEntityModelMapper implements EntityModelMapper<Product, ProductModel>{ }

and then in ProductCrudService:

@Service
public ProductCrudService extends AbstractCrudService<Product, ProductModel>{

  @Autowired
  @Qualifier("productEntityModelQualifier")
  EntityModelMapper<Product, ProductModel> mapper;

  @Override
  protected EntityModelMapper<Product, ProductModel> getMapper(){return mapper;}

  public void someMethod(Product product){
    ProductModel model = getMapper().map(product);
  }

}