Skip to content

Commit 6cf2834

Browse files
committed
#207 - Skip converter registrations for JSR-310 to java.util.Date.
We now prevent converter registrations that enforce a conversion from JSR-310 types to java.util.Date. R2DBC drivers use natively JSR-310 types and some of them don't implement java.util.Date at all.
1 parent d38825e commit 6cf2834

File tree

3 files changed

+71
-6
lines changed

3 files changed

+71
-6
lines changed

src/main/java/org/springframework/data/r2dbc/convert/R2dbcCustomConversions.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.ArrayList;
44
import java.util.Collection;
55
import java.util.Collections;
6+
import java.util.Date;
67
import java.util.List;
78

89
import org.springframework.data.convert.CustomConversions;
@@ -40,7 +41,7 @@ public class R2dbcCustomConversions extends CustomConversions {
4041
* @param converters must not be {@literal null}.
4142
*/
4243
public R2dbcCustomConversions(Collection<?> converters) {
43-
super(STORE_CONVERSIONS, appendOverrides(converters));
44+
super(new R2dbcCustomConversionsConfiguration(STORE_CONVERSIONS, appendOverrides(converters)));
4445
}
4546

4647
/**
@@ -50,14 +51,29 @@ public R2dbcCustomConversions(Collection<?> converters) {
5051
* @param converters must not be {@literal null}.
5152
*/
5253
public R2dbcCustomConversions(StoreConversions storeConversions, Collection<?> converters) {
53-
super(storeConversions, appendOverrides(converters));
54+
super(new R2dbcCustomConversionsConfiguration(storeConversions, appendOverrides(converters)));
5455
}
5556

56-
private static Collection<?> appendOverrides(Collection<?> converters) {
57+
private static List<?> appendOverrides(Collection<?> converters) {
5758

5859
List<Object> objects = new ArrayList<>(converters);
5960
objects.addAll(R2dbcConverters.getOverrideConvertersToRegister());
6061

6162
return objects;
6263
}
64+
65+
static class R2dbcCustomConversionsConfiguration extends ConverterConfiguration {
66+
67+
public R2dbcCustomConversionsConfiguration(StoreConversions storeConversions, List<?> userConverters) {
68+
super(storeConversions, userConverters, convertiblePair -> {
69+
70+
if (convertiblePair.getSourceType().getName().startsWith("java.time.")
71+
&& convertiblePair.getTargetType().equals(Date.class)) {
72+
return false;
73+
}
74+
75+
return true;
76+
});
77+
}
78+
}
6379
}

src/test/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverterUnitTests.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import io.r2dbc.spi.Row;
2222
import lombok.AllArgsConstructor;
2323

24+
import java.time.Instant;
25+
import java.time.LocalDateTime;
2426
import java.util.Arrays;
2527
import java.util.Collections;
2628
import java.util.Map;
@@ -61,17 +63,21 @@ public void before() {
6163
converter = new MappingR2dbcConverter(mappingContext, conversions);
6264
}
6365

64-
@Test // gh-61
66+
@Test // gh-61, gh-207
6567
public void shouldIncludeAllPropertiesInOutboundRow() {
6668

6769
OutboundRow row = new OutboundRow();
6870

69-
converter.write(new Person("id", "Walter", "White"), row);
71+
Instant instant = Instant.now();
72+
LocalDateTime localDateTime = LocalDateTime.now();
73+
converter.write(new Person("id", "Walter", "White", instant, localDateTime), row);
7074

7175
assertThat(row).containsEntry(SqlIdentifier.unquoted("id"), SettableValue.fromOrEmpty("id", String.class));
7276
assertThat(row).containsEntry(SqlIdentifier.unquoted("firstname"),
7377
SettableValue.fromOrEmpty("Walter", String.class));
7478
assertThat(row).containsEntry(SqlIdentifier.unquoted("lastname"), SettableValue.fromOrEmpty("White", String.class));
79+
assertThat(row).containsEntry(SqlIdentifier.unquoted("instant"), SettableValue.from(instant));
80+
assertThat(row).containsEntry(SqlIdentifier.unquoted("local_date_time"), SettableValue.from(localDateTime));
7581
}
7682

7783
@Test // gh-41
@@ -187,6 +193,8 @@ public void shouldReadTopLevelEntity() {
187193
static class Person {
188194
@Id String id;
189195
String firstname, lastname;
196+
Instant instant;
197+
LocalDateTime localDateTime;
190198
}
191199

192200
@AllArgsConstructor

src/test/java/org/springframework/data/r2dbc/repository/MySqlR2dbcRepositoryIntegrationTests.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,34 @@
1616
package org.springframework.data.r2dbc.repository;
1717

1818
import io.r2dbc.spi.ConnectionFactory;
19+
import lombok.AllArgsConstructor;
20+
import lombok.Data;
1921
import reactor.core.publisher.Flux;
2022
import reactor.core.publisher.Mono;
23+
import reactor.test.StepVerifier;
24+
25+
import java.time.LocalDateTime;
2126

2227
import javax.sql.DataSource;
2328

2429
import org.junit.ClassRule;
30+
import org.junit.Test;
2531
import org.junit.runner.RunWith;
2632

33+
import org.springframework.beans.factory.annotation.Autowired;
2734
import org.springframework.context.annotation.Bean;
2835
import org.springframework.context.annotation.ComponentScan.Filter;
2936
import org.springframework.context.annotation.Configuration;
3037
import org.springframework.context.annotation.FilterType;
38+
import org.springframework.dao.DataAccessException;
39+
import org.springframework.data.annotation.Id;
3140
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
3241
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
3342
import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory;
3443
import org.springframework.data.r2dbc.testing.ExternalDatabase;
3544
import org.springframework.data.r2dbc.testing.MySqlTestSupport;
45+
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
46+
import org.springframework.jdbc.core.JdbcTemplate;
3647
import org.springframework.test.context.ContextConfiguration;
3748
import org.springframework.test.context.junit4.SpringRunner;
3849

@@ -47,9 +58,12 @@ public class MySqlR2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositor
4758

4859
@ClassRule public static final ExternalDatabase database = MySqlTestSupport.database();
4960

61+
@Autowired DateTestsRepository dateTestsRepository;
62+
5063
@Configuration
5164
@EnableR2dbcRepositories(considerNestedRepositories = true,
52-
includeFilters = @Filter(classes = MySqlLegoSetRepository.class, type = FilterType.ASSIGNABLE_TYPE))
65+
includeFilters = { @Filter(classes = MySqlLegoSetRepository.class, type = FilterType.ASSIGNABLE_TYPE),
66+
@Filter(classes = DateTestsRepository.class, type = FilterType.ASSIGNABLE_TYPE) })
5367
static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration {
5468

5569
@Bean
@@ -79,6 +93,29 @@ protected Class<? extends LegoSetRepository> getRepositoryInterfaceType() {
7993
return MySqlLegoSetRepository.class;
8094
}
8195

96+
@Test
97+
public void shouldUserJsr310Types() {
98+
99+
JdbcTemplate jdbcTemplate = createJdbcTemplate(createDataSource());
100+
101+
try {
102+
jdbcTemplate.execute("DROP TABLE date_tests");
103+
} catch (DataAccessException e) {}
104+
105+
jdbcTemplate.execute("CREATE TABLE date_tests (id int, created_timestamp TIMESTAMP, created_date datetime);");
106+
107+
dateTestsRepository.save(new DateTests(null, LocalDateTime.now(), LocalDateTime.now())).as(StepVerifier::create)
108+
.expectNextCount(1).verifyComplete();
109+
}
110+
111+
@Data
112+
@AllArgsConstructor
113+
static class DateTests {
114+
@Id Integer id;
115+
LocalDateTime createdTimestamp;
116+
LocalDateTime createdDate;
117+
}
118+
82119
interface MySqlLegoSetRepository extends LegoSetRepository {
83120

84121
@Override
@@ -93,4 +130,8 @@ interface MySqlLegoSetRepository extends LegoSetRepository {
93130
@Query("SELECT id FROM legoset")
94131
Flux<Integer> findAllIds();
95132
}
133+
134+
interface DateTestsRepository extends ReactiveCrudRepository<DateTests, Integer> {
135+
136+
}
96137
}

0 commit comments

Comments
 (0)