DATAJPA-461 - Fixed regression in parameter binding of arrays.

Enhanced binding of parameters in StringQueryParameterBinder to be able to deal with situations where a parameter value has to be converted to be correctly bound e.g. for parameter values in IN-expressions.

We now only convert array values to collections if the value is to be bound in the context of an IN-parameter. Previously we erroneously always converted an array value to a collection value which lead to problems if an array value was meant to be used "as-is" e.g. in cases where an user wants to query for a certain byte[].

Original pull request: #56.
This commit is contained in:
Thomas Darimont
2014-02-10 15:53:18 +01:00
committed by Oliver Gierke
parent c85caf00d4
commit f8b0917c90
8 changed files with 502 additions and 179 deletions

View File

@@ -1212,6 +1212,34 @@ public class UserRepositoryTests {
assertThat(result, hasItem(firstUser));
}
/**
* @DATAJPA-461
*/
@Test
public void customFindByQueryWithPositionalVarargsParameters() {
flushTestUsers();
Collection<User> result = repository.findByIdsCustomWithPositionalVarArgs(firstUser.getId(), secondUser.getId());
assertThat(result, hasSize(2));
assertThat(result, hasItems(firstUser, secondUser));
}
/**
* @DATAJPA-461
*/
@Test
public void customFindByQueryWithNamedVarargsParameters() {
flushTestUsers();
Collection<User> result = repository.findByIdsCustomWithNamedVarArgs(firstUser.getId(), secondUser.getId());
assertThat(result, hasSize(2));
assertThat(result, hasItems(firstUser, secondUser));
}
private Page<User> executeSpecWithSort(Sort sort) {
flushTestUsers();

View File

@@ -19,7 +19,7 @@ import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.data.jpa.repository.query.StringQuery.LikeBinding;
import org.springframework.data.jpa.repository.query.StringQuery.LikeParameterBinding;
import org.springframework.data.repository.query.parser.Part.Type;
/**
@@ -29,33 +29,33 @@ public class LikeBindingUnitTests {
@Test(expected = IllegalArgumentException.class)
public void rejectsNullName() {
new LikeBinding(null, Type.CONTAINING);
new LikeParameterBinding(null, Type.CONTAINING);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsEmptyName() {
new LikeBinding("", Type.CONTAINING);
new LikeParameterBinding("", Type.CONTAINING);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullType() {
new LikeBinding("foo", null);
new LikeParameterBinding("foo", null);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsInvalidType() {
new LikeBinding("foo", Type.SIMPLE_PROPERTY);
new LikeParameterBinding("foo", Type.SIMPLE_PROPERTY);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsInvalidPosition() {
new LikeBinding(0, Type.CONTAINING);
new LikeParameterBinding(0, Type.CONTAINING);
}
@Test
public void setsUpInstanceForName() {
LikeBinding binding = new LikeBinding("foo", Type.CONTAINING);
LikeParameterBinding binding = new LikeParameterBinding("foo", Type.CONTAINING);
assertThat(binding.hasName("foo"), is(true));
assertThat(binding.hasName("bar"), is(false));
@@ -67,7 +67,7 @@ public class LikeBindingUnitTests {
@Test
public void setsUpInstanceForIndex() {
LikeBinding binding = new LikeBinding(1, Type.CONTAINING);
LikeParameterBinding binding = new LikeParameterBinding(1, Type.CONTAINING);
assertThat(binding.hasName("foo"), is(false));
assertThat(binding.hasName(null), is(false));
@@ -83,12 +83,12 @@ public class LikeBindingUnitTests {
assertAugmentedValue(Type.ENDING_WITH, "%value");
assertAugmentedValue(Type.STARTING_WITH, "value%");
assertThat(new LikeBinding(1, Type.CONTAINING).prepare(null), is(nullValue()));
assertThat(new LikeParameterBinding(1, Type.CONTAINING).prepare(null), is(nullValue()));
}
private static void assertAugmentedValue(Type type, Object value) {
LikeBinding binding = new LikeBinding("foo", type);
LikeParameterBinding binding = new LikeParameterBinding("foo", type);
assertThat(binding.prepare("value"), is(value));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2013 the original author or authors.
* Copyright 2008-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@ import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@@ -223,18 +222,18 @@ public class ParameterBinderUnitTests {
}
/**
* @see DATAJPA-415
* @see DATAJPA-461
* @throws Exception
*/
@Test
public void shouldAllowBindingOfVarArgs() throws Exception {
public void shouldAllowBindingOfVarArgsAsIs() throws Exception {
Method method = SampleRepository.class.getMethod("validWithVarArgs", Integer[].class);
JpaParameters parameters = new JpaParameters(method);
Integer[] ids = new Integer[] { 1, 2, 3 };
new ParameterBinder(parameters, new Object[] { ids }).bind(query);
verify(query).setParameter(eq(1), eq(Arrays.asList(1, 2, 3)));
verify(query).setParameter(eq(1), eq(ids));
}
public SampleEntity findByEmbeddable(SampleEmbeddable embeddable) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,9 @@ import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import org.springframework.data.jpa.repository.query.StringQuery.LikeBinding;
import org.springframework.data.jpa.repository.query.StringQuery.InParameterBinding;
import org.springframework.data.jpa.repository.query.StringQuery.LikeParameterBinding;
import org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding;
import org.springframework.data.repository.query.parser.Part.Type;
/**
@@ -41,13 +43,13 @@ public class StringQueryUnitTests {
String source = "select from User u where u.firstname like :firstname";
StringQuery query = new StringQuery(source);
assertThat(query.hasLikeBindings(), is(true));
assertThat(query.hasParameterBindings(), is(true));
assertThat(query.getQueryString(), is(source));
List<LikeBinding> bindings = query.getLikeBindings();
List<ParameterBinding> bindings = query.getParameterBindings();
assertThat(bindings, hasSize(1));
LikeBinding binding = bindings.get(0);
LikeParameterBinding binding = (LikeParameterBinding) bindings.get(0);
assertThat(binding.getType(), is(Type.LIKE));
assertThat(binding.hasName("firstname"), is(true));
}
@@ -57,18 +59,18 @@ public class StringQueryUnitTests {
StringQuery query = new StringQuery("select u from User u where u.firstname like %?1% or u.lastname like %?2");
assertThat(query.hasLikeBindings(), is(true));
assertThat(query.hasParameterBindings(), is(true));
assertThat(query.getQueryString(), is("select u from User u where u.firstname like ?1 or u.lastname like ?2"));
List<LikeBinding> bindings = query.getLikeBindings();
List<ParameterBinding> bindings = query.getParameterBindings();
assertThat(bindings, hasSize(2));
LikeBinding binding = bindings.get(0);
LikeParameterBinding binding = (LikeParameterBinding) bindings.get(0);
assertThat(binding, is(notNullValue()));
assertThat(binding.hasPosition(1), is(true));
assertThat(binding.getType(), is(Type.CONTAINING));
binding = bindings.get(1);
binding = (LikeParameterBinding) bindings.get(1);
assertThat(binding, is(notNullValue()));
assertThat(binding.hasPosition(2), is(true));
assertThat(binding.getType(), is(Type.ENDING_WITH));
@@ -79,18 +81,92 @@ public class StringQueryUnitTests {
StringQuery query = new StringQuery("select u from User u where u.firstname like %:firstname");
assertThat(query.hasLikeBindings(), is(true));
assertThat(query.hasParameterBindings(), is(true));
assertThat(query.getQueryString(), is("select u from User u where u.firstname like :firstname"));
List<LikeBinding> bindings = query.getLikeBindings();
List<ParameterBinding> bindings = query.getParameterBindings();
assertThat(bindings, hasSize(1));
LikeBinding binding = bindings.get(0);
LikeParameterBinding binding = (LikeParameterBinding) bindings.get(0);
assertThat(binding, is(notNullValue()));
assertThat(binding.hasName("firstname"), is(true));
assertThat(binding.getType(), is(Type.ENDING_WITH));
}
/**
* @see DATAJPA-461
*/
@Test
public void detectsNamedInParameterBindings() {
String queryString = "select u from User u where u.id in :ids";
StringQuery query = new StringQuery(queryString);
assertThat(query.hasParameterBindings(), is(true));
assertThat(query.getQueryString(), is(queryString));
List<ParameterBinding> bindings = query.getParameterBindings();
assertThat(bindings, hasSize(1));
assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0));
}
/**
* @see DATAJPA-461
*/
@Test
public void detectsMultipleNamedInParameterBindings() {
String queryString = "select u from User u where u.id in :ids and u.name in :names and foo = :bar";
StringQuery query = new StringQuery(queryString);
assertThat(query.hasParameterBindings(), is(true));
assertThat(query.getQueryString(), is(queryString));
List<ParameterBinding> bindings = query.getParameterBindings();
assertThat(bindings, hasSize(2));
assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0));
assertNamedBinding(InParameterBinding.class, "names", bindings.get(1));
}
/**
* @see DATAJPA-461
*/
@Test
public void detectsPositionalInParameterBindings() {
String queryString = "select u from User u where u.id in ?1";
StringQuery query = new StringQuery(queryString);
assertThat(query.hasParameterBindings(), is(true));
assertThat(query.getQueryString(), is(queryString));
List<ParameterBinding> bindings = query.getParameterBindings();
assertThat(bindings, hasSize(1));
assertPositionalBinding(InParameterBinding.class, 1, bindings.get(0));
}
/**
* @see DATAJPA-461
*/
@Test
public void detectsMultiplePositionalInParameterBindings() {
String queryString = "select u from User u where u.id in ?1 and u.names in ?2 and foo = ?3";
StringQuery query = new StringQuery(queryString);
assertThat(query.hasParameterBindings(), is(true));
assertThat(query.getQueryString(), is(queryString));
List<ParameterBinding> bindings = query.getParameterBindings();
assertThat(bindings, hasSize(2));
assertPositionalBinding(InParameterBinding.class, 1, bindings.get(0));
assertPositionalBinding(InParameterBinding.class, 2, bindings.get(1));
}
/**
* @see DATAJPA-373
*/
@@ -103,4 +179,20 @@ public class StringQueryUnitTests {
public void rejectsDifferentBindingsForRepeatedParameter() {
new StringQuery("select u from User u where u.firstname like %?1 and u.lastname like ?1%");
}
private void assertPositionalBinding(Class<? extends ParameterBinding> bindingType, Integer position,
ParameterBinding expectedBinding) {
assertThat(bindingType.isInstance(expectedBinding), is(true));
assertThat(expectedBinding, is(notNullValue()));
assertThat(expectedBinding.hasPosition(position), is(true));
}
private void assertNamedBinding(Class<? extends ParameterBinding> bindingType, String parameterName,
ParameterBinding expectedBinding) {
assertThat(bindingType.isInstance(expectedBinding), is(true));
assertThat(expectedBinding, is(notNullValue()));
assertThat(expectedBinding.hasName(parameterName), is(true));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2013 the original author or authors.
* Copyright 2008-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -277,6 +277,18 @@ public interface UserRepository extends JpaRepository<User, Integer>, JpaSpecifi
*/
Collection<User> findByIdIn(@Param("ids") Integer... ids);
/**
* @see DATAJPA-461
*/
@Query("select u from User u where u.id in ?1")
Collection<User> findByIdsCustomWithPositionalVarArgs(Integer... ids);
/**
* @see DATAJPA-461
*/
@Query("select u from User u where u.id in :ids")
Collection<User> findByIdsCustomWithNamedVarArgs(@Param("ids") Integer... ids);
/**
* @see DATAJPA-415
*/