DATAREST-1304 - EntityLookupConfiguration is now used in PUT for creation.
Previously the backend identifier derived from the URI was set as identifier on the object to be created in a PUT request. However, in case a custom entity lookup is used, this is not the identifier but an arbitrary property pointed to through user defined code, mostly a method reference. We now use the newly introduced MethodInvocationRecorder API in Spring Data Commons to be able to obtain the property that is supposed to be used and set that to the value calculated. This requires the entity type for which the custom lookup is configured to be non-final as the invocation recording is build on top of proxies. Related tickets: DATACMNS-1449.
This commit is contained in:
@@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -31,6 +32,7 @@ import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.rest.core.support.EntityLookup;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.data.rest.webmvc.RootResourceInformation;
|
||||
import org.springframework.data.rest.webmvc.json.DomainObjectReader;
|
||||
@@ -39,6 +41,7 @@ import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.plugin.core.PluginRegistry;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
@@ -75,7 +78,8 @@ public class PersistentEntityResourceHandlerMethodArgumentResolverUnitTests {
|
||||
public void returnsAggregateInstanceWithIdentifierPopulatedForPutRequests() throws Exception {
|
||||
|
||||
PersistentEntityResourceHandlerMethodArgumentResolver argumentResolver = new PersistentEntityResourceHandlerMethodArgumentResolver(
|
||||
Arrays.<HttpMessageConverter<?>> asList(converter), rootResourceResolver, backendIdResolver, reader);
|
||||
Arrays.<HttpMessageConverter<?>> asList(converter), rootResourceResolver, backendIdResolver, reader,
|
||||
PluginRegistry.empty());
|
||||
|
||||
HttpServletRequest request = new MockHttpServletRequest("PUT", "/foo/4711");
|
||||
|
||||
@@ -89,6 +93,32 @@ public class PersistentEntityResourceHandlerMethodArgumentResolverUnitTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAREST-1304
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setsLookupPropertyForEntitiesWithCustomLookup() throws Exception {
|
||||
|
||||
EntityLookup<?> lookup = mock(EntityLookup.class);
|
||||
doReturn(Optional.of("name")).when(lookup).getLookupProperty();
|
||||
doReturn(true).when(lookup).supports(Foo.class);
|
||||
|
||||
PersistentEntityResourceHandlerMethodArgumentResolver argumentResolver = new PersistentEntityResourceHandlerMethodArgumentResolver(
|
||||
Arrays.<HttpMessageConverter<?>> asList(converter), rootResourceResolver, backendIdResolver, reader,
|
||||
PluginRegistry.of(Arrays.asList(lookup)));
|
||||
|
||||
HttpServletRequest request = new MockHttpServletRequest("PUT", "/foo/someName");
|
||||
|
||||
doReturn(new Foo()).when(converter).read(Mockito.any(Class.class), Mockito.any(HttpInputMessage.class));
|
||||
mockInvocationOfResolver(backendIdResolver, "someName");
|
||||
|
||||
Object result = argumentResolver.resolveArgument(null, null, new ServletWebRequest(request), null);
|
||||
|
||||
assertThat(result).isInstanceOfSatisfying(PersistentEntityResource.class, it -> {
|
||||
assertThat(it.getContent()).isInstanceOfSatisfying(Foo.class, foo -> {
|
||||
assertThat(foo.name).isEqualTo("someName");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void setupRootResourceInfoFor(Class<?> type) throws Exception {
|
||||
|
||||
RootResourceInformation information = mock(RootResourceInformation.class);
|
||||
@@ -113,5 +143,6 @@ public class PersistentEntityResourceHandlerMethodArgumentResolverUnitTests {
|
||||
|
||||
static class Foo {
|
||||
@Id Long id;
|
||||
String name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.NestedEntitySerializer;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.support.ExcerptProjector;
|
||||
import org.springframework.hateoas.UriTemplate;
|
||||
import org.springframework.hateoas.server.EntityLinks;
|
||||
import org.springframework.hateoas.server.RepresentationModelProcessor;
|
||||
import org.springframework.hateoas.UriTemplate;
|
||||
import org.springframework.hateoas.server.mvc.RepresentationModelProcessorInvoker;
|
||||
import org.springframework.plugin.core.PluginRegistry;
|
||||
|
||||
@@ -92,7 +92,8 @@ public class PersistentEntityJackson2ModuleUnitTests {
|
||||
|
||||
this.persistentEntities = new PersistentEntities(Arrays.asList(mappingContext));
|
||||
|
||||
RepresentationModelProcessorInvoker invoker = new RepresentationModelProcessorInvoker(Collections.<RepresentationModelProcessor<?>> emptyList());
|
||||
RepresentationModelProcessorInvoker invoker = new RepresentationModelProcessorInvoker(
|
||||
Collections.<RepresentationModelProcessor<?>> emptyList());
|
||||
|
||||
NestedEntitySerializer nestedEntitySerializer = new NestedEntitySerializer(persistentEntities,
|
||||
new EmbeddedResourcesAssembler(persistentEntities, associations, mock(ExcerptProjector.class)), invoker);
|
||||
@@ -201,6 +202,11 @@ public class PersistentEntityJackson2ModuleUnitTests {
|
||||
public Optional<Home> lookupEntity(Object id) {
|
||||
return Optional.of(new Home());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getLookupProperty() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
||||
Reference in New Issue
Block a user