diff --git a/pom.xml b/pom.xml
index eeaa0b9e93..460f239464 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-relational-parent
- 2.3.0-SNAPSHOT
+ 2.3.0-908-boolean-for-derived-queries-SNAPSHOT
pom
Spring Data Relational Parent
diff --git a/spring-data-jdbc-distribution/pom.xml b/spring-data-jdbc-distribution/pom.xml
index 03d6a5c2a0..a86a0a2724 100644
--- a/spring-data-jdbc-distribution/pom.xml
+++ b/spring-data-jdbc-distribution/pom.xml
@@ -14,7 +14,7 @@
org.springframework.data
spring-data-relational-parent
- 2.3.0-SNAPSHOT
+ 2.3.0-908-boolean-for-derived-queries-SNAPSHOT
../pom.xml
diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml
index af9ad0904e..f99d52e942 100644
--- a/spring-data-jdbc/pom.xml
+++ b/spring-data-jdbc/pom.xml
@@ -6,7 +6,7 @@
4.0.0
spring-data-jdbc
- 2.3.0-SNAPSHOT
+ 2.3.0-908-boolean-for-derived-queries-SNAPSHOT
Spring Data JDBC
Spring Data module for JDBC repositories.
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-relational-parent
- 2.3.0-SNAPSHOT
+ 2.3.0-908-boolean-for-derived-queries-SNAPSHOT
diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java
index be6398b3cf..7aca5b75f0 100644
--- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java
+++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java
@@ -133,7 +133,7 @@ public JdbcCustomConversions jdbcCustomConversions() {
}
}
- private List> userConverters() {
+ protected List> userConverters() {
return Collections.emptyList();
}
diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/QueryMapper.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/QueryMapper.java
index f8ee2d7b1e..328e088295 100644
--- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/QueryMapper.java
+++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/QueryMapper.java
@@ -402,11 +402,15 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, i
}
if (comparator == Comparator.IS_TRUE) {
- return column.isEqualTo(SQL.literalOf(true));
+
+ Expression bind = bindBoolean(column, parameterSource, true);
+ return column.isEqualTo(bind);
}
if (comparator == Comparator.IS_FALSE) {
- return column.isEqualTo(SQL.literalOf(false));
+
+ Expression bind = bindBoolean(column, parameterSource, false);
+ return column.isEqualTo(bind);
}
Expression columnExpression = column;
@@ -495,6 +499,12 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, i
}
}
+ private Expression bindBoolean(Column column, MapSqlParameterSource parameterSource, boolean value) {
+
+ Object converted = converter.writeValue(value, ClassTypeInformation.OBJECT);
+ return bind(converted, Types.BIT, parameterSource, column.getName().getReference());
+ }
+
Field createPropertyField(@Nullable RelationalPersistentEntity> entity, SqlIdentifier key) {
return entity == null ? new Field(key) : new MetadataBackedField(key, entity, mappingContext, converter);
}
diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
index 54497a5d44..f3c30237dc 100644
--- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
+++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
@@ -492,6 +492,19 @@ public void pageQueryProjectionShouldReturnProjectedEntities() {
assertThat(result.getContent().get(0).getName()).isEqualTo("Entity Name");
}
+ @Test // #908
+ void derivedQueryWithBooleanLiteralFindsCorrectValues() {
+
+ repository.save(createDummyEntity());
+ DummyEntity entity = createDummyEntity();
+ entity.flag = true;
+ entity = repository.save(entity);
+
+ List result = repository.findByFlagTrue();
+
+ assertThat(result).extracting(e -> e.idProp).containsExactly(entity.idProp);
+ }
+
private Instant createDummyBeforeAndAfterNow() {
Instant now = Instant.now();
@@ -557,6 +570,8 @@ interface DummyEntityRepository extends CrudRepository {
@Query("SELECT * FROM DUMMY_ENTITY WHERE OFFSET_DATE_TIME > :threshhold")
List findByOffsetDateTime(@Param("threshhold") OffsetDateTime threshhold);
+
+ List findByFlagTrue();
}
@Configuration
@@ -603,10 +618,12 @@ public void onApplicationEvent(AbstractRelationalEvent> event) {
@Data
@NoArgsConstructor
static class DummyEntity {
+
String name;
Instant pointInTime;
OffsetDateTime offsetDateTime;
@Id private Long idProp;
+ boolean flag;
public DummyEntity(String name) {
this.name = name;
diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfigurationIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfigurationIntegrationTests.java
index 1ec72619c9..e2cad273d7 100644
--- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfigurationIntegrationTests.java
+++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfigurationIntegrationTests.java
@@ -15,12 +15,13 @@
*/
package org.springframework.data.jdbc.repository.config;
+import static java.util.Arrays.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
-import java.util.Arrays;
-import java.util.Collections;
+import java.util.Collection;
import java.util.List;
+import java.util.Optional;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
@@ -29,6 +30,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
+import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
@@ -36,7 +38,9 @@
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.relational.core.dialect.Dialect;
-import org.springframework.data.relational.core.dialect.HsqlDbDialect;
+import org.springframework.data.relational.core.dialect.LimitClause;
+import org.springframework.data.relational.core.dialect.LockClause;
+import org.springframework.data.relational.core.sql.render.SelectRenderContext;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@@ -53,7 +57,7 @@ void configuresInfrastructureComponents() {
assertApplicationContext(context -> {
- List> expectedBeanTypes = Arrays.asList(DataAccessStrategy.class, //
+ List> expectedBeanTypes = asList(DataAccessStrategy.class, //
JdbcMappingContext.class, //
JdbcConverter.class, //
JdbcCustomConversions.class, //
@@ -70,11 +74,26 @@ void configuresInfrastructureComponents() {
void registersSimpleTypesFromCustomConversions() {
assertApplicationContext(context -> {
+
JdbcMappingContext mappingContext = context.getBean(JdbcMappingContext.class);
assertThat( //
mappingContext.getPersistentEntity(AbstractJdbcConfigurationUnderTest.Blah.class) //
).describedAs("Blah should not be an entity, since there is a WritingConversion configured for it") //
.isNull();
+
+ }, AbstractJdbcConfigurationUnderTest.class, Infrastructure.class);
+ }
+
+ @Test // #908
+ void userProvidedConversionsOverwriteDialectSpecificConversions() {
+
+ assertApplicationContext(applicationContext -> {
+
+ Optional> customWriteTarget = applicationContext.getBean(JdbcCustomConversions.class)
+ .getCustomWriteTarget(Boolean.class);
+
+ assertThat(customWriteTarget).contains(String.class);
+
}, AbstractJdbcConfigurationUnderTest.class, Infrastructure.class);
}
@@ -106,12 +125,12 @@ static class AbstractJdbcConfigurationUnderTest extends AbstractJdbcConfiguratio
@Override
@Bean
public Dialect jdbcDialect(NamedParameterJdbcOperations operations) {
- return HsqlDbDialect.INSTANCE;
+ return new DummyDialect();
}
@Override
- public JdbcCustomConversions jdbcCustomConversions() {
- return new JdbcCustomConversions(Collections.singletonList(Blah2BlubbConverter.INSTANCE));
+ protected List> userConverters() {
+ return asList(Blah2BlubbConverter.INSTANCE, BooleanToYnConverter.INSTANCE);
}
@WritingConverter
@@ -127,6 +146,59 @@ public Blubb convert(Blah blah) {
private static class Blah {}
private static class Blubb {}
+
+ private static class DummyDialect implements Dialect {
+ @Override
+ public LimitClause limit() {
+ return null;
+ }
+
+ @Override
+ public LockClause lock() {
+ return null;
+ }
+
+ @Override
+ public SelectRenderContext getSelectContext() {
+ return null;
+ }
+
+ @Override
+ public Collection