Ulyses Evans
Ulyses Evans

Reputation: 63

Error that 2 parameter(s) provided but only 1 parameter(s) present in query

Hi, I have an error and i dont know how to fix it. I see other similar issues here, but they haven't been useful to me. So, I hope you could help me.

I have this DAO:

public interface GoalDao extends PagingAndSortingRepository<Goal, Long> {

    Slice<Goal> findByCompanyId(Long companyId, PageRequest of);

}

And this method in my service:

    @Override
    @Transactional(readOnly = true)
    public Block<Goal> findCompanyGoals(Long userId, Long companyId, int page, int size)
            throws InstanceNotFoundException, PermissionException {
        Company company = permissionChecker.checkCompanyExistsAndBelongsToUser(companyId, userId);

        Slice<Goal> slice = goalDao.findByCompanyIdOrderByIdDesc(company.getId(), PageRequest.of(page, size));
        return new Block<>(slice.getContent(), slice.hasNext());
    }

So, this line:

    Slice<Goal> slice = goalDao.findByCompanyIdOrderByIdDesc(company.getId(), PageRequest.of(page, size));

It is throwing me the following error:

testException = org.springframework.dao.InvalidDataAccessApiUsageException: At least 2 parameter(s) provided but only 1 parameter(s) present in query.; nested exception is java.lang.IllegalArgumentException: At least 2 parameter(s) provided but only 1 parameter(s) present in query.

Thank you.

Upvotes: 0

Views: 4632

Answers (2)

Mohamed AMAZIRH
Mohamed AMAZIRH

Reputation: 1217

To add more information to @Bisha's answer : It doesn't work with PageRequest because Spring accepts only two types (in a method signature) to apply sorting and pagination : Pageable & Sort.

Pageable and Sort are considered special parameters that are handled diffrently by Spring (It won't try to bind them to the query).

In your question's example, Spring treats your PageRequest method parameter (in the method signature) as a normal method parameter (even if it implements Pageable) and tries to bind it to the final query hence the error message.

You can see where the check is done in Spring's source code (spring-data-jpa:2.4.10 and spring-data-commons:2.4.10):

In org.springframework.data.jpa.repository.query.ParameterBinderFactory, Spring checks if a parameter should be bound to the query by calling parameter.isBindable :

private static List<ParameterBinding> getBindings(JpaParameters parameters) {

    List<ParameterBinding> result = new ArrayList<>();
    int bindableParameterIndex = 0;
    
    for (JpaParameter parameter : parameters) {
    
        if (parameter.isBindable()) {
           result.add(new ParameterBinding(++bindableParameterIndex));
        }
    }
    
    return result;
}

isBindable in (org.springframework.data.jpa.repository.query.JpaParameters) will ultimately call isBindable in org.springframework.data.jpa.repository.query.Parameter:

public boolean isBindable() {
    return !isSpecialParameter();
}

isSpecialParameter will return false when the parameter type is PageRequest which means isBindable will true and Spring will try to bind the parameter to the query instead of using it for pagination.

isSpecialParameter will return false because (in your case) the list TYPES doesn't contain the class PageRequest :

public boolean isSpecialParameter() {
    return isDynamicProjectionParameter || TYPES.contains(parameter.getParameterType());
}

TYPES is initialized in a static block in org.springframework.data.repository.query.Parameter and has (in your case) only two values Pageable and Sort :

static {

    List<Class<?>> types = new ArrayList<>(Arrays.asList(Pageable.class, Sort.class));

    // consider Kotlin Coroutines Continuation a special parameter. That parameter is synthetic and should not get
    // bound to any query.

    ClassUtils.ifPresent("kotlin.coroutines.Continuation", Parameter.class.getClassLoader(), types::add);

    TYPES = Collections.unmodifiableList(types);
}

Upvotes: 3

Bisha
Bisha

Reputation: 56

In your GoalDao try using Pageable instead of PageRequest. So it will look like this:

public interface GoalDao extends PagingAndSortingRepository<Goal, Long> {

    Slice<Goal> findByCompanyId(Long companyId, Pageable pageable);

}

Not sure why, but it worked for me and I hope it will help you too.

Upvotes: 4

Related Questions