Skip to content

Commit 5f7f912

Browse files
committed
DATAREST-647 - Removed unnecessary lookup of the entity to update.
RepositoryEntityController.patchItemResource(…) triggered an additional, unnecessary lookup of the original entity to be updated. However the resolution algorithm for PersistentEntityResource already checks the presence and rejects an invalid identifier with a ResourceNotFoundException. PersistentEntityResource now carries a boolean flag to expose whether the entity is about to be created. That allows us to avoid the additional lookup in the method handling PUT requests, too. Related tickets: DATAREST-441.
1 parent d4dbeb9 commit 5f7f912

File tree

3 files changed

+36
-17
lines changed

3 files changed

+36
-17
lines changed

spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResource.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public class PersistentEntityResource extends Resource<Object> {
4040

4141
private final PersistentEntity<?, ?> entity;
4242
private final Iterable<EmbeddedWrapper> embeddeds;
43+
private final boolean isNew;
4344

4445
/**
4546
* Creates a new {@link PersistentEntityResource} for the given {@link PersistentEntity}, content, embedded
@@ -51,14 +52,15 @@ public class PersistentEntityResource extends Resource<Object> {
5152
* @param embeddeds can be {@literal null}.
5253
*/
5354
private PersistentEntityResource(PersistentEntity<?, ?> entity, Object content, Iterable<Link> links,
54-
Iterable<EmbeddedWrapper> embeddeds) {
55+
Iterable<EmbeddedWrapper> embeddeds, boolean isNew) {
5556

5657
super(content, links);
5758

5859
Assert.notNull(entity, "PersistentEntity must not be null!");
5960

6061
this.entity = entity;
6162
this.embeddeds = embeddeds == null ? NO_EMBEDDEDS : embeddeds;
63+
this.isNew = isNew;
6264
}
6365

6466
/**
@@ -88,6 +90,16 @@ public Iterable<EmbeddedWrapper> getEmbeddeds() {
8890
return embeddeds;
8991
}
9092

93+
/**
94+
* Returns whether the content of the resource is a new entity about to be created. Used to distinguish between
95+
* creation and updates for incoming requests.
96+
*
97+
* @return
98+
*/
99+
public boolean isNew() {
100+
return isNew;
101+
}
102+
91103
/**
92104
* Creates a new {@link Builder} to create {@link PersistentEntityResource}s eventually.
93105
*
@@ -159,7 +171,17 @@ public Builder withLink(Link link) {
159171
* @return
160172
*/
161173
public PersistentEntityResource build() {
162-
return new PersistentEntityResource(entity, content, links, embeddeds);
174+
return new PersistentEntityResource(entity, content, links, embeddeds, false);
175+
}
176+
177+
/**
178+
* Finally creates the {@link PersistentEntityResource} instance to symbolize the contained entity is about to be
179+
* created.
180+
*
181+
* @return
182+
*/
183+
public PersistentEntityResource forCreation() {
184+
return new PersistentEntityResource(entity, content, links, embeddeds, true);
163185
}
164186
}
165187
}

spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -371,13 +371,12 @@ public ResponseEntity<? extends ResourceSupport> putItemResource(RootResourceInf
371371
RepositoryInvoker invoker = resourceInformation.getInvoker();
372372
Object objectToSave = incomingWrapper.getBean();
373373

374-
Object domainObject = invoker.invokeFindOne(id);
374+
Object domainObject = payload.getContent();
375375

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

378-
return domainObject == null ? createAndReturn(objectToSave, invoker, assembler,
379-
config.returnBodyOnCreate(acceptHeader)) : saveAndReturn(objectToSave, invoker, PUT, assembler,
380-
config.returnBodyOnUpdate(acceptHeader));
378+
return payload.isNew() ? createAndReturn(objectToSave, invoker, assembler, config.returnBodyOnCreate(acceptHeader))
379+
: saveAndReturn(objectToSave, invoker, PUT, assembler, config.returnBodyOnUpdate(acceptHeader));
381380
}
382381

383382
/**
@@ -402,15 +401,11 @@ public ResponseEntity<ResourceSupport> patchItemResource(RootResourceInformation
402401

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

405-
Object domainObject = resourceInformation.getInvoker().invokeFindOne(id);
406-
407-
if (domainObject == null) {
408-
throw new ResourceNotFoundException();
409-
}
404+
Object domainObject = payload.getContent();
410405

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

413-
return saveAndReturn(payload.getContent(), resourceInformation.getInvoker(), PATCH, assembler,
408+
return saveAndReturn(domainObject, resourceInformation.getInvoker(), PATCH, assembler,
414409
config.returnBodyOnUpdate(acceptHeader));
415410
}
416411

spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/PersistentEntityResourceHandlerMethodArgumentResolver.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.data.repository.support.RepositoryInvoker;
2626
import org.springframework.data.rest.webmvc.IncomingRequest;
2727
import org.springframework.data.rest.webmvc.PersistentEntityResource;
28+
import org.springframework.data.rest.webmvc.PersistentEntityResource.Builder;
2829
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
2930
import org.springframework.data.rest.webmvc.RootResourceInformation;
3031
import org.springframework.data.rest.webmvc.json.DomainObjectReader;
@@ -122,13 +123,16 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m
122123
}
123124

124125
Serializable id = idResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
125-
Object obj = read(resourceInformation, incoming, converter, id);
126+
Object objectToUpdate = getObjectToUpdate(id, resourceInformation);
127+
boolean forUpdate = objectToUpdate != null;
128+
Object obj = read(resourceInformation, incoming, converter, objectToUpdate);
126129

127130
if (obj == null) {
128131
throw new HttpMessageNotReadableException(String.format(ERROR_MESSAGE, domainType));
129132
}
130133

131-
return PersistentEntityResource.build(obj, resourceInformation.getPersistentEntity()).build();
134+
Builder build = PersistentEntityResource.build(obj, resourceInformation.getPersistentEntity());
135+
return forUpdate ? build.build() : build.forCreation();
132136
}
133137

134138
throw new HttpMessageNotReadableException(String.format(NO_CONVERTER_FOUND, domainType, contentType));
@@ -145,9 +149,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m
145149
* @return
146150
*/
147151
private Object read(RootResourceInformation information, IncomingRequest request,
148-
HttpMessageConverter<Object> converter, Serializable id) {
149-
150-
Object objectToUpdate = getObjectToUpdate(id, information);
152+
HttpMessageConverter<Object> converter, Object objectToUpdate) {
151153

152154
// JSON + PATCH request
153155
if (request.isPatchRequest() && converter instanceof MappingJackson2HttpMessageConverter) {

0 commit comments

Comments
 (0)