From 78f26aa0a7a44558ac39d69bdc75b5741f6e6fc5 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 12 Mar 2019 12:23:52 +0100 Subject: [PATCH] DATAJDBC-327 - Polishing. Extend Javadoc. Reorder constructors in the order of their parameter number. Add missing assertions. Introduce utility to create predicates. Remove unused fields. Add since tags. Reformat. Original pull request: #123. --- .../jdbc/core/DefaultDataAccessStrategy.java | 66 ++++++++++++++----- .../data/jdbc/core/convert/ArrayUtil.java | 10 +-- .../jdbc/core/convert/BasicJdbcConverter.java | 61 ++++++++++------- .../core/convert/DefaultJdbcTypeFactory.java | 17 +++-- .../data/jdbc/core/convert/package-info.java | 7 ++ .../data/jdbc/core/package-info.java | 3 + .../data/jdbc/support/JdbcUtil.java | 5 +- .../DefaultDataAccessStrategyUnitTests.java | 19 +++--- ...JdbcAggregateTemplateIntegrationTests.java | 6 +- ...lConverterAggregateReferenceUnitTests.java | 6 +- ...itoryCustomConversionIntegrationTests.java | 31 +++++---- .../SimpleJdbcRepositoryEventsUnitTests.java | 3 + src/main/asciidoc/jdbc.adoc | 6 +- 13 files changed, 157 insertions(+), 83 deletions(-) create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/package-info.java diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java index 58b20c14..4a868735 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java @@ -65,24 +65,44 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy { private final @NonNull NamedParameterJdbcOperations operations; private final @NonNull DataAccessStrategy accessStrategy; + /** + * Creates a {@link DefaultDataAccessStrategy} which references it self for resolution of recursive data accesses. + * Only suitable if this is the only access strategy in use. + * + * @param sqlGeneratorSource must not be {@literal null}. + * @param context must not be {@literal null}. + * @param converter must not be {@literal null}. + * @param operations must not be {@literal null}. + */ public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, RelationalMappingContext context, - JdbcConverter converter, NamedParameterJdbcOperations operations, @Nullable DataAccessStrategy accessStrategy) { + JdbcConverter converter, NamedParameterJdbcOperations operations) { + this(sqlGeneratorSource, context, converter, operations, null); + } + + /** + * Creates a {@link DefaultDataAccessStrategy} + * + * @param sqlGeneratorSource must not be {@literal null}. + * @param context must not be {@literal null}. + * @param converter must not be {@literal null}. + * @param operations must not be {@literal null}. + * @param mappingAccessStrategy can be {@literal null}. + * @since 1.1 + */ + public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, RelationalMappingContext context, + JdbcConverter converter, NamedParameterJdbcOperations operations, + @Nullable DataAccessStrategy mappingAccessStrategy) { + + Assert.notNull(sqlGeneratorSource, "SqlGeneratorSource must not be null"); + Assert.notNull(context, "RelationalMappingContext must not be null"); + Assert.notNull(converter, "JdbcConverter must not be null"); + Assert.notNull(operations, "NamedParameterJdbcOperations must not be null"); this.sqlGeneratorSource = sqlGeneratorSource; this.context = context; this.converter = converter; this.operations = operations; - this.accessStrategy = accessStrategy == null ? this : accessStrategy; - } - - /** - * Creates a {@link DefaultDataAccessStrategy} which references it self for resolution of recursive data accesses. - * Only suitable if this is the only access strategy in use. - */ - public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, RelationalMappingContext context, - JdbcConverter converter, NamedParameterJdbcOperations operations) { - - this(sqlGeneratorSource, context, converter, operations, null); + this.accessStrategy = mappingAccessStrategy == null ? this : mappingAccessStrategy; } /* @@ -104,7 +124,8 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy { KeyHolder holder = new GeneratedKeyHolder(); RelationalPersistentEntity persistentEntity = getRequiredPersistentEntity(domainType); - MapSqlParameterSource parameterSource = getParameterSource(instance, persistentEntity, "", PersistentProperty::isIdProperty); + MapSqlParameterSource parameterSource = getParameterSource(instance, persistentEntity, "", + PersistentProperty::isIdProperty); identifier.forEach((name, value, type) -> addConvertedPropertyValue(parameterSource, name, value, type)); @@ -134,7 +155,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy { RelationalPersistentEntity persistentEntity = getRequiredPersistentEntity(domainType); return operations.update(sql(domainType).getUpdate(), - getParameterSource(instance, persistentEntity, "", property -> false)) != 0; + getParameterSource(instance, persistentEntity, "", Predicates.includeAll())) != 0; } /* @@ -289,7 +310,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy { } private MapSqlParameterSource getParameterSource(S instance, RelationalPersistentEntity persistentEntity, - String prefix, Predicate skipProperty) { + String prefix, Predicate skipProperty) { MapSqlParameterSource parameters = new MapSqlParameterSource(); @@ -445,4 +466,19 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy { private SqlGenerator sql(Class domainType) { return sqlGeneratorSource.getSqlGenerator(domainType); } + + /** + * Utility to create {@link Predicate}s. + */ + static class Predicates { + + /** + * Include all {@link Predicate} returning {@literal false} to never skip a property. + * + * @return the include all {@link Predicate}. + */ + static Predicate includeAll() { + return it -> false; + } + } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/ArrayUtil.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/ArrayUtil.java index 69f21191..16870c9c 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/ArrayUtil.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/ArrayUtil.java @@ -21,17 +21,19 @@ import lombok.experimental.UtilityClass; * A collection of utility methods for dealing with arrays. * * @author Jens Schauder + * @since 1.1 */ @UtilityClass class ArrayUtil { /** - * Convertes an {@code Byte[]} into a {@code byte[]} - * @param byteArray the array to be converted. Must not be {@literal null}. + * Converts an {@code Byte[]} into a {@code byte[]}. * - * @return a {@code byte[]} of same size with the unboxed values of the input array. Guaranteed to be not {@literal null}. + * @param byteArray the array to be converted. Must not be {@literal null}. + * @return a {@code byte[]} of same size with the unboxed values of the input array. Guaranteed to be not + * {@literal null}. */ - static Object toPrimitiveByteArray(Byte[] byteArray) { + static byte[] toPrimitiveByteArray(Byte[] byteArray) { byte[] bytes = new byte[byteArray.length]; for (int i = 0; i < byteArray.length; i++) { diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java index 5cb74c07..8cf92ecc 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java @@ -22,6 +22,7 @@ import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.data.convert.CustomConversions; import org.springframework.data.jdbc.core.mapping.AggregateReference; @@ -35,6 +36,7 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * {@link RelationalConverter} that uses a {@link MappingContext} to apply basic conversion of relational values to @@ -54,43 +56,54 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc private final JdbcTypeFactory typeFactory; + /** + * Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and a + * {@link JdbcTypeFactory#unsupported() no-op type factory} throwing {@link UnsupportedOperationException} on type + * creation. Use {@link #BasicJdbcConverter(MappingContext, JdbcTypeFactory)} to convert arrays and large objects into + * JDBC-specific types. + * + * @param context must not be {@literal null}. + */ + public BasicJdbcConverter( + MappingContext, ? extends RelationalPersistentProperty> context) { + this(context, JdbcTypeFactory.unsupported()); + } + /** * Creates a new {@link BasicRelationalConverter} given {@link MappingContext}. * - * @param context must not be {@literal null}. org.springframework.data.jdbc.core.DefaultDataAccessStrategyUnitTests - * @param typeFactory + * @param context must not be {@literal null}. + * @param typeFactory must not be {@literal null} + * @since 1.1 */ public BasicJdbcConverter( MappingContext, ? extends RelationalPersistentProperty> context, JdbcTypeFactory typeFactory) { + super(context); + + Assert.notNull(typeFactory, "JdbcTypeFactory must not be null"); + this.typeFactory = typeFactory; } /** - * Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and {@link CustomConversions}. - * + * Creates a new {@link BasicRelationalConverter} given {@link MappingContext}, {@link CustomConversions}, and + * {@link JdbcTypeFactory}. + * * @param context must not be {@literal null}. * @param conversions must not be {@literal null}. - * @param typeFactory + * @param typeFactory must not be {@literal null} + * @since 1.1 */ public BasicJdbcConverter( MappingContext, ? extends RelationalPersistentProperty> context, CustomConversions conversions, JdbcTypeFactory typeFactory) { - super(context, conversions); - this.typeFactory = typeFactory; - } - /** - * Creates a new {@link BasicRelationalConverter} given {@link MappingContext}. - * - * @param context must not be {@literal null}. org.springframework.data.jdbc.core.DefaultDataAccessStrategyUnitTests - * @deprecated use one of the constructors with {@link JdbcTypeFactory} parameter. - */ - @Deprecated - public BasicJdbcConverter( - MappingContext, ? extends RelationalPersistentProperty> context) { - this(context, JdbcTypeFactory.unsupported()); + super(context, conversions); + + Assert.notNull(typeFactory, "JdbcTypeFactory must not be null"); + this.typeFactory = typeFactory; } /** @@ -186,6 +199,11 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc return customWriteTarget.isPresent() && customWriteTarget.get().isAssignableFrom(JdbcValue.class); } + /* + * (non-Javadoc) + * @see org.springframework.data.jdbc.core.convert.JdbcConverter#writeValue(java.lang.Object, java.lang.Class, int) + */ + @Override public JdbcValue writeJdbcValue(@Nullable Object value, Class columnType, int sqlType) { JdbcValue jdbcValue = tryToConvertToJdbcValue(value); @@ -209,16 +227,15 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc } return JdbcValue.of(convertedValue, JDBCType.BINARY); - } + @Nullable private JdbcValue tryToConvertToJdbcValue(@Nullable Object value) { - JdbcValue jdbcValue = null; if (canWriteAsJdbcValue(value)) { - jdbcValue = (JdbcValue) writeValue(value, ClassTypeInformation.from(JdbcValue.class)); + return (JdbcValue) writeValue(value, ClassTypeInformation.from(JdbcValue.class)); } - return jdbcValue; + return null; } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultJdbcTypeFactory.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultJdbcTypeFactory.java index 01eed147..d9eac776 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultJdbcTypeFactory.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultJdbcTypeFactory.java @@ -15,16 +15,17 @@ */ package org.springframework.data.jdbc.core.convert; +import java.sql.Array; +import java.sql.JDBCType; + import org.springframework.data.jdbc.support.JdbcUtil; import org.springframework.jdbc.core.ConnectionCallback; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.util.Assert; -import java.sql.Array; -import java.sql.JDBCType; - /** - * A {@link JdbcTypeFactory} that performs the conversion by utilizing {@link JdbcOperations#execute(ConnectionCallback)}. + * A {@link JdbcTypeFactory} that performs the conversion by utilizing + * {@link JdbcOperations#execute(ConnectionCallback)}. * * @author Jens Schauder * @since 1.1 @@ -33,7 +34,15 @@ public class DefaultJdbcTypeFactory implements JdbcTypeFactory { private final JdbcOperations operations; + /** + * Creates a new {@link DefaultJdbcTypeFactory}. + * + * @param operations must not be {@literal null}. + */ public DefaultJdbcTypeFactory(JdbcOperations operations) { + + Assert.notNull(operations, "JdbcOperations must not be null"); + this.operations = operations; } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/package-info.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/package-info.java new file mode 100644 index 00000000..43ca52cb --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/package-info.java @@ -0,0 +1,7 @@ +/** + * JDBC-specific conversion classes. + */ +@NonNullApi +package org.springframework.data.jdbc.core.convert; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/package-info.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/package-info.java index ece606c9..51e8e0fb 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/package-info.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/package-info.java @@ -1,3 +1,6 @@ +/** + * Core JDBC implementation. + */ @NonNullApi package org.springframework.data.jdbc.core; diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/JdbcUtil.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/JdbcUtil.java index f1cc782e..e1c81b4b 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/JdbcUtil.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/JdbcUtil.java @@ -87,7 +87,7 @@ public class JdbcUtil { /** * Converts a {@link JDBCType} to an {@code int} value as defined in {@link Types}. - * + * * @param jdbcType value to be converted. May be {@literal null}. * @return One of the values defined in {@link Types} or {@link JdbcUtils#TYPE_UNKNOWN}. */ @@ -98,7 +98,7 @@ public class JdbcUtil { /** * Converts a value defined in {@link Types} into a {@link JDBCType} instance or {@literal null} if the value is * {@link JdbcUtils#TYPE_UNKNOWN} - * + * * @param sqlType One of the values defined in {@link Types} or {@link JdbcUtils#TYPE_UNKNOWN}. * @return a matching {@link JDBCType} instance or {@literal null}. */ @@ -121,7 +121,6 @@ public class JdbcUtil { */ @Nullable public static JDBCType jdbcTypeFor(Class type) { - return jdbcTypeFor(sqlTypeFor(type)); } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategyUnitTests.java index 621c2194..d6d9ea10 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategyUnitTests.java @@ -27,6 +27,7 @@ import java.util.HashMap; import org.junit.Test; import org.mockito.ArgumentCaptor; + import org.springframework.core.convert.converter.Converter; import org.springframework.data.annotation.Id; import org.springframework.data.convert.ReadingConverter; @@ -37,6 +38,7 @@ import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.JdbcCustomConversions; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.relational.core.mapping.RelationalMappingContext; +import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.support.KeyHolder; @@ -52,10 +54,11 @@ public class DefaultDataAccessStrategyUnitTests { public static final long ID_FROM_ADDITIONAL_VALUES = 23L; public static final long ORIGINAL_ID = 4711L; - NamedParameterJdbcOperations jdbcOperations = mock(NamedParameterJdbcOperations.class); + NamedParameterJdbcOperations namedJdbcOperations = mock(NamedParameterJdbcOperations.class); + JdbcOperations jdbcOperations = mock(JdbcOperations.class); RelationalMappingContext context = new JdbcMappingContext(); JdbcConverter converter = new BasicJdbcConverter(context, new JdbcCustomConversions(), - new DefaultJdbcTypeFactory(jdbcOperations.getJdbcOperations())); + new DefaultJdbcTypeFactory(jdbcOperations)); HashMap additionalParameters = new HashMap<>(); ArgumentCaptor paramSourceCaptor = ArgumentCaptor.forClass(SqlParameterSource.class); @@ -63,7 +66,7 @@ public class DefaultDataAccessStrategyUnitTests { new SqlGeneratorSource(context), // context, // converter, // - jdbcOperations); + namedJdbcOperations); @Test // DATAJDBC-146 public void additionalParameterForIdDoesNotLeadToDuplicateParameters() { @@ -72,7 +75,7 @@ public class DefaultDataAccessStrategyUnitTests { accessStrategy.insert(new DummyEntity(ORIGINAL_ID), DummyEntity.class, additionalParameters); - verify(jdbcOperations).update(eq("INSERT INTO dummy_entity (id) VALUES (:id)"), paramSourceCaptor.capture(), + verify(namedJdbcOperations).update(eq("INSERT INTO dummy_entity (id) VALUES (:id)"), paramSourceCaptor.capture(), any(KeyHolder.class)); } @@ -85,7 +88,7 @@ public class DefaultDataAccessStrategyUnitTests { accessStrategy.insert(new DummyEntity(ORIGINAL_ID), DummyEntity.class, additionalParameters); - verify(jdbcOperations).update(sqlCaptor.capture(), paramSourceCaptor.capture(), any(KeyHolder.class)); + verify(namedJdbcOperations).update(sqlCaptor.capture(), paramSourceCaptor.capture(), any(KeyHolder.class)); assertThat(sqlCaptor.getValue()) // .containsSequence("INSERT INTO dummy_entity (", "id", ") VALUES (", ":id", ")") // @@ -98,13 +101,13 @@ public class DefaultDataAccessStrategyUnitTests { JdbcConverter converter = new BasicJdbcConverter(context, new JdbcCustomConversions(Arrays.asList(BooleanToStringConverter.INSTANCE, StringToBooleanConverter.INSTANCE)), - new DefaultJdbcTypeFactory(jdbcOperations.getJdbcOperations())); + new DefaultJdbcTypeFactory(jdbcOperations)); DefaultDataAccessStrategy accessStrategy = new DefaultDataAccessStrategy( // new SqlGeneratorSource(context), // context, // converter, // - jdbcOperations); + namedJdbcOperations); ArgumentCaptor sqlCaptor = ArgumentCaptor.forClass(String.class); @@ -112,7 +115,7 @@ public class DefaultDataAccessStrategyUnitTests { accessStrategy.insert(entity, EntityWithBoolean.class, new HashMap<>()); - verify(jdbcOperations).update(sqlCaptor.capture(), paramSourceCaptor.capture(), any(KeyHolder.class)); + verify(namedJdbcOperations).update(sqlCaptor.capture(), paramSourceCaptor.capture(), any(KeyHolder.class)); assertThat(paramSourceCaptor.getValue().getValue("id")).isEqualTo(ORIGINAL_ID); assertThat(paramSourceCaptor.getValue().getValue("flag")).isEqualTo("T"); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java index 379aaa72..a1a1ed59 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java @@ -31,6 +31,7 @@ import org.junit.Assume; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; @@ -422,7 +423,7 @@ public class JdbcAggregateTemplateIntegrationTests { @Test // DATAJDBC-327 public void saveAndLoadAnEntityWithByteArray() { ByteArrayOwner owner = new ByteArrayOwner(); - owner.binaryData = new byte[]{1, 23, 42}; + owner.binaryData = new byte[] { 1, 23, 42 }; ByteArrayOwner saved = template.save(owner); @@ -430,10 +431,9 @@ public class JdbcAggregateTemplateIntegrationTests { assertThat(reloaded).isNotNull(); assertThat(reloaded.id).isEqualTo(saved.id); - assertThat(reloaded.binaryData).isEqualTo(new byte[]{1, 23, 42}); + assertThat(reloaded.binaryData).isEqualTo(new byte[] { 1, 23, 42 }); } - private static void assumeNot(String dbProfileName) { Assume.assumeTrue("true" diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/BasicRelationalConverterAggregateReferenceUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/BasicRelationalConverterAggregateReferenceUnitTests.java index 1fb1cb70..c40f8cee 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/BasicRelationalConverterAggregateReferenceUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/BasicRelationalConverterAggregateReferenceUnitTests.java @@ -38,12 +38,8 @@ import org.springframework.data.util.ClassTypeInformation; */ public class BasicRelationalConverterAggregateReferenceUnitTests { - SoftAssertions softly = new SoftAssertions(); - - ConversionService conversionService = new DefaultConversionService(); - JdbcMappingContext context = new JdbcMappingContext(); - RelationalConverter converter = new BasicJdbcConverter(context, JdbcTypeFactory.unsupported()); + RelationalConverter converter = new BasicJdbcConverter(context); RelationalPersistentEntity entity = context.getRequiredPersistentEntity(DummyEntity.class); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCustomConversionIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCustomConversionIntegrationTests.java index b2bc4ac5..a6901402 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCustomConversionIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCustomConversionIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 the original author or authors. + * Copyright 2019 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. @@ -25,6 +25,7 @@ import java.util.Optional; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -84,23 +85,21 @@ public class JdbcRepositoryCustomConversionIntegrationTests { * In PostrgreSQL this fails if a simple converter like the following is used. * *
-	 * {@code
-	 @WritingConverter enum PlainStringToBigDecimalConverter implements Converter {
-	
-	 	INSTANCE;
-	
-	 	@Override
-	 	@Nullable
-	 	public BigDecimal convert(@Nullable String source) {
-	
-	 		return source == null ? null : new BigDecimal(source);
-	 	}
-	
-	 }
-	}
+	 *
+	 * @WritingConverter
+	 * enum PlainStringToBigDecimalConverter implements Converter {
+	 *
+	 * 	INSTANCE;
+	 *
+	 * 	@Override
+	 * 	@Nullable
+	 * 	public BigDecimal convert(@Nullable String source) {
+	 *
+	 * 		return source == null ? null : new BigDecimal(source);
+	 * 	}
+	 * }
 	 * 
*/ - @Test // DATAJDBC-327 public void saveAndLoadAnEntity() { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java index ed64d1c1..6136f3f9 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java @@ -33,6 +33,7 @@ import org.assertj.core.groups.Tuple; import org.junit.Before; import org.junit.Test; import org.mockito.stubbing.Answer; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.core.DefaultDataAccessStrategy; @@ -53,6 +54,7 @@ import org.springframework.data.relational.core.mapping.event.BeforeSaveEvent; import org.springframework.data.relational.core.mapping.event.Identifier; import org.springframework.data.relational.core.mapping.event.RelationalEvent; import org.springframework.data.repository.CrudRepository; +import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.support.KeyHolder; @@ -224,6 +226,7 @@ public class SimpleJdbcRepositoryEventsUnitTests { NamedParameterJdbcOperations operations = mock(NamedParameterJdbcOperations.class); when(operations.update(anyString(), any(SqlParameterSource.class), any(KeyHolder.class))) .thenAnswer(setIdInKeyHolder); + when(operations.getJdbcOperations()).thenReturn(mock(JdbcOperations.class)); return operations; } diff --git a/src/main/asciidoc/jdbc.adoc b/src/main/asciidoc/jdbc.adoc index d1592ccb..93b5478e 100644 --- a/src/main/asciidoc/jdbc.adoc +++ b/src/main/asciidoc/jdbc.adoc @@ -190,9 +190,9 @@ Converters should be annotated with `@ReadingConverter` or `@WritingConverter` i ==== JdbcValue -When setting bind parameters with a JDBC driver one may opt to provide a `java.sql.Types` constant value to denote the type of the parameter. -If for a value this type need to be specified this can be done by using a writing converter as described in the previous section. -This converter should convert to `JdbcValue` which has a field for the value and one of for the `JDBCType`. +Value conversion uses `JdbcValue` to enrich values propagated to JDBC operations with a `java.sql.Types` type. +Register a custom write converter if you need to specify a JDBC-specific type instead of using type derivation. +This converter should convert the value to `JdbcValue` which has a field for the value and for the actual `JDBCType`. [[jdbc.entity-persistence.naming-strategy]] === `NamingStrategy`