diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java index 2ea9327d1b..235ba8d98e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java @@ -38,6 +38,7 @@ * @author Jens Schauder * @author Oliver Gierke * @author Mark Paluch + * @author Maciej Walkowiak */ public class EntityRowMapper implements RowMapper { @@ -76,7 +77,7 @@ public T mapRow(ResultSet resultSet, int rowNumber) { idValue = readFrom(resultSet, idProperty, prefix); } - T result = createInstance(entity, resultSet, idValue); + T result = createInstance(entity, resultSet, idValue, prefix); return entity.requiresPropertyPopulation() // ? populateProperties(result, resultSet) // @@ -97,21 +98,21 @@ private T populateProperties(T result, ResultSet resultSet) { continue; } - propertyAccessor.setProperty(property, readOrLoadProperty(resultSet, id, property)); + propertyAccessor.setProperty(property, readOrLoadProperty(resultSet, id, property, "")); } return propertyAccessor.getBean(); } @Nullable - private Object readOrLoadProperty(ResultSet resultSet, @Nullable Object id, RelationalPersistentProperty property) { + private Object readOrLoadProperty(ResultSet resultSet, @Nullable Object id, RelationalPersistentProperty property, String prefix) { if (property.isCollectionLike() && id != null) { return accessStrategy.findAllByProperty(id, property); } else if (property.isMap() && id != null) { return ITERABLE_OF_ENTRY_TO_MAP_CONVERTER.convert(accessStrategy.findAllByProperty(id, property)); } else { - return readFrom(resultSet, property, ""); + return readFrom(resultSet, property, prefix); } } @@ -159,7 +160,7 @@ private S readEntityFrom(ResultSet rs, RelationalPersistentProperty property return null; } - S instance = createInstance(entity, rs, idValue); + S instance = createInstance(entity, rs, idValue, prefix); PersistentPropertyAccessor accessor = converter.getPropertyAccessor(entity, instance); @@ -180,7 +181,7 @@ private Object getObjectFromResultSet(ResultSet rs, String backreferenceName) { } } - private S createInstance(RelationalPersistentEntity entity, ResultSet rs, @Nullable Object idValue) { + private S createInstance(RelationalPersistentEntity entity, ResultSet rs, @Nullable Object idValue, String prefix) { return converter.createInstance(entity, parameter -> { @@ -190,7 +191,7 @@ private S createInstance(RelationalPersistentEntity entity, ResultSet rs, RelationalPersistentProperty property = entity.getRequiredPersistentProperty(parameterName); - return readOrLoadProperty(rs, idValue, property); + return readOrLoadProperty(rs, idValue, property, prefix); }); } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/EntityRowMapperUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/EntityRowMapperUnitTests.java index 4aee627a16..0a503afebb 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/EntityRowMapperUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/EntityRowMapperUnitTests.java @@ -58,6 +58,7 @@ * * @author Jens Schauder * @author Mark Paluch + * @author Maciej Walkowiak */ public class EntityRowMapperUnitTests { @@ -120,15 +121,30 @@ public void namingStrategyGetsHonoredForConstructor() throws SQLException { public void simpleOneToOneGetsProperlyExtracted() throws SQLException { ResultSet rs = mockResultSet(asList("id", "name", "child_id", "child_name"), // - ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta"); + ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta"); rs.next(); OneToOne extracted = createRowMapper(OneToOne.class).mapRow(rs, 1); assertThat(extracted) // - .isNotNull() // - .extracting(e -> e.id, e -> e.name, e -> e.child.id, e -> e.child.name) // - .containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta"); + .isNotNull() // + .extracting(e -> e.id, e -> e.name, e -> e.child.id, e -> e.child.name) // + .containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta"); + } + + @Test // DATAJDBC-286 + public void immutableOneToOneGetsProperlyExtracted() throws SQLException { + + ResultSet rs = mockResultSet(asList("id", "name", "child_id", "child_name"), // + ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta"); + rs.next(); + + OneToOneImmutable extracted = createRowMapper(OneToOneImmutable.class).mapRow(rs, 1); + + assertThat(extracted) // + .isNotNull() // + .extracting(e -> e.id, e -> e.name, e -> e.child.id, e -> e.child.name) // + .containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha", 24L, "beta"); } @Test // DATAJDBC-113 @@ -371,6 +387,15 @@ static class OneToOne { Trivial child; } + @RequiredArgsConstructor + @Wither + static class OneToOneImmutable { + + private final @Id Long id; + private final String name; + private final TrivialImmutable child; + } + static class OneToSet { @Id Long id;