Skip to content

Commit 3c9765c

Browse files
schaudergregturn
authored andcommitted
DATAJDBC-147 - Support registration von converters via ConversionCustomizers.
1 parent 207278c commit 3c9765c

17 files changed

+127
-47
lines changed

src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,9 @@
2121
import java.util.stream.Collectors;
2222
import java.util.stream.StreamSupport;
2323

24-
import org.springframework.core.convert.ConversionService;
25-
import org.springframework.core.convert.support.DefaultConversionService;
26-
import org.springframework.core.convert.support.GenericConversionService;
2724
import org.springframework.dao.EmptyResultDataAccessException;
2825
import org.springframework.dao.InvalidDataAccessApiUsageException;
2926
import org.springframework.dao.NonTransientDataAccessException;
30-
import org.springframework.data.convert.Jsr310Converters;
3127
import org.springframework.data.jdbc.mapping.model.BasicJdbcPersistentEntityInformation;
3228
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
3329
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
@@ -58,7 +54,6 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
5854
private final SqlGeneratorSource sqlGeneratorSource;
5955
private final NamedParameterJdbcOperations operations;
6056
private final JdbcMappingContext context;
61-
private final ConversionService conversions = getDefaultConversionService();
6257
private final DataAccessStrategy accessStrategy;
6358

6459
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, NamedParameterJdbcOperations operations,
@@ -222,14 +217,6 @@ public <T> boolean existsById(Object id, Class<T> domainType) {
222217
return operations.queryForObject(existsSql, parameter, Boolean.class);
223218
}
224219

225-
private static GenericConversionService getDefaultConversionService() {
226-
227-
DefaultConversionService conversionService = new DefaultConversionService();
228-
Jsr310Converters.getConvertersToRegister().forEach(conversionService::addConverter);
229-
230-
return conversionService;
231-
}
232-
233220
private <S> MapSqlParameterSource getPropertyMap(final S instance, JdbcPersistentEntity<S> persistentEntity) {
234221

235222
MapSqlParameterSource parameters = new MapSqlParameterSource();
@@ -295,7 +282,7 @@ private <S> Optional<Object> getIdFromHolder(KeyHolder holder, JdbcPersistentEnt
295282
}
296283

297284
private <T> EntityRowMapper<T> getEntityRowMapper(Class<T> domainType) {
298-
return new EntityRowMapper<>(getRequiredPersistentEntity(domainType), conversions, context, accessStrategy);
285+
return new EntityRowMapper<>(getRequiredPersistentEntity(domainType), context.getConversions(), context, accessStrategy);
299286
}
300287

301288
private RowMapper getMapEntityRowMapper(JdbcPersistentProperty property) {
@@ -323,7 +310,7 @@ private <V> V convert(Object from, Class<V> to) {
323310

324311
Object id = persistentEntity == null ? null : persistentEntity.getIdentifierAccessor(from).getIdentifier();
325312

326-
return conversions.convert(id == null ? from : id, to);
313+
return context.getConversions().convert(id == null ? from : id, to);
327314
}
328315

329316
private SqlGenerator sql(Class<?> domainType) {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jdbc.mapping.model;
17+
18+
import org.springframework.core.convert.support.GenericConversionService;
19+
20+
/**
21+
* @author Jens Schauder
22+
*/
23+
public interface ConversionCustomizer {
24+
25+
void customize(GenericConversionService conversions);
26+
}

src/main/java/org/springframework/data/jdbc/mapping/model/JdbcMappingContext.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
import java.util.HashSet;
2828
import java.util.List;
2929

30+
import org.springframework.core.convert.ConversionService;
31+
import org.springframework.core.convert.support.DefaultConversionService;
32+
import org.springframework.core.convert.support.GenericConversionService;
33+
import org.springframework.data.convert.Jsr310Converters;
3034
import org.springframework.data.mapping.PropertyPath;
3135
import org.springframework.data.mapping.context.AbstractMappingContext;
3236
import org.springframework.data.mapping.context.MappingContext;
@@ -50,13 +54,21 @@ public class JdbcMappingContext extends AbstractMappingContext<JdbcPersistentEnt
5054
));
5155

5256
private final @Getter NamingStrategy namingStrategy;
57+
private GenericConversionService conversions = getDefaultConversionService();
5358

54-
public JdbcMappingContext(NamingStrategy namingStrategy) {
59+
public JdbcMappingContext(NamingStrategy namingStrategy, ConversionCustomizer customizer) {
5560

5661
this.namingStrategy = namingStrategy;
62+
63+
customizer.customize(conversions);
64+
5765
setSimpleTypeHolder(new SimpleTypeHolder(CUSTOM_SIMPLE_TYPES, true));
5866
}
5967

68+
public JdbcMappingContext() {
69+
this(new DefaultNamingStrategy(), __ -> {});
70+
}
71+
6072
public List<PropertyPath> referencedEntities(Class<?> rootType, PropertyPath path) {
6173

6274
List<PropertyPath> paths = new ArrayList<>();
@@ -103,4 +115,16 @@ protected JdbcPersistentProperty createPersistentProperty(Property property, Jdb
103115
return new BasicJdbcPersistentEntityInformation<>((JdbcPersistentEntity<T>) getRequiredPersistentEntity(type));
104116
}
105117

118+
public ConversionService getConversions() {
119+
return conversions;
120+
}
121+
122+
private static GenericConversionService getDefaultConversionService() {
123+
124+
DefaultConversionService conversionService = new DefaultConversionService();
125+
Jsr310Converters.getConvertersToRegister().forEach(conversionService::addConverter);
126+
127+
return conversionService;
128+
}
129+
106130
}

src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.data.jdbc.core.DefaultDataAccessStrategy;
3333
import org.springframework.data.jdbc.core.DelegatingDataAccessStrategy;
3434
import org.springframework.data.jdbc.core.SqlGeneratorSource;
35+
import org.springframework.data.jdbc.mapping.model.ConversionCustomizer;
3536
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
3637
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
3738
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
@@ -65,22 +66,23 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
6566
private static final String DATA_SOURCE_BEAN_NAME = "dataSource";
6667
private static final String NAMING_STRATEGY_BEAN_NAME = "namingStrategy";
6768
private static final String SQL_SESSION_FACTORY_BEAN_NAME = "sqlSessionFactory";
69+
private static final String CONVERSION_CUSTOMIZER_BEAN_NAME = "conversionCustomizer";
6870

6971
private final ApplicationEventPublisher applicationEventPublisher;
70-
private final ApplicationContext context;
72+
private final ApplicationContext applicationContext;
7173

7274
JdbcRepositoryFactoryBean(Class<? extends T> repositoryInterface, ApplicationEventPublisher applicationEventPublisher,
73-
ApplicationContext context) {
75+
ApplicationContext applicationContext) {
7476

7577
super(repositoryInterface);
7678
this.applicationEventPublisher = applicationEventPublisher;
77-
this.context = context;
79+
this.applicationContext = applicationContext;
7880
}
7981

8082
@Override
8183
protected RepositoryFactorySupport doCreateRepositoryFactory() {
8284

83-
final JdbcMappingContext context = new JdbcMappingContext(findOrCreateNamingStrategy());
85+
final JdbcMappingContext context = new JdbcMappingContext(findOrCreateNamingStrategy(), findOrCreateConversionCustomizer());
8486

8587
return new JdbcRepositoryFactory(applicationEventPublisher, context, createDataAccessStrategy(context));
8688
}
@@ -156,6 +158,10 @@ private NamingStrategy findOrCreateNamingStrategy() {
156158
return getNamingStrategy().orElse(new DefaultNamingStrategy());
157159
}
158160

161+
private ConversionCustomizer findOrCreateConversionCustomizer() {
162+
return getConversionCustomizer().orElse(conversionService->{});
163+
}
164+
159165
private Optional<NamedParameterJdbcOperations> getNamedParameterJdbcOperations() {
160166
return getBean(NamedParameterJdbcOperations.class, NAMED_PARAMETER_JDBC_OPERATIONS_BEAN_NAME);
161167
}
@@ -172,9 +178,13 @@ private Optional<NamingStrategy> getNamingStrategy() {
172178
return getBean(NamingStrategy.class, NAMING_STRATEGY_BEAN_NAME);
173179
}
174180

181+
private Optional<ConversionCustomizer> getConversionCustomizer() {
182+
return getBean(ConversionCustomizer.class, CONVERSION_CUSTOMIZER_BEAN_NAME);
183+
}
184+
175185
private <R> Optional<R> getBean(Class<R> type, String name) {
176186

177-
Map<String, R> beansOfType = context.getBeansOfType(type);
187+
Map<String, R> beansOfType = applicationContext.getBeansOfType(type);
178188

179189
if (beansOfType.size() == 1) {
180190
return beansOfType.values().stream().findFirst();

src/test/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategyUnitTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@
1515
*/
1616
package org.springframework.data.jdbc.core;
1717

18-
import static org.assertj.core.api.Assertions.*;
19-
import static org.mockito.Mockito.*;
20-
21-
import lombok.RequiredArgsConstructor;
22-
2318
import java.util.HashMap;
2419

20+
import lombok.RequiredArgsConstructor;
2521
import org.junit.Test;
2622
import org.mockito.ArgumentCaptor;
23+
2724
import org.springframework.data.annotation.Id;
2825
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
2926
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
3027
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
3128
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
3229
import org.springframework.jdbc.support.KeyHolder;
3330

31+
import static org.assertj.core.api.Assertions.*;
32+
import static org.mockito.Mockito.*;
33+
3434
/**
3535
* @author Jens Schauder
3636
*/
@@ -39,7 +39,7 @@ public class DefaultDataAccessStrategyUnitTests {
3939
public static final long ID_FROM_ADDITIONAL_VALUES = 23L;
4040
public static final long ORIGINAL_ID = 4711L;
4141

42-
JdbcMappingContext context = new JdbcMappingContext(new DefaultNamingStrategy());
42+
JdbcMappingContext context = new JdbcMappingContext(new DefaultNamingStrategy(), __ -> {});
4343
NamedParameterJdbcOperations jdbcOperations = mock(NamedParameterJdbcOperations.class);
4444
HashMap<String, Object> additionalParameters = new HashMap<>();
4545
ArgumentCaptor<SqlParameterSource> captor = ArgumentCaptor.forClass(SqlParameterSource.class);

src/test/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreterUnitTests.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@
1515
*/
1616
package org.springframework.data.jdbc.core;
1717

18-
import static org.assertj.core.api.Assertions.*;
19-
import static org.mockito.Mockito.*;
20-
2118
import java.util.AbstractMap.SimpleEntry;
2219
import java.util.Map;
2320

2421
import org.junit.Test;
2522
import org.mockito.ArgumentCaptor;
23+
2624
import org.springframework.data.annotation.Id;
2725
import org.springframework.data.jdbc.core.conversion.DbAction;
2826
import org.springframework.data.jdbc.core.conversion.DbAction.Insert;
@@ -31,6 +29,9 @@
3129
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
3230
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
3331

32+
import static org.assertj.core.api.Assertions.*;
33+
import static org.mockito.Mockito.*;
34+
3435
/**
3536
* Unit tests for {@link DefaultJdbcInterpreter}
3637
*
@@ -46,7 +47,7 @@ public class DefaultJdbcInterpreterUnitTests {
4647
public String getReverseColumnName(JdbcPersistentProperty property) {
4748
return BACK_REFERENCE;
4849
}
49-
});
50+
}, __ -> {});
5051

5152
DataAccessStrategy dataAccessStrategy = mock(DataAccessStrategy.class);
5253
DefaultJdbcInterpreter interpreter = new DefaultJdbcInterpreter(context, dataAccessStrategy);

src/test/java/org/springframework/data/jdbc/core/EntityRowMapperUnitTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import org.springframework.core.convert.support.GenericConversionService;
4141
import org.springframework.data.annotation.Id;
4242
import org.springframework.data.convert.Jsr310Converters;
43-
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
4443
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
4544
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
4645
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
@@ -118,7 +117,7 @@ public void mapReferenceGetsLoadedWithAdditionalSelect() throws SQLException {
118117

119118
private <T> EntityRowMapper<T> createRowMapper(Class<T> type) {
120119

121-
JdbcMappingContext context = new JdbcMappingContext(new DefaultNamingStrategy());
120+
JdbcMappingContext context = new JdbcMappingContext();
122121
DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class);
123122

124123
// the ID of the entity is used to determin what kind of resultset is needed for subsequent selects.

src/test/java/org/springframework/data/jdbc/core/JdbcEntityTemplateIntegrationTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.springframework.context.annotation.Configuration;
3131
import org.springframework.context.annotation.Import;
3232
import org.springframework.data.annotation.Id;
33-
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
3433
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
3534
import org.springframework.data.jdbc.testing.TestConfiguration;
3635
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@@ -254,7 +253,7 @@ Class<?> testClass() {
254253
JdbcEntityOperations operations(ApplicationEventPublisher publisher,
255254
NamedParameterJdbcOperations namedParameterJdbcOperations) {
256255

257-
final JdbcMappingContext context = new JdbcMappingContext(new DefaultNamingStrategy());
256+
final JdbcMappingContext context = new JdbcMappingContext();
258257
return new JdbcEntityTemplate(publisher, context, dataAccessStrategy(namedParameterJdbcOperations, context));
259258
}
260259

src/test/java/org/springframework/data/jdbc/core/SqlGeneratorContextBasedNamingStrategyUnitTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ private void threadedTest(String user, CountDownLatch latch, Consumer<String> te
185185
*/
186186
private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) {
187187

188-
JdbcMappingContext context = new JdbcMappingContext(namingStrategy);
188+
JdbcMappingContext context = new JdbcMappingContext(namingStrategy, __ -> {});
189189
JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
190190

191191
return new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));

src/test/java/org/springframework/data/jdbc/core/SqlGeneratorFixedNamingStrategyUnitTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public void deleteByList() {
180180
*/
181181
private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) {
182182

183-
JdbcMappingContext context = new JdbcMappingContext(namingStrategy);
183+
JdbcMappingContext context = new JdbcMappingContext(namingStrategy, __ -> {});
184184
JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
185185
return new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));
186186
}

src/test/java/org/springframework/data/jdbc/core/SqlGeneratorUnitTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class SqlGeneratorUnitTests {
4646
public void setUp() {
4747

4848
NamingStrategy namingStrategy = new PrefixingNamingStrategy();
49-
JdbcMappingContext context = new JdbcMappingContext(namingStrategy);
49+
JdbcMappingContext context = new JdbcMappingContext(namingStrategy, __ -> {});
5050
JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
5151
this.sqlGenerator = new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));
5252
}

src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.springframework.data.annotation.Id;
2626
import org.springframework.data.jdbc.core.conversion.AggregateChange.Kind;
2727
import org.springframework.data.jdbc.core.conversion.DbAction.Delete;
28-
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
2928
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
3029

3130
/**
@@ -36,7 +35,7 @@
3635
@RunWith(MockitoJUnitRunner.class)
3736
public class JdbcEntityDeleteWriterUnitTests {
3837

39-
JdbcEntityDeleteWriter converter = new JdbcEntityDeleteWriter(new JdbcMappingContext(new DefaultNamingStrategy()));
38+
JdbcEntityDeleteWriter converter = new JdbcEntityDeleteWriter(new JdbcMappingContext());
4039

4140
@Test
4241
public void deleteDeletesTheEntityAndReferencedEntities() {

src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import org.springframework.data.jdbc.core.conversion.DbAction.Delete;
3333
import org.springframework.data.jdbc.core.conversion.DbAction.Insert;
3434
import org.springframework.data.jdbc.core.conversion.DbAction.Update;
35-
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
3635
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
3736

3837
/**
@@ -44,7 +43,7 @@
4443
public class JdbcEntityWriterUnitTests {
4544

4645
public static final long SOME_ENTITY_ID = 23L;
47-
JdbcEntityWriter converter = new JdbcEntityWriter(new JdbcMappingContext(new DefaultNamingStrategy()));
46+
JdbcEntityWriter converter = new JdbcEntityWriter(new JdbcMappingContext());
4847

4948
@Test // DATAJDBC-112
5049
public void newEntityGetsConvertedToOneInsert() {

src/test/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentPropertyUnitTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class BasicJdbcPersistentPropertyUnitTests {
3737
@Test // DATAJDBC-104
3838
public void enumGetsStoredAsString() {
3939

40-
JdbcPersistentEntity<?> persistentEntity = new JdbcMappingContext(new DefaultNamingStrategy())
40+
JdbcPersistentEntity<?> persistentEntity = new JdbcMappingContext()
4141
.getRequiredPersistentEntity(DummyEntity.class);
4242

4343
persistentEntity.doWithProperties((PropertyHandler<JdbcPersistentProperty>) p -> {

src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.springframework.data.jdbc.mapping.event.BeforeSave;
2828
import org.springframework.data.jdbc.mapping.event.Identifier;
2929
import org.springframework.data.jdbc.mapping.event.JdbcEvent;
30-
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
3130
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
3231
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
3332
import org.springframework.data.repository.CrudRepository;
@@ -47,7 +46,7 @@ public class SimpleJdbcRepositoryEventsUnitTests {
4746
@Before
4847
public void before() {
4948

50-
final JdbcMappingContext context = new JdbcMappingContext(new DefaultNamingStrategy());
49+
final JdbcMappingContext context = new JdbcMappingContext();
5150
JdbcRepositoryFactory factory = new JdbcRepositoryFactory( //
5251
publisher, //
5352
context, //

0 commit comments

Comments
 (0)