2

Im trying to set up a h2 database using jpa/jdbc, after creating an implemntation for a query interface using jpa as opposed to jdbc i am now getting the error:

Parameter 0 of constructor in com.nsa.charitystarter.service.CharityQueries required a single bean, but 2 were found: - charityRepoJDBC: defined in file [C:\Users\V La Roche\Desktop\assessment-1-starter\out\production\classes\com\nsa\charitystarter\data\CharityRepoJDBC.class] - charityRepoJPA: defined in null

Im unsure as to what has gone wrong and am not really sure where to go from here, i havent been able to find many people with a similar issue to me online.

My implementation using jdbc

@Repository
public class CharityRepoJDBC implements CharityRepository {

    private JdbcTemplate jdbc;
    private RowMapper<Charity> charityMapper;

    @Autowired
    public CharityRepoJDBC(JdbcTemplate aTemplate) {
        jdbc = aTemplate;


        charityMapper = (rs, i) -> new Charity(
                rs.getLong("id"),
                rs.getString("name"),
                rs.getString("registration_id"),
                rs.getString("acronym"),
                rs.getString("purpose")
        );
    }

    @Override
    public List<Charity> findCharityBySearch(String searchTerm) {

        String likeSearch = "%" + searchTerm + "%";

        return jdbc.query(
                "select id, acronym, name, purpose, logo_file_name, registration_id  " +
                        "from charity " +
                        "where concat(name, acronym, purpose, registration_id) like ?",
                new Object[]{likeSearch},
                charityMapper);
    }

    @Override
    public Optional<Charity> findById(Long id) {
        return Optional.of(
                jdbc.queryForObject(
                        "select id, acronym, name, purpose, logo_file_name, registration_id  from charity where id=?",
                        new Object[]{id},
                        charityMapper)
        );
    }
}

Charity finder implementation:

@Service
public class CharityQueries implements CharityFinder {
    private CharityRepository charityRepository;


    public CharityQueries(CharityRepository repo) {
        charityRepository = repo;
    }

    public Optional<Charity> findCharityByIndex(Integer index) {
        return charityRepository.findById(index.longValue());
    }

    public List<Charity> findCharityBySearch(String searchTerm) {

        return charityRepository.findCharityBySearch(searchTerm);
    }
}

CharityFinder interface

public interface CharityFinder {

    public Optional<Charity> findCharityByIndex(Integer index);

    public List<Charity> findCharityBySearch(String searchTerm);

}

error log :

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

Description:

Parameter 0 of constructor in com.nsa.charitystarter.service.CharityQueries required a single bean, but 2 were found:
    - charityRepoJDBC: defined in file [C:\Users\V La Roche\Desktop\assessment-1-starter\out\production\classes\com\nsa\charitystarter\data\CharityRepoJDBC.class]
    - charityRepoJPA: defined in null


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


Process finished with exit code 0
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
V La Roche
  • 21
  • 1
  • 1
  • 3

3 Answers3

1

You have following definition currently,

@Repository
public class CharityRepoJDBC implements CharityRepository {

And you are injecting CharityRepository in your service layer CharityQueries

@Service
public class CharityQueries implements CharityFinder {
    private CharityRepository charityRepository;

Hence when you deploy your application the container is confused which bean you are trying to autowire into the service.

By default spring autowires by type and hence by that there are 2 beans which are qualified to be injected by spring container.

  1. CharityRepository itself and other
  2. CharityRepoJDBC

So you need to either explicitly tell container which bean you are trying to autowire in this case.

So you can try adding qualifiers as below to solve the issue.

@Service
    public class CharityQueries implements CharityFinder {
        @Qualifier("CharityRepoJDBC")
        private CharityRepository charityRepository;

and at the same time modify your CharityRepoJDBC to be,

@Repository(value = "CharityRepoJDBC")
public class CharityRepoJDBC implements CharityRepository {
ScanQR
  • 3,740
  • 1
  • 13
  • 30
  • Sadly that doesnt help, im confused as one of the beans its confused about using doesnt actually exist anymore within my project. I deleted the class it was contained in but for soem reason is still causing the error – V La Roche Nov 03 '19 at 10:22
1

You seem to have the Spring Data JDBC starter on the classpath and the Spring Data JPA starter.

Spring Data JDBC has a bug which causes it to produce implementation for repository interfaces even if it shouldn't, thus you end up with one implementation from JPA and another one from JDBC.

If you really want to use Spring Data JDBC and Spring Data JPA you can limit the @EnableJdbcRepositories and @EnableJpaRepositories annotations using the include and exclude filters.

But from your code and the tags you used I suspect you might be not at all interested in Spring Data Jdbc but only in Spring Jdbc. If this is the case look for a dependency spring-boot-starter-data-jdbc and change it to spring-boot-starter-jdbc.

In case all this Spring (Data) JDBC/JPA confuse you this question and its answers might help: Spring Data JDBC / Spring Data JPA vs Hibernate

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
0

I solved it putting @Primary annotation in the repository interface. In your case it would be the following:

@Primary
public interface CharityFinder {

    public Optional<Charity> findCharityByIndex(Integer index);

    public List<Charity> findCharityBySearch(String searchTerm);

}
Thalys Menezes
  • 345
  • 1
  • 4
  • 17