diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryMethod.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryMethod.java index 960785b8d..4893418f2 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryMethod.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryMethod.java @@ -151,6 +151,15 @@ public class JdbcQueryMethod extends QueryMethod { return this.namedQueries.hasQuery(name) ? this.namedQueries.getQuery(name) : null; } + /** + * @return {@literal true} if the method is annotated with {@code @Query(name=…)}. + */ + public boolean hasAnnotatedQueryName() { + return lookupQueryAnnotation() // + .map(Query::name) // + .map(StringUtils::hasText).orElse(false); + } + @Override public String getNamedQueryName() { @@ -159,6 +168,7 @@ public class JdbcQueryMethod extends QueryMethod { return StringUtils.hasText(annotatedName) ? annotatedName : super.getNamedQueryName(); } + /** * Returns the class to be used as {@link org.springframework.jdbc.core.RowMapper} * diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java index 365a8055c..c8047dc0c 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java @@ -34,6 +34,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -143,7 +144,7 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery { String query = queryMethod.getDeclaredQuery(); - if (StringUtils.isEmpty(query)) { + if (ObjectUtils.isEmpty(query)) { throw new IllegalStateException(String.format("No query specified on %s", queryMethod.getName())); } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java index 291d2cf50..efb90850e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java @@ -19,6 +19,9 @@ import java.lang.reflect.Method; import java.sql.ResultSet; import java.sql.SQLException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.jdbc.core.convert.EntityRowMapper; @@ -58,6 +61,8 @@ import org.springframework.util.Assert; */ class JdbcQueryLookupStrategy implements QueryLookupStrategy { + private static final Log LOG = LogFactory.getLog(JdbcQueryLookupStrategy.class); + private final ApplicationEventPublisher publisher; private final @Nullable EntityCallbacks callbacks; private final RelationalMappingContext context; @@ -103,6 +108,11 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy { try { if (namedQueries.hasQuery(queryMethod.getNamedQueryName()) || queryMethod.hasAnnotatedQuery()) { + if (queryMethod.hasAnnotatedQuery() && queryMethod.hasAnnotatedQueryName()) { + LOG.warn(String.format( + "Query method %s is annotated with both, a query and a query name. Using the declared query.", method)); + } + RowMapper mapper = queryMethod.isModifyingQuery() ? null : createMapper(queryMethod); StringBasedJdbcQuery query = new StringBasedJdbcQuery(queryMethod, operations, mapper, converter); query.setBeanFactory(beanfactory); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java index 4d8377dfc..38048cb2f 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java @@ -88,6 +88,20 @@ public class JdbcQueryLookupStrategyUnitTests { verify(operations).queryForObject(anyString(), any(SqlParameterSource.class), any(RowMapper.class)); } + @Test // GH-1061 + public void prefersDeclaredQuery() { + + RowMapper numberFormatMapper = mock(RowMapper.class); + QueryMappingConfiguration mappingConfiguration = new DefaultQueryMappingConfiguration() + .registerRowMapper(NumberFormat.class, numberFormatMapper); + + RepositoryQuery repositoryQuery = getRepositoryQuery("annotatedQueryWithQueryAndQueryName", mappingConfiguration); + + repositoryQuery.execute(new Object[] {}); + + verify(operations).queryForObject(eq("some SQL"), any(SqlParameterSource.class), any(RowMapper.class)); + } + private RepositoryQuery getRepositoryQuery(String name, QueryMappingConfiguration mappingConfiguration) { JdbcQueryLookupStrategy queryLookupStrategy = new JdbcQueryLookupStrategy(publisher, callbacks, mappingContext, @@ -102,5 +116,8 @@ public class JdbcQueryLookupStrategyUnitTests { // NumberFormat is just used as an arbitrary non simple type. @Query("some SQL") NumberFormat returningNumberFormat(); + + @Query(value = "some SQL", name = "query-name") + void annotatedQueryWithQueryAndQueryName(); } }