DATAREST-506 - NotModified responses now return headers, too.

Responses for item resources that result in 304 Not Modifier now also return the headers they'd return if a 200 Ok would've been returned.
This commit is contained in:
Oliver Gierke
2015-04-12 18:18:54 +02:00
parent 72647464c6
commit bb933237b0
4 changed files with 37 additions and 25 deletions

View File

@@ -24,6 +24,7 @@ import java.util.List;
import org.springframework.data.auditing.AuditableBeanWrapper;
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.rest.core.mapping.ResourceMetadata;
import org.springframework.data.rest.webmvc.support.ETag;
import org.springframework.data.web.PagedResourcesAssembler;
@@ -132,18 +133,24 @@ class AbstractRepositoryRestController {
* @return
*/
protected HttpHeaders prepareHeaders(PersistentEntityResource resource) {
return resource == null ? new HttpHeaders() : prepareHeaders(resource.getPersistentEntity(), resource.getContent());
}
HttpHeaders headers = new HttpHeaders();
if (resource == null) {
return headers;
}
/**
* Retruns the default headers to be returned for the given {@link PersistentEntity} and value. Will set {@link ETag}
* and {@code Last-Modified} headers if applicable.
*
* @param entity must not be {@literal null}.
* @param value must not be {@literal null}.
* @return
*/
protected HttpHeaders prepareHeaders(PersistentEntity<?, ?> entity, Object value) {
// Add ETag
headers = ETag.from(resource).addTo(headers);
HttpHeaders headers = ETag.from(entity, value).addTo(new HttpHeaders());
// Add Last-Modified
AuditableBeanWrapper wrapper = getAuditableBeanWrapper(resource.getContent());
AuditableBeanWrapper wrapper = getAuditableBeanWrapper(value);
if (wrapper == null) {
return headers;

View File

@@ -31,6 +31,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.data.auditing.AuditableBeanWrapper;
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.repository.support.Repositories;
@@ -319,9 +320,10 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
List<String> ifNoneMatch = headers.getIfNoneMatch();
ETag eTag = ifNoneMatch.isEmpty() ? ETag.NO_ETAG : ETag.from(ifNoneMatch.get(0));
PersistentEntity<?, ?> entity = resourceInformation.getPersistentEntity();
if (eTag.matches(resourceInformation.getPersistentEntity(), domainObj)) {
return new ResponseEntity<Resource<?>>(HttpStatus.NOT_MODIFIED);
if (eTag.matches(entity, domainObj)) {
return new ResponseEntity<Resource<?>>(prepareHeaders(entity, domainObj), HttpStatus.NOT_MODIFIED);
}
// Check last modification for If-Modfied-Since
@@ -332,7 +334,7 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
long current = wrapper.getLastModifiedDate().getTimeInMillis() / 1000 * 1000;
if (current <= headers.getIfModifiedSince()) {
return new ResponseEntity<Resource<?>>(HttpStatus.NOT_MODIFIED);
return new ResponseEntity<Resource<?>>(prepareHeaders(entity, domainObj), HttpStatus.NOT_MODIFIED);
}
}

View File

@@ -65,6 +65,17 @@ public final class ETag {
return resource == null ? NO_ETAG : from(resource.getPersistentEntity(), resource.getContent());
}
/**
* Creates a new {@link ETag} from the given {@link PersistentEntity} and target bean.
*
* @param entity must not be {@literal null}.
* @param bean must not be {@literal null}.
* @return
*/
public static ETag from(PersistentEntity<?, ?> entity, Object bean) {
return from(getVersionInformation(entity, bean));
}
/**
* Verifies the ETag to be created for the given target bean with the current one and raises a
* {@link ETagDoesntMatchException} in case they don't match.
@@ -160,17 +171,6 @@ public final class ETag {
return value.hashCode();
}
/**
* Creates a new {@link ETag} from the given {@link PersistentEntity} and target bean.
*
* @param entity
* @param bean
* @return
*/
private static ETag from(PersistentEntity<?, ?> entity, Object bean) {
return from(getVersionInformation(entity, bean));
}
/**
* Returns the quoted version property of a domain object, returns null if it doesn't contains the property
*

View File

@@ -17,6 +17,7 @@ package org.springframework.data.rest.webmvc.mongodb;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.http.HttpHeaders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@@ -292,10 +293,12 @@ public class MongoWebTests extends CommonWebTests {
Link receiptLink = client.getDiscoverer(response).findLinkWithRel("self", response.getContentAsString());
mvc.perform(get(receiptLink.getHref()).header("If-Modified-Since", response.getHeader("Last-Modified"))).//
andExpect(status().isNotModified());
mvc.perform(get(receiptLink.getHref()).header(IF_MODIFIED_SINCE, response.getHeader(LAST_MODIFIED))).//
andExpect(status().isNotModified()).//
andExpect(header().string(ETAG, is(notNullValue())));
mvc.perform(get(receiptLink.getHref()).header("If-None-Match", response.getHeader("ETag"))).//
andExpect(status().isNotModified());
mvc.perform(get(receiptLink.getHref()).header(IF_NONE_MATCH, response.getHeader(ETAG))).//
andExpect(status().isNotModified()).//
andExpect(header().string(ETAG, is(notNullValue())));
}
}