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:
Jon Brisbin
2012-05-03 09:10:32 -05:00
parent 09df01a0ad
commit ab7b497d72
3 changed files with 79 additions and 39 deletions

41
doc/validation.md Normal file
View 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>

View File

@@ -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);
}
}
}

View File

@@ -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;