mercredi 29 décembre 2021

Spring can not pick a JpaRepository that extends a generic interface

Problem description

I have a couple of controllers that look like this:

@RequestMapping("InkUsage")
@RestController
public class InkUsageController extends BaseController<InkUsageDto> {
    public InkUsageController(BaseService<InkUsageDto> service) {
        super(service);
    }
}

@RequestMapping("MediaCategoryUsage")
@RestController
public class MediaCategoryUsageController extends BaseController<MediaCategoryUsageDto> {
    public MediaCategoryUsageController(BaseService<MediaCategoryUsageDto> service) {
        super(service);
    }
}

Both of them extend a BaseController class that looks like this:

@AllArgsConstructor
@RestController
public class BaseController<T> {
    private BaseService<T> service;

    @PostMapping
    public ResponseEntity<List<T>> getAll(){...}
    

    ...
}

The BaseService looks like this:

@AllArgsConstructor
@Service
public class BaseService<T> {
    private BaseRepository<T> repository;
    
    public List<T> getAll() {...}

    ...
}

The BaseRepository is just an interface that JpaRepositories extend:

public interface BaseRepository<T> {
    List<T> getAllAggregated(String dateFormat);
    List<T> getAllNonAggregated(String dateFormat);
    ...
}

This is how one of the JpaRepositories look like:

@Repository("InkUsageRepository")
public interface InkUsageRepository extends JpaRepository<InkUsageEntity, Long>,
        BaseRepository<InkUsageDto> {
    @Query("SELECT new api.coloradodashboard.inkusage.InkUsageDto(DATE_FORMAT(i.date, :dateFormat) AS formatted_date, sum(i.cyanLitresUsed), sum(i.magentaLitresUsed), sum(i.yellowLitresUsed), sum(i.blackLitresUsed)) " +
            "FROM InkUsageEntity i " +
            "GROUP BY formatted_date " +
            "ORDER BY formatted_date ASC")
    List<InkUsageDto> getAllAggregated(@Param("dateFormat") String dateFormat);

    ...
}

The problem is that when I run the application Spring complains that BaseService requires a single bean of type BaseRepository but it found 2, which is true. However, both implementations use a different class as a generic type(one uses BaseRepository<InkUsageDto>, for example) and it seems Spring can not pick up that.

Question

How can I tell Spring to use the proper repository?

What I already tried

  • Spring suggests using a @Primary qualifier, but that will not solve my problem because I plan on having 5 JpaRepositories extending BaseRepository.
  • I tried passing the repository into the BaseController constructor, then immediately create new BaseService(repository) in the BaseController constructor but Spring complains it can not find a bean of type BaseRepository.
  • I checked whether passing a variable into a @Qualifier is possible, but they only take constant expressions.
  • A solution that will probably work but I avoid is to create BaseRepository class implementation for each repository, but that means having 5 implementations with the same code except the repository field.

Aucun commentaire:

Enregistrer un commentaire