From b287cb23a6066ec05c743f2a3f23abbb40a81fb2 Mon Sep 17 00:00:00 2001 From: Thomas Lang Date: Fri, 20 Sep 2019 12:35:58 +0200 Subject: [PATCH] DATAJDBC-341 - Map NULL values in EntityRowMapper for columns not being fetched in the query (fixed tests) --- .../jdbc/core/convert/BasicJdbcConverter.java | 35 +++++++++++- .../convert/EntityRowMapperUnitTests.java | 55 +++++++++++++++++-- 2 files changed, 82 insertions(+), 8 deletions(-) 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 8cde089b9b..7ee274f762 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 @@ -58,10 +58,10 @@ * @author Jens Schauder * @author Christoph Strobl * @author Myeonghyeon Lee - * @since 1.1 * @see MappingContext * @see SimpleTypeHolder * @see CustomConversions + * @since 1.1 */ public class BasicJdbcConverter extends BasicRelationalConverter implements JdbcConverter { @@ -324,7 +324,35 @@ private T populateProperties(T instance, @Nullable Object idValue) { continue; } - propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property)); + // check if property is in the result set + // if not - leave it out + // DATAJDBC-341 + if (property.isEntity() || property.isEmbedded()) { + propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property)); + } else { + try { + if (resultSet.findColumn(property.getColumnName()) > 0) { + propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property)); + } else { + try { + propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property)); + } catch (Exception exception) { + LOG.info( + "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."); + } + } + } catch (SQLException e) { + String columnAlias = path.extendBy(property).getColumnAlias(); + try { + if (resultSet.findColumn(columnAlias) > 0) { + propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property)); + } + } catch (SQLException ex) { + LOG.info(String.format("Cannot find column named %s within the result set!", property.getColumnName())); + } + } + } + } return propertyAccessor.getBean(); @@ -444,7 +472,8 @@ private Object getObjectFromResultSet(String backreferenceName) { try { return resultSet.getObject(backreferenceName); } catch (SQLException o_O) { - throw new MappingException(String.format("Could not read value %s from result set!", backreferenceName), o_O); + LOG.info(String.format("Could not read value %s from result set! Use null as value.", backreferenceName), o_O); + return null; } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java index fd5208c38d..f146a3c90e 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java @@ -32,11 +32,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -85,6 +81,35 @@ public String getColumnName(RelationalPersistentProperty property) { } }; + @Test // DATAJDBC-341 + public void mapNotNeededValueTypePropertiesToNull() throws SQLException { + ResultSet rs = mockResultSet(singletonList("id"), // + ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha"); + rs.next(); + Trivial extracted = createRowMapper(Trivial.class).mapRow(rs, 1); + + assertThat(extracted) // + .isNotNull() // + .extracting(e -> e.id, e -> e.name) // + .containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, null); + + } + + @Test // DATAJDBC-341 + public void mapNotNeededPrimitiveTypePropertiesToNull() throws SQLException { + ResultSet rs = mockResultSet(singletonList("id"), // + ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha"); + rs.next(); + TrivialMapPropertiesToNullIfNotNeeded extracted = createRowMapper(TrivialMapPropertiesToNullIfNotNeeded.class) + .mapRow(rs, 1); + + assertThat(extracted) // + .isNotNull() // + .extracting(e -> e.id, e -> e.age) // + .containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, 0); + + } + @Test // DATAJDBC-113 public void simpleEntitiesGetProperlyExtracted() throws SQLException { @@ -475,6 +500,19 @@ static class Trivial { String name; } + @EqualsAndHashCode + @NoArgsConstructor + @AllArgsConstructor + @Getter + static class TrivialMapPropertiesToNullIfNotNeeded { + + @Id Long id; + int age; + String phone; + Boolean isSupreme; + long referenceToCustomer; + } + @EqualsAndHashCode @NoArgsConstructor @AllArgsConstructor @@ -760,11 +798,18 @@ public Object answer(InvocationOnMock invocation) throws Throwable { return isAfterLast() || isBeforeFirst() ? 0 : index + 1; case "toString": return this.toString(); + case "findColumn": + return isThereAColumnNamed(invocation.getArgument(0)); default: throw new OperationNotSupportedException(invocation.getMethod().getName()); } } + private int isThereAColumnNamed(String name) { + Optional> first = values.stream().filter(s -> s.equals(name)).findFirst(); + return (first.isPresent()) ? 1 : 0; + } + private boolean isAfterLast() { return index >= values.size() && !values.isEmpty(); }