Custom exception
public class JsonException extends RuntimeException{
private int code;
public JsonException() {
}
public JsonException(String message) {
super(message);
}
public JsonException(int code, String message) {
super(message);
this.code = code;
}
public JsonException(Throwable cause) {
super(cause);
}
public JsonException(String message, Throwable cause) {
super(message, cause);
}
}
Rest URI
#RestController
#RequestMapping("/api")
public class Rests {
#GetMapping("/e")
public Boolean exceptionCode() {
throw new JsonException(401, "test");
}}
Request for '/api/e', the error page write status 500.The problem is how to make the message is 'status=401,Type =test',
You are directly throwing exception in controller that why you got internal server error.
If you want return any specific reason then you have to construct object need to set the reason by exception.getMessage() and set the status code.
Related
I have a MessageHandler to receive WebSocket message, and I want resend the message to some restcontrollers. Message has type and content fields, I want to treat them as PostMapping and RequestBody. Is this possible?
public class MessageHandler extends TextWebSocketHandler {
#Override
public void handleTextMessage(#Nonnull final WebSocketSession session, #Nonnull final TextMessage message) {
// parse message and send to restcontroller
}
}
public class WsMessage {
public int type;
public String content;
}
I just converted our application code into simple classes to express the problem concisely. Our use case contains a class which internally uses some helper classes with static methods which needs to be mocked. So, planned to use PowerMockito. No issues with this part, however we have one class where we have an anonymous block inside one of the methods. When we try to create an instance of this class, PowerMockito fails with a very vague error. Tried spending few hours to resolve the issue without any luck.
public abstract class AbstractClass {
public abstract void methodOne(String arg);
public void methodTwo()
{
System.out.println("In method two");
}
}
public class StaticMethod {
public static String someStaticMethod()
{
System.out.println("in static method");
return "static";
}
}
public class AbstractClassCaller {
public AbstractClassCaller()
{
StaticMethod.someStaticMethod();
// The following piece of code is the problematic block
AbstractClass abstractClassInstance = new AbstractClass(){
public void methodOne(String methodArg)
{
System.out.println("In Method One");
}
};
}
}
#Test
#PrepareForTest({AbstractClassCaller.class,StaticMethod.class})
public class AbstractClassCallerTest {
#Test
public void test() throws Exception
{
PowerMockito.mockStatic(StaticMethod.class);
PowerMockito.when(StaticMethod.someStaticMethod()).thenReturn(
"PowerStatic");
// This is the code which triggers the exception
AbstractClassCaller instance = new AbstractClassCaller();
}
#ObjectFactory
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
}
The above junit class fails with the following exception:
org.powermock.reflect.exceptions.ConstructorNotFoundException: Failed to lookup constructor with parameter types [ com.oracle.oal.seaas.AbstractClassCaller ] in class com.oracle.oal.seaas.AbstractClassCaller$1.
at com.oracle.oal.seaas.AbstractClassCallerTest.test(AbstractClassCallerTest.java:21)
Caused by: java.lang.NoSuchMethodException: com.oracle.oal.seaas.AbstractClassCaller$1.<init>(com.oracle.oal.seaas.AbstractClassCaller)
at com.oracle.oal.seaas.AbstractClassCallerTest.test(AbstractClassCallerTest.java:21)
// the following anonymous block in AbstractClassCaller is causing the issue:
AbstractClass abstractClassInstance = new AbstractClass(){
public void methodOne(String methodArg)
{
System.out.println("In Method One");
}
};
Any ideas on how to fix this issue?
I am trying to update an audit entry using the response body advice but as far as I can tell it never gets executed. I see the bean in the logs:
{"timestamp":"2018-08-21T15:48:08.349Z","level":"INFO","thread":"main",
"logger":"org.springframework.data.rest.webmvc.RepositoryRestHandlerAdapter",
"message":"Detected ResponseBodyAdvice bean in responseAuditAdvice","context":"default"}
My controller method looks like this:
#PostMapping(path = "/stage", consumes = {
"application/json"
}, produces = {
"application/json"
})
#ResponseBody
public ResponseEntity<?> stage(#Valid #RequestBody StagingDto stagingDto,
#RequestHeader(HttpHeaders.USER_AGENT) String userAgent,
BindingResult bindingResult) {
I have a RequestAuditAdvice that extends RequestBodyAdviceAdapter and it is working fine. Also if the error flow occurs I see the exception advice executing as well. it is only the response advice that is failing to trigger. Any suggestions?
here is the advice bean:
#Slf4j
#RequiredArgsConstructor(onConstructor_ = #Inject)
#ControllerAdvice
public class ResponseAuditAdvice implements ResponseBodyAdvice<Object> {
private final RequestService requestService;
#Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
#Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
log.info("Updating audit for response.");
String ip = new String (request.getRemoteAddress().getAddress().getAddress());
requestService.auditResponse(ip, 200);
return body;
}
}
I am using asp.net mvc applicaiton and I am new about cross cutting concers. So I need to know where can I use my logger code following example.
I have an interface that logs erros. I am implementing this interface on my code.
public interface ILogger { void Log(Exception exception); }
So I have Controller, ProductService, ProductRepository classes.
public interface ProductController: ApiController{
public IHttpActionResult Get(){
try {
productService.GetProducts();
}catch(Exception e){
logger.Log(e); // 1-Should I use logging in here?
}
}
}
Product service;
public class ProductService{
public IEnumerable<Product> GetProducts(){
try {
productRepository.GetAll();
}catch(Exception e){
logger.Log(e); // 2-Should I use logging in here?
}
}
}
In repository.
public class ProductRepository{
public IEnumerable<Product> GetAll(){
try {
}catch(Exception e){
logger.Log(e); // 3-Should I use logging in here?
}
}
}
I could not determine where can I use logging code. Or add logging in everywhere.
You can implement custom exception filter.
public class LogExceptionAttribute : ExceptionFilterAttribute
{
public ILogger logger { get; set; }
public LogExceptionAttribute(ILogger logger)
{
this.logger = logger;
}
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
var exception = actionExecutedContext.Exception;
logger.Log(actionExecutedContext.Exception);
// You could also send client a message about exception.
actionExecutedContext.Response =
actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError, exception.Message);
}
}
Then register it on global level.
GlobalConfiguration.Configuration.Filters.Add(new LogExceptionAttribute(Logger));
This filter would be called for any unhandled exception thrown from controller method.
I'd like to return 404 when the response object is null for every response automatically in spring boot.
I need suggestions.
I don't want to check object in controller that it is null or not.
You need more than one Spring module to accomplish this. The basic steps are:
Declare an exception class that can be used to throw an exception when a repository method does not return an expected value.
Add a #ControllerAdvice that catches the custom exception and translates it into an HTTP 404 status code.
Add an AOP advice that intercepts return values of repository methods and raises the custom exception when it finds the values not matching expectations.
Step 1: Exception class
public class ResourceNotFoundException extends RuntimeException {}
Step 2: Controller advice
#ControllerAdvice
public class ResourceNotFoundExceptionHandler
{
#ExceptionHandler(ResourceNotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public void handleResourceNotFound() {}
}
Step 3: AspectJ advice
#Aspect
#Component
public class InvalidRepositoryReturnValueAspect
{
#AfterReturning(pointcut = "execution(* org.example.data.*Repository+.findOne(..))", returning = "result")
public void intercept(final Object result)
{
if (result == null)
{
throw new ResourceNotFoundException();
}
}
}
A sample application is available on Github to demonstrate all of this in action. Use a REST client like Postman for Google Chrome to add some records. Then, attempting to fetch an existing record by its identifier will return the record correctly but attempting to fetch one by a non-existent identifier will return 404.
Simplest way to do this in Spring is write your own exception class like below
#ResponseStatus(value = HttpStatus.NOT_FOUND)
class ResourceNotFoundException extends RuntimeException{
}
Then just throw the ResourceNotFoundException from anywhere.
if (something == null) throw new ResourceNotFoundException();
For more -> Read
Similar to #manish's answer (https://stackoverflow.com/a/43891952/986160) but without the AspectJ pointcut and using another #ControllerAdvice instead:
Step 1: NotFoundException class:
public class NotFoundException extends RuntimeException {
public NotFoundException(String msg) {
super(msg);
}
public NotFoundException() {}
}
Step 2: Check if body returned in endpoint is null and throw NotFoundException:
#ControllerAdvice
public class NotFoundAdvice implements ResponseBodyAdvice {
#Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
#Override
#SuppressWarnings("unchecked")
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body == null) {
throw new NotFoundException("resource not found");
}
return body;
}
}
Step 3: handle NotFoundException and make the response have a status of 404
#ControllerAdvice
public class GlobalExceptionAdvice {
#Data
public class ErrorDetails {
private Date timestamp;
private String message;
private String details;
public ErrorDetails(Date timestamp, String message, String details) {
super();
this.timestamp = timestamp;
this.message = message;
this.details = details;
}
}
#ExceptionHandler(NotFoundException.class)
public final ResponseEntity<ErrorDetails> notFoundHandler(Exception ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
}
Alternative to Step 3:
You can just annotate your NotFoundException with #ResponseStatus and override fillInStackTrace() (from https://stackoverflow.com/a/31263942/986160) so that it has similar effect to GlobalExceptionAdvice and doesn't show stacktrace like this:
#ResponseStatus(value = HttpStatus.NOT_FOUND,reason = "resource not found")
public class NotFoundException extends RuntimeException {
public NotFoundException(String msg) {
super(msg);
}
public NotFoundException() {}
#Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
There is no need to throw exceptions, now ResponseBodyAdvice does the trick:
#ControllerAdvice
public class NullTo404 implements ResponseBodyAdvice<Object> {
#Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
#Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
if (body == null) {
response.setStatusCode(HttpStatus.NOT_FOUND);
}
return body;
}
}
Similarly, you can implement ResponseBodyAdvice<Optional<?>>, and check for Optional.isEmpty() before setting the response status. It has the added benefit of working nicely with CrudRepository. Most controller methods eventually ends like this:
public Optional<Product> getProductBySku(#PathVariable String sku) {
// logic goes here...
return productRepository.findBySku(sku);
}