From 1417287b2b2cb3c3fb3d44375fa9adca0274b964 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 18 Jun 2015 19:05:55 +0200 Subject: [PATCH] DATAREST-581 - Fixed ETag calculation for projected item resources. Instead of using the PersistentEntityResource to obtain the ETag we now calculate headers based on the domain object and PersistentEntity upfront. This prevents the failure of trying to read the ETag from a potentially projected proxy. --- .../webmvc/RepositoryEntityController.java | 9 +++--- ...itoryEntityControllerIntegrationTests.java | 29 +++++++++++++++++++ .../data/rest/webmvc/jpa/Address.java | 2 ++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java index f526e23b8..120207b88 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java @@ -321,12 +321,13 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem List ifNoneMatch = headers.getIfNoneMatch(); ETag eTag = ifNoneMatch.isEmpty() ? ETag.NO_ETAG : ETag.from(ifNoneMatch.get(0)); PersistentEntity entity = resourceInformation.getPersistentEntity(); + HttpHeaders responseHeaders = prepareHeaders(entity, domainObj); if (eTag.matches(entity, domainObj)) { - return new ResponseEntity>(prepareHeaders(entity, domainObj), HttpStatus.NOT_MODIFIED); + return new ResponseEntity>(responseHeaders, HttpStatus.NOT_MODIFIED); } - // Check last modification for If-Modfied-Since + // Check last modification for If-Modified-Since if (headers.getIfModifiedSince() != -1) { @@ -334,12 +335,12 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem long current = wrapper.getLastModifiedDate().getTimeInMillis() / 1000 * 1000; if (current <= headers.getIfModifiedSince()) { - return new ResponseEntity>(prepareHeaders(entity, domainObj), HttpStatus.NOT_MODIFIED); + return new ResponseEntity>(responseHeaders, HttpStatus.NOT_MODIFIED); } } PersistentEntityResource resource = assembler.toFullResource(domainObj); - return new ResponseEntity>(resource, prepareHeaders(resource), HttpStatus.OK); + return new ResponseEntity>(resource, responseHeaders, HttpStatus.OK); } /** diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryEntityControllerIntegrationTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryEntityControllerIntegrationTests.java index 83d351ee5..48a3b2c3d 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryEntityControllerIntegrationTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryEntityControllerIntegrationTests.java @@ -23,8 +23,10 @@ import static org.springframework.http.HttpMethod.*; import java.util.List; import org.junit.Test; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mapping.context.PersistentEntities; +import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.webmvc.jpa.Address; import org.springframework.data.rest.webmvc.jpa.AddressRepository; @@ -33,12 +35,14 @@ import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig; import org.springframework.data.rest.webmvc.jpa.Order; import org.springframework.data.rest.webmvc.jpa.Person; import org.springframework.data.rest.webmvc.support.ETag; +import org.springframework.hateoas.Resource; import org.springframework.http.HttpEntity; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.test.context.ContextConfiguration; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.LinkedMultiValueMap; import org.springframework.web.HttpRequestMethodNotSupportedException; /** @@ -244,4 +248,29 @@ public class RepositoryEntityControllerIntegrationTests extends AbstractControll is(false)); assertThat(controller.postCollectionResource(request, persistentEntityResource, assembler, "").hasBody(), is(false)); } + + /** + * @see DATAREST-581 + */ + @Test + public void createsEtagForProjectedEntityCorrectly() throws Exception { + + Address address = repository.save(new Address()); + + PersistentEntityResourceAssembler assembler = Mockito.mock(PersistentEntityResourceAssembler.class); + AddressProjection addressProjection = new SpelAwareProxyProjectionFactory() + .createProjection(AddressProjection.class); + + PersistentEntityResource resource = PersistentEntityResource + .build(addressProjection, entities.getPersistentEntity(Address.class)).build(); + + Mockito.when(assembler.toFullResource(Mockito.any(Object.class))).thenReturn(resource); + + ResponseEntity> entity = controller.getItemResource(getResourceInformation(Address.class), address.id, + assembler, new LinkedMultiValueMap()); + + assertThat(entity.getHeaders().getETag(), is(notNullValue())); + } + + interface AddressProjection {} } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Address.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Address.java index b4ac3fb21..1ae854732 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Address.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Address.java @@ -18,6 +18,7 @@ package org.springframework.data.rest.webmvc.jpa; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.Version; /** * @author Oliver Gierke @@ -26,4 +27,5 @@ import javax.persistence.Id; public class Address { public @Id @GeneratedValue Long id; + public @Version Long version; }