java 泛型服务实现需要一个bean,但找到了2个bean

ezykj2lf  于 2023-06-20  发布在  Java
关注(0)|答案(1)|浏览(108)

我试图用我想为许多实体实现的方法(findById,findByIdToDto,findAll,findAllToDto)实现一个通用的ReadService,这样我就可以避免一遍又一遍地编写相同的代码。

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ReadService<
        ID,
        ENTITY,
        DTO,
        MAPPER extends BaseMapperToDTO<ENTITY, DTO>,
        REPOSITORY extends JpaRepository<ENTITY, ID>> {

    private final MAPPER mapper;

    private final REPOSITORY repository;

    @Setter
    private Class<ENTITY> entityClass;

    public ENTITY findById(ID id) throws FunctionalException {
        return repository
                .findById(id)
                .orElseThrow(() -> new FunctionalException(
                        "No " + entityClass.getSimpleName() + " found with the id: " + id));
    }

    public DTO findByIdToDto(ID id) throws FunctionalException {
        return mapper.toDto(findById(id));
    }

    public Collection<ENTITY> findAll() {
        return repository.findAll();
    }

    public Collection<DTO> findAllToDto() {
        return mapper.toDtos(findAll());
    }

}

问题是得到了以下错误:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.paulmarcelinbejan.toolbox.web.service.ReadService required a single bean, but 2 were found:
    - continentMapperImpl: defined in file [/projects/HyperBank/HyperBank-Maps/target/classes/com/hyperbank/maps/continent/mapper/ContinentMapperImpl.class]
    - countryMapperImpl: defined in file [/projects/HyperBank/HyperBank-Maps/target/classes/com/hyperbank/maps/country/mapper/CountryMapperImpl.class]

Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

我在Controller中使用ReadService:

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/continent")
public class ContinentRestController {

    private final ReadService<Integer, Continent, ContinentDto, ContinentMapper, ContinentRepository> readService;

    @PostConstruct
    private void injectClass() {
        readService.setEntityClass(Continent.class);
    }

    @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody ContinentDto findById(@PathVariable Integer id) throws FunctionalException {
        return readService.findByIdToDto(id);
    }

}

如果ReadService被参数化,为什么它会创建两个MAPPER bean?每次我想使用它,我都必须用它必须使用的MAPPER参数化它。
解决它的最好办法是什么?
P.S.有那些通用的实现是很重要的,因为它节省了我很多时间。还考虑到我已经实现了创建,更新和删除,它们工作得很好:

private final CreateService<Integer, Continent, ContinentDto, ContinentMapper, ContinentRepository> createService;
private final UpdateService<Integer, Continent, ContinentDto, ContinentMapper, ContinentRepository> updateService;
private final DeleteService<Integer, Continent, ContinentDto, ContinentMapper, ContinentRepository> deleteService;
fiei3ece

fiei3ece1#

我删除了ReadService上的@Service

@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ReadService<
        ID,
        ENTITY,
        DTO,
        MAPPER extends BaseMapperToDTO<ENTITY, DTO>,
        REPOSITORY extends JpaRepository<ENTITY, ID>> {

    private final MAPPER mapper;

    private final REPOSITORY repository;

    private final Class<ENTITY> entityClass;

    public ENTITY findById(ID id) throws FunctionalException {
        return repository
                .findById(id)
                .orElseThrow(() -> new FunctionalException(
                        "No " + entityClass.getSimpleName() + " found with the id: " + id));
    }

    public DTO findByIdToDto(ID id) throws FunctionalException {
        return mapper.toDto(findById(id));
    }

    public Collection<ENTITY> findAll() {
        return repository.findAll();
    }

    public Collection<DTO> findAllToDto() {
        return mapper.toDtos(findAll());
    }

}

我认为在Controller内部使用ReadService不是一个好主意,所以我决定将它移到ContinentService上,然后直接在Controller端使用ContinentService。
我正在ContinentService的构造函数中创建ReadService的示例。

@Service
public class ContinentService {

    public ContinentService(ContinentMapper continentMapper, ContinentRepository continentRepository) {
        readService = new ReadService<>(continentMapper, continentRepository, Continent.class);
    }

    private final ReadService<Integer, Continent, ContinentDto, ContinentMapper, ContinentRepository> readService;

    public ContinentDto findByIdToDto(Integer id) throws FunctionalException {
        return readService.findByIdToDto(id);
    }

    public Collection<ContinentDto> findAllToDto() {
        return readService.findAllToDto();
    }

}

这是控制器

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/country")
public class CountryRestController {

    private final CountryService countryService;

    @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody CountryDto findById(@PathVariable Integer id) throws FunctionalException {
        return countryService.findByIdToDto(id);
    }

    @GetMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Collection<CountryDto> findAll() {
        return countryService.findAllToDto();
    }

}

相关问题