DATACMNS-1296 - PersistentPropertyPathAccessor now properly handles intermediate nulls when setting values.

We now use a dedicated GetOptions instance for the lookup of the parent path in case SetOptions is defined to skip nulls so that the lookup does not fail if the parent path contains a null value.
This commit is contained in:
Oliver Drotbohm
2020-08-06 08:50:20 +02:00
parent 856f1d3194
commit b187ea62d0
2 changed files with 28 additions and 2 deletions

View File

@@ -29,6 +29,7 @@ import java.util.stream.Collectors;
import org.springframework.core.CollectionFactory;
import org.springframework.data.mapping.AccessOptions;
import org.springframework.data.mapping.AccessOptions.GetOptions;
import org.springframework.data.mapping.AccessOptions.GetOptions.GetNulls;
import org.springframework.data.mapping.AccessOptions.SetOptions;
import org.springframework.data.mapping.AccessOptions.SetOptions.SetNulls;
import org.springframework.data.mapping.MappingException;
@@ -53,6 +54,8 @@ import org.springframework.util.Assert;
@RequiredArgsConstructor
class SimplePersistentPropertyPathAccessor<T> implements PersistentPropertyPathAccessor<T> {
private static final GetOptions DEFAULT_GET_OPTIONS = AccessOptions.defaultGetOptions();
private final @NonNull PersistentPropertyAccessor<T> delegate;
/*
@@ -81,7 +84,7 @@ class SimplePersistentPropertyPathAccessor<T> implements PersistentPropertyPathA
@Nullable
@Override
public Object getProperty(PersistentPropertyPath<? extends PersistentProperty<?>> path) {
return getProperty(path, AccessOptions.defaultGetOptions());
return getProperty(path, DEFAULT_GET_OPTIONS);
}
/*
@@ -151,7 +154,11 @@ class SimplePersistentPropertyPathAccessor<T> implements PersistentPropertyPathA
return;
}
Object parent = parentPath.isEmpty() ? getBean() : getProperty(parentPath);
GetOptions lookupOptions = options.getNullHandling() != REJECT
? DEFAULT_GET_OPTIONS.withNullValues(GetNulls.EARLY_RETURN)
: DEFAULT_GET_OPTIONS;
Object parent = parentPath.isEmpty() ? getBean() : getProperty(parentPath, lookupOptions);
if (parent == null) {
handleNull(path, options.getNullHandling());

View File

@@ -86,6 +86,20 @@ class SimplePersistentPropertyPathAccessorUnitTests {
}).doesNotThrowAnyException();
}
@Test // DATACMNS-1296
void skipsIntermediateNullsWhenSettingNestedValues() {
CustomerWrapperWrapper wrapper = new CustomerWrapperWrapper(null);
PersistentPropertyPathAccessor<CustomerWrapperWrapper> accessor = getAccessor(wrapper);
PersistentPropertyPath<SamplePersistentProperty> path = context
.getPersistentPropertyPath("wrapper.customer.firstname", CustomerWrapperWrapper.class);
assertThatCode(() -> {
accessor.setProperty(path, "Dave", AccessOptions.defaultSetOptions().skipNulls());
}).doesNotThrowAnyException();
}
private void assertFirstnamesSetFor(Customers customers, String path) {
PersistentPropertyPath<SamplePersistentProperty> propertyPath = context.getPersistentPropertyPath(path,
@@ -124,4 +138,9 @@ class SimplePersistentPropertyPathAccessorUnitTests {
static class CustomerWrapper {
Customer customer;
}
@AllArgsConstructor
static class CustomerWrapperWrapper {
CustomerWrapper wrapper;
}
}