Improve error handling in the Spring HATEOAS-based sample
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.DefaultErrorAttributes;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
|
||||
@Component
|
||||
class ExceptionSupressingErrorAttributes extends DefaultErrorAttributes {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
|
||||
boolean includeStackTrace) {
|
||||
Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
|
||||
errorAttributes.remove("exception");
|
||||
Object message = requestAttributes.getAttribute("javax.servlet.error.message", RequestAttributes.SCOPE_REQUEST);
|
||||
if (message != null) {
|
||||
errorAttributes.put("message", message);
|
||||
}
|
||||
return errorAttributes;
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,13 @@ package com.example.notes;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface NoteRepository extends CrudRepository<Note, Long> {
|
||||
|
||||
Optional<Note> findById(long id);
|
||||
|
||||
List<Note> findByTagsIn(Collection<Tag> tags);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ import com.example.notes.TagResourceAssembler.TagResource;
|
||||
@RequestMapping("/notes")
|
||||
public class NotesController {
|
||||
|
||||
private static final UriTemplate TAG_URI_TEMPLATE = new UriTemplate("/tags/{id}");
|
||||
|
||||
private final NoteRepository noteRepository;
|
||||
|
||||
private final TagRepository tagRepository;
|
||||
@@ -52,7 +54,8 @@ public class NotesController {
|
||||
|
||||
@Autowired
|
||||
public NotesController(NoteRepository noteRepository, TagRepository tagRepository,
|
||||
NoteResourceAssembler noteResourceAssembler, TagResourceAssembler tagResourceAssembler) {
|
||||
NoteResourceAssembler noteResourceAssembler,
|
||||
TagResourceAssembler tagResourceAssembler) {
|
||||
this.noteRepository = noteRepository;
|
||||
this.tagRepository = tagRepository;
|
||||
this.noteResourceAssembler = noteResourceAssembler;
|
||||
@@ -84,21 +87,25 @@ public class NotesController {
|
||||
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
|
||||
Resource<Note> note(@PathVariable("id") long id) {
|
||||
Note note = this.noteRepository.findOne(id);
|
||||
Note note = this.noteRepository.findById(id).orElseThrow(
|
||||
() -> new ResourceDoesNotExistException());
|
||||
return this.noteResourceAssembler.toResource(note);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{id}/tags", method = RequestMethod.GET)
|
||||
ResourceSupport noteTags(@PathVariable("id") long id) {
|
||||
return new NestedContentResource<TagResource>(
|
||||
this.tagResourceAssembler.toResources(this.noteRepository.findOne(id)
|
||||
.getTags()));
|
||||
this.tagResourceAssembler
|
||||
.toResources(this.noteRepository.findById(id)
|
||||
.orElseThrow(() -> new ResourceDoesNotExistException())
|
||||
.getTags()));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.PATCH)
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
void updateNote(@PathVariable("id") long id, @RequestBody NotePatchInput noteInput) {
|
||||
Note note = this.noteRepository.findOne(id);
|
||||
Note note = this.noteRepository.findById(id).orElseThrow(
|
||||
() -> new ResourceDoesNotExistException());
|
||||
if (noteInput.getTagUris() != null) {
|
||||
note.setTags(getTags(noteInput.getTagUris()));
|
||||
}
|
||||
@@ -112,11 +119,23 @@ public class NotesController {
|
||||
}
|
||||
|
||||
private List<Tag> getTags(List<URI> tagLocations) {
|
||||
UriTemplate template = new UriTemplate("/tags/{id}");
|
||||
return tagLocations
|
||||
.stream()
|
||||
.map(location -> this.tagRepository.findOne(Long.valueOf(template.match(
|
||||
location.toASCIIString()).get("id"))))
|
||||
.map(location -> this.tagRepository.findById(extractTagId(location))
|
||||
.orElseThrow(
|
||||
() -> new IllegalArgumentException("The tag '" + location
|
||||
+ "' does not exist")))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private long extractTagId(URI tagLocation) {
|
||||
try {
|
||||
String idString = TAG_URI_TEMPLATE.match(tagLocation.toASCIIString()).get(
|
||||
"id");
|
||||
return Long.valueOf(idString);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw new IllegalArgumentException("The tag '" + tagLocation + "' is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class ResourceDoesNotExistException extends RuntimeException {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
|
||||
@ControllerAdvice
|
||||
public class RestNotesControllerAdvice {
|
||||
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
public void handleIllegalArgumentException(IllegalArgumentException ex,
|
||||
HttpServletResponse response) throws IOException {
|
||||
response.sendError(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(ResourceDoesNotExistException.class)
|
||||
public void handleResourceDoesNotExistException(ResourceDoesNotExistException ex,
|
||||
HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
response.sendError(HttpStatus.NOT_FOUND.value(),
|
||||
"The resource '" + request.getRequestURI() + "' does not exist");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,8 +16,12 @@
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface TagRepository extends CrudRepository<Tag, Long> {
|
||||
|
||||
Optional<Tag> findById(long id);
|
||||
|
||||
}
|
||||
|
||||
@@ -74,14 +74,16 @@ public class TagsController {
|
||||
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
|
||||
Resource<Tag> tag(@PathVariable("id") long id) {
|
||||
Tag tag = this.repository.findOne(id);
|
||||
Tag tag = this.repository.findById(id).orElseThrow(
|
||||
() -> new ResourceDoesNotExistException());
|
||||
return this.tagResourceAssembler.toResource(tag);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{id}/notes", method = RequestMethod.GET)
|
||||
ResourceSupport tagNotes(@PathVariable("id") long id) {
|
||||
return new NestedContentResource<NoteResource>(
|
||||
this.noteResourceAssembler.toResources(this.repository.findOne(id)
|
||||
this.noteResourceAssembler.toResources(this.repository.findById(id)
|
||||
.orElseThrow(() -> new ResourceDoesNotExistException())
|
||||
.getNotes()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user