#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.
This commit is contained in:
Mark Paluch
2020-05-15 11:50:24 +02:00
parent 94f7f1759b
commit 7cfac09aa0
3 changed files with 71 additions and 6 deletions

View File

@@ -3,6 +3,7 @@ package org.springframework.data.r2dbc.convert;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.springframework.data.convert.CustomConversions;
@@ -40,7 +41,7 @@ public class R2dbcCustomConversions extends CustomConversions {
* @param converters must not be {@literal null}.
*/
public R2dbcCustomConversions(Collection<?> converters) {
super(STORE_CONVERSIONS, appendOverrides(converters));
super(new R2dbcCustomConversionsConfiguration(STORE_CONVERSIONS, appendOverrides(converters)));
}
/**
@@ -50,14 +51,29 @@ public class R2dbcCustomConversions extends CustomConversions {
* @param converters must not be {@literal null}.
*/
public R2dbcCustomConversions(StoreConversions storeConversions, Collection<?> converters) {
super(storeConversions, appendOverrides(converters));
super(new R2dbcCustomConversionsConfiguration(storeConversions, appendOverrides(converters)));
}
private static Collection<?> appendOverrides(Collection<?> converters) {
private static List<?> appendOverrides(Collection<?> converters) {
List<Object> objects = new ArrayList<>(converters);
objects.addAll(R2dbcConverters.getOverrideConvertersToRegister());
return objects;
}
static class R2dbcCustomConversionsConfiguration extends ConverterConfiguration {
public R2dbcCustomConversionsConfiguration(StoreConversions storeConversions, List<?> userConverters) {
super(storeConversions, userConverters, convertiblePair -> {
if (convertiblePair.getSourceType().getName().startsWith("java.time.")
&& convertiblePair.getTargetType().equals(Date.class)) {
return false;
}
return true;
});
}
}
}

View File

@@ -21,6 +21,8 @@ import static org.mockito.Mockito.*;
import io.r2dbc.spi.Row;
import lombok.AllArgsConstructor;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
@@ -61,17 +63,21 @@ public class MappingR2dbcConverterUnitTests {
converter = new MappingR2dbcConverter(mappingContext, conversions);
}
@Test // gh-61
@Test // gh-61, gh-207
public void shouldIncludeAllPropertiesInOutboundRow() {
OutboundRow row = new OutboundRow();
converter.write(new Person("id", "Walter", "White"), row);
Instant instant = Instant.now();
LocalDateTime localDateTime = LocalDateTime.now();
converter.write(new Person("id", "Walter", "White", instant, localDateTime), row);
assertThat(row).containsEntry(SqlIdentifier.unquoted("id"), SettableValue.fromOrEmpty("id", String.class));
assertThat(row).containsEntry(SqlIdentifier.unquoted("firstname"),
SettableValue.fromOrEmpty("Walter", String.class));
assertThat(row).containsEntry(SqlIdentifier.unquoted("lastname"), SettableValue.fromOrEmpty("White", String.class));
assertThat(row).containsEntry(SqlIdentifier.unquoted("instant"), SettableValue.from(instant));
assertThat(row).containsEntry(SqlIdentifier.unquoted("local_date_time"), SettableValue.from(localDateTime));
}
@Test // gh-41
@@ -187,6 +193,8 @@ public class MappingR2dbcConverterUnitTests {
static class Person {
@Id String id;
String firstname, lastname;
Instant instant;
LocalDateTime localDateTime;
}
@AllArgsConstructor

View File

@@ -16,23 +16,34 @@
package org.springframework.data.r2dbc.repository;
import io.r2dbc.spi.ConnectionFactory;
import lombok.AllArgsConstructor;
import lombok.Data;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.time.LocalDateTime;
import javax.sql.DataSource;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.dao.DataAccessException;
import org.springframework.data.annotation.Id;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory;
import org.springframework.data.r2dbc.testing.ExternalDatabase;
import org.springframework.data.r2dbc.testing.MySqlTestSupport;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@@ -47,9 +58,12 @@ public class MySqlR2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositor
@ClassRule public static final ExternalDatabase database = MySqlTestSupport.database();
@Autowired DateTestsRepository dateTestsRepository;
@Configuration
@EnableR2dbcRepositories(considerNestedRepositories = true,
includeFilters = @Filter(classes = MySqlLegoSetRepository.class, type = FilterType.ASSIGNABLE_TYPE))
includeFilters = { @Filter(classes = MySqlLegoSetRepository.class, type = FilterType.ASSIGNABLE_TYPE),
@Filter(classes = DateTestsRepository.class, type = FilterType.ASSIGNABLE_TYPE) })
static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration {
@Bean
@@ -79,6 +93,29 @@ public class MySqlR2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositor
return MySqlLegoSetRepository.class;
}
@Test
public void shouldUserJsr310Types() {
JdbcTemplate jdbcTemplate = createJdbcTemplate(createDataSource());
try {
jdbcTemplate.execute("DROP TABLE date_tests");
} catch (DataAccessException e) {}
jdbcTemplate.execute("CREATE TABLE date_tests (id int, created_timestamp TIMESTAMP, created_date datetime);");
dateTestsRepository.save(new DateTests(null, LocalDateTime.now(), LocalDateTime.now())).as(StepVerifier::create)
.expectNextCount(1).verifyComplete();
}
@Data
@AllArgsConstructor
static class DateTests {
@Id Integer id;
LocalDateTime createdTimestamp;
LocalDateTime createdDate;
}
interface MySqlLegoSetRepository extends LegoSetRepository {
@Override
@@ -93,4 +130,8 @@ public class MySqlR2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositor
@Query("SELECT id FROM legoset")
Flux<Integer> findAllIds();
}
interface DateTestsRepository extends ReactiveCrudRepository<DateTests, Integer> {
}
}