Skip to content

Commit c2062db

Browse files
THD-Thomas-Langschauder
authored andcommitted
DATAJDBC-341 - Map NULL values in EntityRowMapper for columns not being fetched in the query.
Original pull request: #170.
1 parent 6769528 commit c2062db

File tree

2 files changed

+82
-8
lines changed

2 files changed

+82
-8
lines changed

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@
5959
* @author Jens Schauder
6060
* @author Christoph Strobl
6161
* @author Myeonghyeon Lee
62-
* @since 1.1
6362
* @see MappingContext
6463
* @see SimpleTypeHolder
6564
* @see CustomConversions
65+
* @since 1.1
6666
*/
6767
public class BasicJdbcConverter extends BasicRelationalConverter implements JdbcConverter {
6868

@@ -401,7 +401,35 @@ private T populateProperties(T instance, @Nullable Object idValue) {
401401
continue;
402402
}
403403

404-
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
404+
// check if property is in the result set
405+
// if not - leave it out
406+
// DATAJDBC-341
407+
if (property.isEntity() || property.isEmbedded()) {
408+
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
409+
} else {
410+
try {
411+
if (resultSet.findColumn(property.getColumnName().getReference(identifierProcessing)) > 0) {
412+
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
413+
} else {
414+
try {
415+
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
416+
} catch (Exception exception) {
417+
LOG.info(
418+
"The result set is not corresponding to the target entity. Left out properties will be set to standard values (NULL for reference types, 0 for primitives.");
419+
}
420+
}
421+
} catch (SQLException e) {
422+
String columnAlias = path.extendBy(property).getColumnAlias().getReference(identifierProcessing);
423+
try {
424+
if (resultSet.findColumn(columnAlias) > 0) {
425+
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
426+
}
427+
} catch (SQLException ex) {
428+
LOG.info(String.format("Cannot find column named %s within the result set!", property.getColumnName()));
429+
}
430+
}
431+
}
432+
405433
}
406434

407435
return propertyAccessor.getBean();
@@ -523,7 +551,8 @@ private Object getObjectFromResultSet(String backreferenceName) {
523551
try {
524552
return resultSet.getObject(backreferenceName);
525553
} catch (SQLException o_O) {
526-
throw new MappingException(String.format("Could not read value %s from result set!", backreferenceName), o_O);
554+
LOG.info(String.format("Could not read value %s from result set! Use null as value.", backreferenceName), o_O);
555+
return null;
527556
}
528557
}
529558

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,7 @@
3232

3333
import java.sql.ResultSet;
3434
import java.sql.SQLException;
35-
import java.util.ArrayList;
36-
import java.util.HashMap;
37-
import java.util.List;
38-
import java.util.Map;
39-
import java.util.Set;
35+
import java.util.*;
4036
import java.util.function.Function;
4137
import java.util.stream.Collectors;
4238
import java.util.stream.Stream;
@@ -87,6 +83,35 @@ public String getColumnName(RelationalPersistentProperty property) {
8783
}
8884
};
8985

86+
@Test // DATAJDBC-341
87+
public void mapNotNeededValueTypePropertiesToNull() throws SQLException {
88+
ResultSet rs = mockResultSet(singletonList("id"), //
89+
ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha");
90+
rs.next();
91+
Trivial extracted = createRowMapper(Trivial.class).mapRow(rs, 1);
92+
93+
assertThat(extracted) //
94+
.isNotNull() //
95+
.extracting(e -> e.id, e -> e.name) //
96+
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, null);
97+
98+
}
99+
100+
@Test // DATAJDBC-341
101+
public void mapNotNeededPrimitiveTypePropertiesToNull() throws SQLException {
102+
ResultSet rs = mockResultSet(singletonList("id"), //
103+
ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha");
104+
rs.next();
105+
TrivialMapPropertiesToNullIfNotNeeded extracted = createRowMapper(TrivialMapPropertiesToNullIfNotNeeded.class)
106+
.mapRow(rs, 1);
107+
108+
assertThat(extracted) //
109+
.isNotNull() //
110+
.extracting(e -> e.id, e -> e.age) //
111+
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, 0);
112+
113+
}
114+
90115
@Test // DATAJDBC-113
91116
public void simpleEntitiesGetProperlyExtracted() throws SQLException {
92117

@@ -477,6 +502,19 @@ static class Trivial {
477502
String name;
478503
}
479504

505+
@EqualsAndHashCode
506+
@NoArgsConstructor
507+
@AllArgsConstructor
508+
@Getter
509+
static class TrivialMapPropertiesToNullIfNotNeeded {
510+
511+
@Id Long id;
512+
int age;
513+
String phone;
514+
Boolean isSupreme;
515+
long referenceToCustomer;
516+
}
517+
480518
@EqualsAndHashCode
481519
@NoArgsConstructor
482520
@AllArgsConstructor
@@ -762,11 +800,18 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
762800
return isAfterLast() || isBeforeFirst() ? 0 : index + 1;
763801
case "toString":
764802
return this.toString();
803+
case "findColumn":
804+
return isThereAColumnNamed(invocation.getArgument(0));
765805
default:
766806
throw new OperationNotSupportedException(invocation.getMethod().getName());
767807
}
768808
}
769809

810+
private int isThereAColumnNamed(String name) {
811+
Optional<Map<String, Object>> first = values.stream().filter(s -> s.equals(name)).findFirst();
812+
return (first.isPresent()) ? 1 : 0;
813+
}
814+
770815
private boolean isAfterLast() {
771816
return index >= values.size() && !values.isEmpty();
772817
}

0 commit comments

Comments
 (0)