diff --git a/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java b/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java index 13253a2e4..31ea8a77a 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java @@ -32,6 +32,8 @@ import org.springframework.util.Assert; */ public class ParameterBinder { + static final String PARAMETER_NEEDS_TO_BE_NAMED = "For queries with named parameters you need to use provide names for method parameters. Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters."; + private final JpaParameters parameters; private final Iterable parameterSetters; diff --git a/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java b/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java index 9155ae88d..4c1c17212 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java @@ -202,6 +202,8 @@ abstract class QueryParameterSetterFactory { @Override public QueryParameterSetter create(ParameterBinding binding, String queryString) { + Assert.notNull(binding, "Binding must not be null."); + JpaParameter parameter = QueryUtils.hasNamedParameter(queryString) // ? findParameterForBinding(binding) // : parameters.getBindableParameter(binding.getPosition() - 1); @@ -223,7 +225,7 @@ abstract class QueryParameterSetterFactory { } private static String getName(JpaParameter p) { - return p.getName().orElseThrow(() -> new IllegalArgumentException("Parameter needs to be named!")); + return p.getName().orElseThrow(() -> new IllegalStateException(ParameterBinder.PARAMETER_NEEDS_TO_BE_NAMED)); } } diff --git a/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureJpaQuery.java index 4261f2c87..03f704c1f 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureJpaQuery.java @@ -153,7 +153,7 @@ class StoredProcedureJpaQuery extends AbstractJpaQuery { if (useNamedParameters) { procedureQuery.registerStoredProcedureParameter( - param.getName().orElseThrow(() -> new IllegalArgumentException("Parameter needs to be named!")), + param.getName().orElseThrow(() -> new IllegalArgumentException(ParameterBinder.PARAMETER_NEEDS_TO_BE_NAMED)), param.getType(), ParameterMode.IN); } else { procedureQuery.registerStoredProcedureParameter(param.getIndex() + 1, param.getType(), ParameterMode.IN); diff --git a/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryTest.java b/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryTest.java new file mode 100644 index 000000000..78576dd0c --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2017 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.jpa.repository.query; + +import static org.mockito.Mockito.*; + +import java.util.stream.Stream; + +import org.assertj.core.api.Assertions; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter; +import org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding; + +/** + * @author Jens Schauder + */ +public class QueryParameterSetterFactoryTest { + + JpaParameters parameters = mock(JpaParameters.class, Mockito.RETURNS_DEEP_STUBS); + ParameterBinding binding = mock(ParameterBinding.class); + + QueryParameterSetterFactory setterFactory; + + @Before + public void before() { + + // we have one bindable parameter + when(parameters.getBindableParameters().stream()).thenReturn(Stream.of(mock(JpaParameter.class))); + + setterFactory = QueryParameterSetterFactory.basic(parameters); + } + + @Test // DATAJPA-1058 + public void noExceptionWhenQueryDoesNotContainNamedParameters() { + + setterFactory.create(binding, "QueryStringWithOutNamedParameter"); + } + + @Test // DATAJPA-1058 + public void exceptionWhenQueryContainNamedParametersAndMethodParametersAreNotNamed() { + + Assertions.assertThatExceptionOfType(IllegalStateException.class) // + .isThrownBy(() -> setterFactory.create(binding, "QueryStringWith :NamedParameter")) // + .withMessageContaining("Java 8") // + .withMessageContaining("@Param") // + .withMessageContaining("-parameters"); + } + +}