Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
Expand All @@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.6.0.RC1</version>
<version>1.6.0.BUILD-SNAPSHOT</version>
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
</parent>

Expand All @@ -27,7 +27,7 @@
<project.type>multi</project.type>
<dist.id>spring-data-rest</dist.id>

<springdata.commons>1.10.0.RC1</springdata.commons>
<springdata.commons>1.10.0.BUILD-SNAPSHOT</springdata.commons>
<springdata.jpa>1.8.0.RC1</springdata.jpa>
<springdata.mongodb>1.7.0.RC1</springdata.mongodb>
<springdata.neo4j>3.3.0.RC1</springdata.neo4j>
Expand Down Expand Up @@ -154,8 +154,8 @@

<repositories>
<repository>
<id>spring-libs-milestone</id>
<url>http://repo.spring.io/libs-milestone</url>
<id>spring-libs-snapshot</id>
<url>http://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ public class RepositoryRestConfiguration {
private String sortParamName = "sort";
private MediaType defaultMediaType = MediaTypes.HAL_JSON;
private boolean useHalAsDefaultJsonMediaType = true;
private boolean returnBodyOnCreate = false;
private boolean returnBodyOnUpdate = false;
private Boolean returnBodyOnCreate = Boolean.FALSE;
private Boolean returnBodyOnUpdate = Boolean.FALSE;
private List<Class<?>> exposeIdsFor = new ArrayList<Class<?>>();
private ResourceMappingConfiguration domainMappings = new ResourceMappingConfiguration();
private ResourceMappingConfiguration repoMappings = new ResourceMappingConfiguration();
Expand Down Expand Up @@ -296,39 +296,43 @@ public RepositoryRestConfiguration useHalAsDefaultJsonMediaType(boolean useHalAs
/**
* Whether to return a response body after creating an entity.
*
* @return {@literal true} to return a body on create, {@literal false} otherwise.
* @return {@link java.lang.Boolean#TRUE} to return a body on create, {@link java.lang.Boolean#FALSE} otherwise.
* If {@literal null}, defer to HTTP Accept header
*/
public boolean isReturnBodyOnCreate() {
public Boolean isReturnBodyOnCreate() {
return returnBodyOnCreate;
}

/**
* Set whether to return a response body after creating an entity.
*
* @param returnBodyOnCreate {@literal true} to return a body on create, {@literal false} otherwise.
* @param returnBodyOnCreate {@link java.lang.Boolean#TRUE} to return a body on create, {@link java.lang.Boolean#FALSE} otherwise.
* If {@literal null}, defer to HTTP Accept header
* @return {@literal this}
*/
public RepositoryRestConfiguration setReturnBodyOnCreate(boolean returnBodyOnCreate) {
public RepositoryRestConfiguration setReturnBodyOnCreate(Boolean returnBodyOnCreate) {
this.returnBodyOnCreate = returnBodyOnCreate;
return this;
}

/**
* Whether to return a response body after updating an entity.
*
* @return {@literal true} to return a body on update, {@literal false} otherwise.
* @return {@link java.lang.Boolean#TRUE} to return a body on update, {@link java.lang.Boolean#FALSE} otherwise.
* If {@literal null}, defer to HTTP Accept header
*/
public boolean isReturnBodyOnUpdate() {
public Boolean isReturnBodyOnUpdate() {
return returnBodyOnUpdate;
}

/**
* Sets whether to return a response body after updating an entity.
*
* @param returnBodyOnUpdate
* @return
* Set whether to return a response body after updating an entity.
*
* @param returnBodyOnUpdate {@link java.lang.Boolean#TRUE} to return a body on update, {@link java.lang.Boolean#FALSE} otherwise.
* If {@literal null}, defer to HTTP Accept header
* @return {@literal this}
*/
public RepositoryRestConfiguration setReturnBodyOnUpdate(boolean returnBodyOnUpdate) {
public RepositoryRestConfiguration setReturnBodyOnUpdate(Boolean returnBodyOnUpdate) {
this.returnBodyOnUpdate = returnBodyOnUpdate;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
Expand All @@ -81,6 +82,8 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
RestMediaTypes.JSON_PATCH_JSON.toString(), //
MediaType.APPLICATION_JSON_VALUE);

private static final String ACCEPT_HEADER = "Accept";

private final RepositoryEntityLinks entityLinks;
private final RepositoryRestConfiguration config;
private final ConversionService conversionService;
Expand Down Expand Up @@ -227,18 +230,23 @@ public Resources<?> getCollectionResourceCompact(RootResourceInformation repoReq
*
* @param resourceInformation
* @param payload
* @param assembler
* @param acceptHeader
* @return
* @throws HttpRequestMethodNotSupportedException
*/
@ResponseBody
@RequestMapping(value = BASE_MAPPING, method = RequestMethod.POST)
public ResponseEntity<ResourceSupport> postCollectionResource(RootResourceInformation resourceInformation,
PersistentEntityResource payload, PersistentEntityResourceAssembler assembler)
PersistentEntityResource payload, PersistentEntityResourceAssembler assembler,
@RequestHeader(value= ACCEPT_HEADER, required = false) String acceptHeader)
throws HttpRequestMethodNotSupportedException {

resourceInformation.verifySupportedMethod(HttpMethod.POST, ResourceType.COLLECTION);

return createAndReturn(payload.getContent(), resourceInformation.getInvoker(), assembler);
boolean acceptHeaderPresent = acceptHeader != null;

return createAndReturn(payload.getContent(), resourceInformation.getInvoker(), assembler, acceptHeaderPresent);
}

/**
Expand Down Expand Up @@ -312,17 +320,21 @@ public ResponseEntity<Resource<?>> getItemResource(RootResourceInformation resou
/**
* <code>PUT /{repository}/{id}</code> - Updates an existing entity or creates one at exactly that place.
*
* @param eTagMatch

* @param resourceInformation
* @param payload
* @param id
* @param assembler
* @param eTag
* @param acceptHeader
* @return
* @throws HttpRequestMethodNotSupportedException
*/
@RequestMapping(value = BASE_MAPPING + "/{id}", method = RequestMethod.PUT)
public ResponseEntity<? extends ResourceSupport> putItemResource(RootResourceInformation resourceInformation,
PersistentEntityResource payload, @BackendId Serializable id, PersistentEntityResourceAssembler assembler,
ETag eTag) throws HttpRequestMethodNotSupportedException {
ETag eTag, @RequestHeader(value=ACCEPT_HEADER, required = false) String acceptHeader)
throws HttpRequestMethodNotSupportedException {

resourceInformation.verifySupportedMethod(HttpMethod.PUT, ResourceType.ITEM);

Expand All @@ -338,8 +350,10 @@ public ResponseEntity<? extends ResourceSupport> putItemResource(RootResourceInf

eTag.verify(resourceInformation.getPersistentEntity(), domainObject);

return domainObject == null ? createAndReturn(objectToSave, invoker, assembler) : saveAndReturn(objectToSave,
invoker, PUT, assembler);
boolean acceptHeaderPresent = acceptHeader != null;

return domainObject == null ? createAndReturn(objectToSave, invoker, assembler, acceptHeaderPresent)
: saveAndReturn(objectToSave, invoker, PUT, assembler, acceptHeaderPresent);
}

/**
Expand All @@ -349,7 +363,8 @@ public ResponseEntity<? extends ResourceSupport> putItemResource(RootResourceInf
* @param payload
* @param id
* @param assembler
* @param eTag
* @param eTag,
* @param acceptHeader
* @return
* @throws HttpRequestMethodNotSupportedException
* @throws ResourceNotFoundException
Expand All @@ -358,7 +373,8 @@ public ResponseEntity<? extends ResourceSupport> putItemResource(RootResourceInf
@RequestMapping(value = BASE_MAPPING + "/{id}", method = RequestMethod.PATCH)
public ResponseEntity<ResourceSupport> patchItemResource(RootResourceInformation resourceInformation,
PersistentEntityResource payload, @BackendId Serializable id, PersistentEntityResourceAssembler assembler,
ETag eTag) throws HttpRequestMethodNotSupportedException, ResourceNotFoundException {
ETag eTag,@RequestHeader(value=ACCEPT_HEADER, required = false) String acceptHeader )
throws HttpRequestMethodNotSupportedException, ResourceNotFoundException {

resourceInformation.verifySupportedMethod(HttpMethod.PATCH, ResourceType.ITEM);

Expand All @@ -370,7 +386,9 @@ public ResponseEntity<ResourceSupport> patchItemResource(RootResourceInformation

eTag.verify(resourceInformation.getPersistentEntity(), domainObject);

return saveAndReturn(payload.getContent(), resourceInformation.getInvoker(), PATCH, assembler);
boolean acceptHeaderPresent = acceptHeader != null;

return saveAndReturn(payload.getContent(), resourceInformation.getInvoker(), PATCH, assembler, acceptHeaderPresent);
}

/**
Expand Down Expand Up @@ -415,7 +433,7 @@ public ResponseEntity<?> deleteItemResource(RootResourceInformation resourceInfo
* @return
*/
private ResponseEntity<ResourceSupport> saveAndReturn(Object domainObject, RepositoryInvoker invoker,
HttpMethod httpMethod, PersistentEntityResourceAssembler assembler) {
HttpMethod httpMethod, PersistentEntityResourceAssembler assembler, boolean acceptHeaderPresent) {

publisher.publishEvent(new BeforeSaveEvent(domainObject));
Object obj = invoker.invokeSave(domainObject);
Expand All @@ -428,7 +446,10 @@ private ResponseEntity<ResourceSupport> saveAndReturn(Object domainObject, Repos
addLocationHeader(headers, assembler, obj);
}

if (config.isReturnBodyOnUpdate()) {
boolean returnBodyOnUpdate = (config.isReturnBodyOnUpdate() == null && acceptHeaderPresent)
|| Boolean.TRUE.equals(config.isReturnBodyOnUpdate());

if (returnBodyOnUpdate) {
return ControllerUtils.toResponseEntity(HttpStatus.OK, headers, resource);
} else {
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT, headers);
Expand All @@ -443,13 +464,17 @@ private ResponseEntity<ResourceSupport> saveAndReturn(Object domainObject, Repos
* @return
*/
private ResponseEntity<ResourceSupport> createAndReturn(Object domainObject, RepositoryInvoker invoker,
PersistentEntityResourceAssembler assembler) {
PersistentEntityResourceAssembler assembler, boolean acceptHeaderPresent) {

publisher.publishEvent(new BeforeCreateEvent(domainObject));
Object savedObject = invoker.invokeSave(domainObject);
publisher.publishEvent(new AfterCreateEvent(savedObject));

PersistentEntityResource resource = config.isReturnBodyOnCreate() ? assembler.toFullResource(savedObject) : null;

boolean returnBodyOnCreate = (config.isReturnBodyOnCreate() == null && acceptHeaderPresent)
|| Boolean.TRUE.equals(config.isReturnBodyOnCreate());

PersistentEntityResource resource = returnBodyOnCreate ? assembler.toFullResource(savedObject) : null;

HttpHeaders headers = prepareHeaders(resource);
addLocationHeader(headers, assembler, savedObject);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import java.util.List;

import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mapping.context.PersistentEntities;
Expand All @@ -33,6 +34,7 @@
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.ResourceSupport;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
Expand All @@ -46,6 +48,7 @@
*
* @author Oliver Gierke
*/
@SuppressWarnings("ALL")
@ContextConfiguration(classes = JpaRepositoryConfig.class)
@Transactional
public class RepositoryEntityControllerIntegrationTests extends AbstractControllerIntegrationTests {
Expand Down Expand Up @@ -76,7 +79,7 @@ public void rejectsEntityCreationIfSaveIsNotExported() throws Exception {

RootResourceInformation request = getResourceInformation(Address.class);

controller.postCollectionResource(request, null, null);
controller.postCollectionResource(request, null, null, MediaType.APPLICATION_JSON_VALUE);
}

/**
Expand All @@ -91,7 +94,7 @@ public void setsExpandedSelfUriInLocationHeader() throws Exception {
entities.getPersistentEntity(Order.class)).build();

ResponseEntity<?> entity = controller.putItemResource(information, persistentEntityResource, 1L, assembler,
ETag.NO_ETAG);
ETag.NO_ETAG, MediaType.APPLICATION_JSON_VALUE);

assertThat(entity.getHeaders().getLocation().toString(), not(endsWith("{?projection}")));
}
Expand Down Expand Up @@ -181,4 +184,99 @@ public void optionsForItermResourceSetsAllowPatchHeader() {
RestMediaTypes.MERGE_PATCH_JSON.toString(), //
MediaType.APPLICATION_JSON_VALUE));
}

/**
* @see DATAREST-34
*/
@Test
public void verifyAcceptHeaderCanControlBodyReturnOnPutItemResource() throws HttpRequestMethodNotSupportedException {
RootResourceInformation request = getResourceInformation(Order.class);

PersistentEntityResource persistentEntityResource = PersistentEntityResource.build(new Order(new Person()),
entities.getPersistentEntity(Order.class)).build();

configuration.setReturnBodyOnCreate(Boolean.FALSE);
configuration.setReturnBodyOnUpdate(Boolean.FALSE);

ResponseEntity<?> response = controller.putItemResource(request, persistentEntityResource, 1L, assembler,
ETag.NO_ETAG, MediaType.APPLICATION_JSON_VALUE);

assert(!response.hasBody());


configuration.setReturnBodyOnCreate(Boolean.TRUE);
configuration.setReturnBodyOnUpdate(Boolean.TRUE);

response = controller.putItemResource(request, persistentEntityResource, 1L, assembler,
ETag.NO_ETAG, MediaType.APPLICATION_JSON_VALUE);

configuration.setReturnBodyOnCreate(Boolean.FALSE);
configuration.setReturnBodyOnUpdate(Boolean.FALSE);

response = controller.putItemResource(request, persistentEntityResource, 1L, assembler,
ETag.NO_ETAG, null);

assert(!response.hasBody());

configuration.setReturnBodyOnCreate(null);
configuration.setReturnBodyOnUpdate(null);

response = controller.putItemResource(request, persistentEntityResource, 1L, assembler,
ETag.NO_ETAG, null);

assert(!response.hasBody());

configuration.setReturnBodyOnCreate(null);
configuration.setReturnBodyOnUpdate(null);

response = controller.putItemResource(request, persistentEntityResource, 1L, assembler,
ETag.NO_ETAG, MediaType.APPLICATION_JSON_VALUE);

assert(response.hasBody());
}

/**
* @see DATAREST-34
*/
@Test
public void verifyAcceptHeaderCanControlBodyReturnPostCollectionResource() throws HttpRequestMethodNotSupportedException {
RootResourceInformation request = getResourceInformation(Order.class);

PersistentEntityResource persistentEntityResource = PersistentEntityResource.build(new Order(new Person()),
entities.getPersistentEntity(Order.class)).build();

configuration.setReturnBodyOnCreate(null);

ResponseEntity<ResourceSupport> response =
controller.postCollectionResource(request, persistentEntityResource, assembler, MediaType.APPLICATION_JSON_VALUE);


assert(response.hasBody());


response =
controller.postCollectionResource(request, persistentEntityResource, assembler, null);


assert(!response.hasBody());


configuration.setReturnBodyOnCreate(Boolean.FALSE);
response =
controller.postCollectionResource(request, persistentEntityResource, assembler, MediaType.APPLICATION_JSON_VALUE);

assert(!response.hasBody());

configuration.setReturnBodyOnCreate(Boolean.TRUE);
response =
controller.postCollectionResource(request, persistentEntityResource, assembler, null);

assert(response.hasBody());
}

@After
public void cleanUp() {
configuration.setReturnBodyOnCreate(Boolean.FALSE);
configuration.setReturnBodyOnUpdate(Boolean.FALSE);
}
}
Loading