Support validation for fields that are not a PersistentEntity.

For entity types that use transient fields, the validation integration needs to treat those as normal bean types an must not reject the values right away.

Fixes GH-2252.
This commit is contained in:
Florian Cramer
2023-04-13 12:48:56 +02:00
committed by Oliver Drotbohm
parent 2c313275d7
commit 487c2ac75f
2 changed files with 35 additions and 3 deletions

View File

@@ -18,6 +18,7 @@ package org.springframework.data.rest.core;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Optional;
import org.springframework.beans.BeansException;
import org.springframework.beans.ConfigurablePropertyAccessor;
@@ -39,6 +40,7 @@ import org.springframework.validation.Errors;
*
* @author Jon Brisbin
* @author Oliver Gierke
* @author Florian Cramer
*/
public class ValidationErrors extends AbstractPropertyBindingResult {
@@ -92,7 +94,12 @@ public class ValidationErrors extends AbstractPropertyBindingResult {
*/
private Object lookupValueOn(Object value, String segment) {
PersistentProperty<?> property = entities.getPersistentEntity(value.getClass()) //
Optional<PersistentEntity<?, ? extends PersistentProperty<?>>> entity = entities.getPersistentEntity(value.getClass());
if (!entity.isPresent()) {
return new DirectFieldAccessor(value).getPropertyValue(segment);
}
PersistentProperty<?> property = entity //
.map(it -> it.getPersistentProperty(PropertyAccessorUtils.getPropertyName(segment))) //
.orElseThrow(() -> new NotReadablePropertyException(value.getClass(), segment));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 original author or authors.
* Copyright 2016-2023 original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,14 +24,18 @@ import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.NotReadablePropertyException;
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentProperty;
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.util.TypeInformation;
import org.springframework.validation.Errors;
/**
* Unit tests for {@link ValidationErrors}.
*
* @author Oliver Gierke
* @author Florian Cramer
*/
class ValidationErrorsUnitTests {
@@ -40,7 +44,7 @@ class ValidationErrorsUnitTests {
@BeforeEach
void setUp() {
KeyValueMappingContext<?, ?> context = new KeyValueMappingContext<>();
KeyValueMappingContext<?, ?> context = new TestKeyValueMappingContext<>();
context.getPersistentEntity(Foo.class);
this.entities = new PersistentEntities(Arrays.asList(context));
@@ -71,6 +75,14 @@ class ValidationErrorsUnitTests {
assertThat(errors.getFieldValue("bar")).isNull();
}
@Test // GH-2252
void getsTheNestedFieldsValueForNonPersistentEntity() {
ValidationErrors errors = new ValidationErrors(new Foo(), entities);
assertThat(errors.getFieldValue("qux.field")).isEqualTo("World");
}
private static void expectedErrorBehavior(Errors errors) {
assertThat(errors.getFieldValue("bars")).isNotNull();
@@ -88,9 +100,22 @@ class ValidationErrorsUnitTests {
static class Foo {
List<Bar> bars = Collections.singletonList(new Bar());
Bar bar = null;
Qux qux = new Qux();
}
static class Bar {
String field = "Hello";
}
static class Qux {
String field = "World";
}
static class TestKeyValueMappingContext<E extends KeyValuePersistentEntity<?, P>, P extends KeyValuePersistentProperty<P>> extends KeyValueMappingContext<E, P> {
@Override
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
return Qux.class != type.getType() && super.shouldCreatePersistentEntityFor(type);
}
}
}