Skip to content

Commit 18bf6ca

Browse files
schaudergregturn
authored andcommitted
DATAJDBC-181 - Use NamingStrategy for instantiating entities.
The ResultSetParameterValueProvider uses the relevant property for a requested parameter in order to obtain the proper column name to use. Improved mocking of ResultSets in tests to actually fail when a non existing column gets requested instead of just returning null.
1 parent 043bd4d commit 18bf6ca

File tree

2 files changed

+70
-21
lines changed

2 files changed

+70
-21
lines changed

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

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.data.jdbc.core;
1717

1818
import lombok.NonNull;
19+
import lombok.RequiredArgsConstructor;
1920
import org.springframework.core.convert.ConversionService;
2021
import org.springframework.core.convert.converter.Converter;
2122
import org.springframework.data.convert.ClassGeneratingEntityInstantiator;
@@ -94,7 +95,7 @@ public T mapRow(ResultSet resultSet, int rowNumber) throws SQLException {
9495
}
9596

9697
private T createInstance(ResultSet rs) {
97-
return instantiator.createInstance(entity, ResultSetParameterValueProvider.of(rs, conversions, ""));
98+
return instantiator.createInstance(entity, new ResultSetParameterValueProvider(rs, entity, conversions, ""));
9899
}
99100

100101
private Object readFrom(ResultSet resultSet, JdbcPersistentProperty property, String prefix) {
@@ -123,7 +124,7 @@ private <S> S readEntityFrom(ResultSet rs, PersistentProperty<?> property) {
123124
return null;
124125
}
125126

126-
S instance = instantiator.createInstance(entity, ResultSetParameterValueProvider.of(rs, conversions, prefix));
127+
S instance = instantiator.createInstance(entity, new ResultSetParameterValueProvider(rs, entity, conversions, prefix));
127128

128129
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(instance);
129130
ConvertingPropertyAccessor propertyAccessor = new ConvertingPropertyAccessor(accessor, conversions);
@@ -135,40 +136,27 @@ private <S> S readEntityFrom(ResultSet rs, PersistentProperty<?> property) {
135136
return instance;
136137
}
137138

139+
@RequiredArgsConstructor
138140
private static class ResultSetParameterValueProvider implements ParameterValueProvider<JdbcPersistentProperty> {
139141

140142
@NonNull
141143
private final ResultSet resultSet;
142144
@NonNull
145+
private final JdbcPersistentEntity<?> entity;
146+
@NonNull
143147
private final ConversionService conversionService;
144148
@NonNull
145149
private final String prefix;
146150

147-
private ResultSetParameterValueProvider(ResultSet resultSet, ConversionService conversionService, String prefix) {
148-
149-
this.resultSet = resultSet;
150-
this.conversionService = conversionService;
151-
this.prefix = prefix;
152-
}
153-
154-
public static ResultSetParameterValueProvider of(ResultSet resultSet, ConversionService conversionService,
155-
String prefix) {
156-
return new ResultSetParameterValueProvider(resultSet, conversionService, prefix);
157-
}
158-
159151
/*
160152
* (non-Javadoc)
161153
* @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
162154
*/
163155
@Override
164156
public <T> T getParameterValue(Parameter<T, JdbcPersistentProperty> parameter) {
165157

166-
String name = parameter.getName();
167-
if (name == null) {
168-
return null;
169-
}
158+
String column = prefix + entity.getRequiredPersistentProperty(parameter.getName()).getColumnName();
170159

171-
String column = prefix + name;
172160
try {
173161
return conversionService.convert(resultSet.getObject(column), parameter.getType().getType());
174162
} catch (SQLException o_O) {

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

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
import org.springframework.core.convert.support.GenericConversionService;
2424
import org.springframework.data.annotation.Id;
2525
import org.springframework.data.convert.Jsr310Converters;
26+
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
2627
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
2728
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
2829
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
30+
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
31+
import org.springframework.data.repository.query.Param;
2932
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
3033
import org.springframework.util.Assert;
3134

@@ -54,6 +57,12 @@ public class EntityRowMapperUnitTests {
5457
public static final long ID_FOR_ENTITY_REFERENCING_MAP = 42L;
5558
public static final long ID_FOR_ENTITY_REFERENCING_LIST = 4711L;
5659
public static final long ID_FOR_ENTITY_NOT_REFERENCING_MAP = 23L;
60+
public static final DefaultNamingStrategy X_APPENDING_NAMINGSTRATEGY = new DefaultNamingStrategy() {
61+
@Override
62+
public String getColumnName(JdbcPersistentProperty property) {
63+
return super.getColumnName(property) + "x";
64+
}
65+
};
5766

5867
@Test // DATAJDBC-113
5968
public void simpleEntitiesGetProperlyExtracted() throws SQLException {
@@ -70,6 +79,36 @@ public void simpleEntitiesGetProperlyExtracted() throws SQLException {
7079
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha");
7180
}
7281

82+
@Test // DATAJDBC-181
83+
public void namingStrategyGetsHonored() throws SQLException {
84+
85+
ResultSet rs = mockResultSet(asList("idx", "namex"), //
86+
ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha");
87+
rs.next();
88+
89+
Trivial extracted = createRowMapper(Trivial.class, X_APPENDING_NAMINGSTRATEGY).mapRow(rs, 1);
90+
91+
assertThat(extracted) //
92+
.isNotNull() //
93+
.extracting(e -> e.id, e -> e.name) //
94+
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha");
95+
}
96+
97+
@Test // DATAJDBC-181
98+
public void namingStrategyGetsHonoredForConstructor() throws SQLException {
99+
100+
ResultSet rs = mockResultSet(asList("idx", "namex"), //
101+
ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha");
102+
rs.next();
103+
104+
TrivialImmutable extracted = createRowMapper(TrivialImmutable.class, X_APPENDING_NAMINGSTRATEGY).mapRow(rs, 1);
105+
106+
assertThat(extracted) //
107+
.isNotNull() //
108+
.extracting(e -> e.id, e -> e.name) //
109+
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha");
110+
}
111+
73112
@Test // DATAJDBC-113
74113
public void simpleOneToOneGetsProperlyExtracted() throws SQLException {
75114

@@ -131,8 +170,18 @@ public void listReferenceGetsLoadedWithAdditionalSelect() throws SQLException {
131170
}
132171

133172
private <T> EntityRowMapper<T> createRowMapper(Class<T> type) {
173+
return createRowMapper(type, new DefaultNamingStrategy());
174+
}
175+
176+
private <T> EntityRowMapper<T> createRowMapper(Class<T> type, NamingStrategy namingStrategy) {
177+
178+
JdbcMappingContext context = new JdbcMappingContext( //
179+
namingStrategy, //
180+
mock(NamedParameterJdbcOperations.class), //
181+
__ -> {
182+
} //
183+
);
134184

135-
JdbcMappingContext context = new JdbcMappingContext(mock(NamedParameterJdbcOperations.class));
136185
DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class);
137186

138187
// the ID of the entity is used to determine what kind of ResultSet is needed for subsequent selects.
@@ -240,7 +289,12 @@ private boolean isBeforeFirst() {
240289
}
241290

242291
private Object getObject(String column) {
243-
return values.get(index).get(column);
292+
293+
Map<String, Object> rowMap = values.get(index);
294+
295+
Assert.isTrue(rowMap.containsKey(column), String.format("Trying to access a column (%s) that does not exist", column));
296+
297+
return rowMap.get(column);
244298
}
245299

246300
private boolean next() {
@@ -251,6 +305,13 @@ private boolean next() {
251305
}
252306

253307
@RequiredArgsConstructor
308+
static class TrivialImmutable {
309+
310+
@Id
311+
private final Long id;
312+
private final String name;
313+
}
314+
254315
static class Trivial {
255316

256317
@Id

0 commit comments

Comments
 (0)