Tweaks to source code by taking out unnecessary casts, slight tweak to how validators are handled, added validation documentation for the wiki.
This commit is contained in:
41
doc/validation.md
Normal file
41
doc/validation.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Validation in Spring Data REST
|
||||
|
||||
Integrating validation with the Spring Data REST Exporter is as easy as simply defining an instance of a [Validator](http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/validation/Validator.html). There is an ApplicationListener that that looks for these Validator instances on startup and wires them to the correct RepositoryEvent based on the bean name.
|
||||
|
||||
For example, to validate entities before they are saved to the Repository, you only need to define a Validator instance in your ApplicationContext with a name that starts with "beforeSave".
|
||||
|
||||
<!--
|
||||
This validator will be picked up automatically. The default configuration is to look at the bean name
|
||||
and figure out what event you're interested in. This validator is interested in 'beforeSave' events
|
||||
because the word 'beforeSave' appears in the first part of the bean name. It recognizes:
|
||||
|
||||
- beforeSave
|
||||
- afterSave
|
||||
- beforeDelete
|
||||
- afterDelete
|
||||
- beforeLinkSave
|
||||
- afterLinkSave
|
||||
|
||||
What you put after that doesn't matter, you just need to make the bean name unique, of course.
|
||||
-->
|
||||
<bean id="beforeSavePersonValidator" class="com.mycompany.domain.validators.PersonValidator"/>
|
||||
|
||||
All the events dicussed in [Handling ApplicationEvents in the REST Exporter](wiki/Handling-ApplicationEvents-in-the-REST-Exporter) can be validated.
|
||||
|
||||
If any errors are found during validation, a [RepositoryConstraintViolationException](blob/master/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/RepositoryConstraintViolationException.java) will be thrown, resulting in a 400 Bad Request.
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
If you need a little more control over how the Validators are wired, you can instantiate a [ValidatingRepositoryEventListener](blob/master/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/context/ValidatingRepositoryEventListener.java) yourself and use a Map of Validators to their event names:
|
||||
|
||||
<bean class="org.springframework.data.rest.repository.context.ValidatingRepositoryEventListener">
|
||||
<property name="validators">
|
||||
<map>
|
||||
<entry key="beforeSave">
|
||||
<list>
|
||||
<bean class="org.springframework.data.rest.test.webmvc.PersonValidator"/>
|
||||
</list>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
@@ -7,6 +7,7 @@ import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.data.rest.repository.RepositoryConstraintViolationException;
|
||||
import org.springframework.data.rest.repository.ValidationErrors;
|
||||
@@ -30,18 +31,20 @@ public class ValidatingRepositoryEventListener
|
||||
|
||||
@Override public void afterPropertiesSet() throws Exception {
|
||||
if (validators.size() == 0) {
|
||||
Map<String, Validator> validators = applicationContext.getBeansOfType(Validator.class);
|
||||
for (Map.Entry<String, Validator> entry : validators.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
for (Map.Entry<String, Validator> entry : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,
|
||||
Validator.class)
|
||||
.entrySet()) {
|
||||
String name = null;
|
||||
Validator v = entry.getValue();
|
||||
|
||||
if (name.contains("Save")) {
|
||||
name = name.substring(0, name.indexOf("Save") + 4);
|
||||
} else if (name.contains("Delete")) {
|
||||
name = name.substring(0, name.indexOf("Delete") + 6);
|
||||
if (entry.getKey().contains("Save")) {
|
||||
name = entry.getKey().substring(0, name.indexOf("Save") + 4);
|
||||
} else if (entry.getKey().contains("Delete")) {
|
||||
name = entry.getKey().substring(0, name.indexOf("Delete") + 6);
|
||||
}
|
||||
if (null != name) {
|
||||
this.validators.put(name, v);
|
||||
}
|
||||
|
||||
this.validators.put(name, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
@@ -68,7 +67,6 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
@@ -251,7 +249,7 @@ public class RepositoryRestController
|
||||
RepositoryMetadata repoMeta = repositoryMetadataFor(repository);
|
||||
Links links = new Links();
|
||||
|
||||
Iterator iter = ((CrudRepository) repoMeta.repository()).findAll().iterator();
|
||||
Iterator iter = repoMeta.repository().findAll().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Object o = iter.next();
|
||||
Serializable id = (Serializable) repoMeta.entityMetadata().idAttribute().get(o);
|
||||
@@ -396,7 +394,7 @@ public class RepositoryRestController
|
||||
URI baseUri = uriBuilder.build().toUri();
|
||||
|
||||
RepositoryMetadata repoMeta = repositoryMetadataFor(repository);
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
MediaType incomingMediaType = request.getHeaders().getContentType();
|
||||
final Object incoming = readIncoming(request, incomingMediaType, repoMeta.entityMetadata().type());
|
||||
if (null == incoming) {
|
||||
@@ -441,7 +439,7 @@ public class RepositoryRestController
|
||||
(Class<? extends Serializable>) repoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
.type());
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
Object entity = repo.findOne(serId);
|
||||
if (null == entity) {
|
||||
model.addAttribute(STATUS, HttpStatus.NOT_FOUND);
|
||||
@@ -500,7 +498,7 @@ public class RepositoryRestController
|
||||
(Class<? extends Serializable>) repoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
.type());
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
Object entity = null;
|
||||
Class<?> domainType = repoMeta.entityMetadata().type();
|
||||
switch (request.getMethod()) {
|
||||
@@ -561,7 +559,7 @@ public class RepositoryRestController
|
||||
(Class<? extends Serializable>) repoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
.type());
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
|
||||
if (null != eventPublisher) {
|
||||
eventPublisher.publishEvent(new BeforeDeleteEvent(serId));
|
||||
@@ -596,7 +594,7 @@ public class RepositoryRestController
|
||||
(Class<? extends Serializable>) repoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
.type());
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
Object entity = repo.findOne(serId);
|
||||
if (null == entity) {
|
||||
model.addAttribute(STATUS, HttpStatus.NOT_FOUND);
|
||||
@@ -680,7 +678,7 @@ public class RepositoryRestController
|
||||
(Class<? extends Serializable>) repoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
.type());
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
final Object entity = repo.findOne(serId);
|
||||
if (null == entity) {
|
||||
model.addAttribute(STATUS, HttpStatus.NOT_FOUND);
|
||||
@@ -790,7 +788,7 @@ public class RepositoryRestController
|
||||
(Class<? extends Serializable>) repoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
.type());
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
final Object entity = repo.findOne(serId);
|
||||
if (null == entity) {
|
||||
model.addAttribute(STATUS, HttpStatus.NOT_FOUND);
|
||||
@@ -838,7 +836,7 @@ public class RepositoryRestController
|
||||
(Class<? extends Serializable>) repoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
.type());
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
final Object entity = repo.findOne(serId);
|
||||
if (null != entity) {
|
||||
AttributeMetadata attrMeta = repoMeta.entityMetadata().attribute(property);
|
||||
@@ -891,7 +889,7 @@ public class RepositoryRestController
|
||||
(Class<? extends Serializable>) repoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
.type());
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
final Object entity = repo.findOne(serId);
|
||||
if (null == entity) {
|
||||
model.addAttribute(STATUS, HttpStatus.NOT_FOUND);
|
||||
@@ -901,7 +899,7 @@ public class RepositoryRestController
|
||||
// Find linked entity
|
||||
RepositoryMetadata linkedRepoMeta = repositoryMetadataFor(attrMeta);
|
||||
if (null != linkedRepoMeta) {
|
||||
CrudRepository linkedRepo = (CrudRepository) linkedRepoMeta.repository();
|
||||
CrudRepository linkedRepo = linkedRepoMeta.repository();
|
||||
Serializable sChildId = stringToSerializable(linkedId,
|
||||
(Class<? extends Serializable>) linkedRepoMeta.entityMetadata()
|
||||
.idAttribute()
|
||||
@@ -950,13 +948,15 @@ public class RepositoryRestController
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@ExceptionHandler(OptimisticLockingFailureException.class)
|
||||
@ResponseBody
|
||||
public ResponseEntity handleLockingFailure(OptimisticLockingFailureException ex) throws IOException {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
public Model handleLockingFailure(OptimisticLockingFailureException ex) throws IOException {
|
||||
Model model = new ExtendedModelMap();
|
||||
model.addAttribute(STATUS, HttpStatus.CONFLICT);
|
||||
|
||||
Map m = new HashMap();
|
||||
m.put("message", ex.getMessage());
|
||||
return new ResponseEntity(objectMapper.writeValueAsBytes(m), headers, HttpStatus.CONFLICT);
|
||||
|
||||
model.addAttribute(RESOURCE, m);
|
||||
return model;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@@ -1013,7 +1013,7 @@ public class RepositoryRestController
|
||||
String sId = UriUtils.path(uris.get(1));
|
||||
|
||||
RepositoryMetadata repoMeta = repositoryMetadataFor(repoName);
|
||||
CrudRepository repo = (CrudRepository) repoMeta.repository();
|
||||
CrudRepository repo = repoMeta.repository();
|
||||
if (null == repo) {
|
||||
return null;
|
||||
}
|
||||
@@ -1057,18 +1057,14 @@ public class RepositoryRestController
|
||||
}
|
||||
}
|
||||
|
||||
List<Link> links = (List<Link>) entityDto.get(LINKS);
|
||||
if (null == links) {
|
||||
links = new ArrayList<Link>();
|
||||
entityDto.put(LINKS, links);
|
||||
}
|
||||
for (String attrName : entityMetadata.linkedAttributes().keySet()) {
|
||||
URI uri = UriComponentsBuilder.fromUri(baseUri)
|
||||
.pathSegment(attrName)
|
||||
.build()
|
||||
.toUri();
|
||||
Link l = new SimpleLink(repoRel + "." + entity.getClass().getSimpleName() + "." + attrName, uri);
|
||||
List<Link> links = (List<Link>) entityDto.get(LINKS);
|
||||
if (null == links) {
|
||||
links = new ArrayList<Link>();
|
||||
entityDto.put(LINKS, links);
|
||||
}
|
||||
links.add(l);
|
||||
links.add(new SimpleLink(repoRel + "." + entity.getClass().getSimpleName() + "." + attrName,
|
||||
buildUri(baseUri, attrName)));
|
||||
}
|
||||
|
||||
return entityDto;
|
||||
|
||||
Reference in New Issue
Block a user