Why instance variable inside Custom Exception Mapper has to be static?

孤人 提交于 2019-12-11 15:13:04

问题


I have implemented a custom exception mapper in order to throw the bad request in my application. Here's the code:

CustomFilterBadRequest:

package com.test.exceptions;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import java.util.Date;

public class CustomFilterBadRequest extends Exception implements
        ExceptionMapper<CustomFilterBadRequest> {

    private String uriInfo;


    public CustomFilterBadRequest() {
        super("Invalid Request. Please try again with the valid request");
    }

    public CustomFilterBadRequest(String uriInfo, String message) {
        super(message);
        this.uriInfo = uriInfo;
    }

    @Override
    public Response toResponse(CustomFilterBadRequest exception) {
        return Response.status(400).entity(new ErrorDetails(new Date(),
                400, "bad request", exception.getMessage(),this.uriInfo)).type(MediaType.APPLICATION_JSON).build();
    }
}

Issue:

Note: In this example, I have an instance variable called uriInfo. From another service, I do :

throw new CustomFilterBadRequest("uri","message")

Immediately, the constructor gets called and my uriInfo is set to the value "uri". After this, toResponse method gets called.My uriInfo instance variable is reset. why? Whereas, when I made the instance variable to be static, the value is retained.

I am unable to get any documentation on this. Please help.

*****UPDATE*****

When the REST End point related to this exception is invoked, the default constructor of CustomFilterBadRequest is invoked creating an object with state uriInfo initialized to null. Let's call this object as object1.

when we do throw new CustomFilterBadRequest("uri","msg"), an object is created with state uriInfo initialized to the value uri. Let's call this object as object2.

JAX-RS Runtime maps the CustomFilterBadRequest exception to the exception mapper which is also CustomFilterBadRequest here. Hence toResponse method gets called. It gets uriInfo from object1. (which is obviously null here)

And there's no necessity that we should use only class variables inside Custom exception mappers.

This kind of implementation is quite confusing. I have updated with the straightforward implementation in the answer below.


回答1:


The problem is that the toResponse(...) method is called on the instance of CustomFilterBadRequest that is registered with the JAX-RS runtime. If the no-arg constructor is used in registration that is why uriInfo always has it's default value of null.

I would recommend that you have your exception defined in one class, and you Exception handler defined in another.

Exception:

public class CustomBadRequest extends Exception {

  private String uriInfo;

  public CustomBadRequest() {
    super("Invalid Request. Please try again with the valid request");
  }

  public CustomBadRequest(String uriInfo, String message) {
    super(message);
    this.uriInfo = uriInfo;
  }

  public String getUriInfo() {
    return uriInfo;
  }
}

ExceptionMapper:

@Provider
public class CustomFilterBadRequest implements ExceptionMapper<CustomBadRequest> {

  @Override
  public Response toResponse(CustomBadRequest exception) {
    return Response.status(400).entity(new ErrorDetails(new Date(),
      400, "bad request", exception.getMessage(),exception.getUriInfo())).type(MediaType.APPLICATION_JSON).build();
  }
}



回答2:


I understood the reason behind the issue.

Whenever we hit the end point, default constructors of exception mappers registered with the jersey is called and objects of each type are created with state initialized to default values of its type.

When the custom exception is thrown, the custom exception object is created and JAX-RS runtime searches for the exception mapper to map the exception. If none is found, it just maps to the default exception mapper. If the custom exception mapper is found, toResponse method is called. In this case, we should get the states of customexception from its object itself inside the toResponse method.

I needed this to obtain uriInfo inside exceptionmapper.

Here's the working code:

CustomFilterBadRequest.java

public class CustomFilterBadRequest extends Exception {

public CustomFilterBadRequest(String message) {
    super(message);
}

}

CustomFilterBadRequestExceptionMapper.java

public class CustomFilterBadRequestExceptionMapper implements ExceptionMapper<CustomFilterBadRequest> {

private UriInfo uriInfo;

public CustomFilterBadRequestExceptionMapper(@Context UriInfo uriInfo) {
    this.uriInfo = uriInfo;
}

@Override
public Response toResponse(CustomFilterBadRequest exception) {
    return Response.status(400).entity(new ErrorDetails(Instant.now(),
            400, "bad request", exception.getMessage(),this.uriInfo.getPath())).type(MediaType.APPLICATION_JSON).build();
}

}

Thanks a lot everyone for the response.




回答3:


Im pretty sure this is all you have to do:

CustomFilterBadRequest:

package com.test.exceptions;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import java.util.Date;

public class CustomFilterBadRequest extends Exception implements
        ExceptionMapper<CustomFilterBadRequest> {

    private String uriInfo;


    public CustomFilterBadRequest() {
        super("Invalid Request. Please try again with the valid request");
    }

    public CustomFilterBadRequest(String uriInfo, String message) {
        super(message);
        this.uriInfo = uriInfo;
    }

    @Override
    public Response toResponse(CustomFilterBadRequest exception) {
        return Response.status(400).entity(new ErrorDetails(new Date(),
                400, "bad request", exception.getMessage(),exception.uriInfo)).type(MediaType.APPLICATION_JSON).build();
    }
}

I just changed this.uriInfo to exception.uriInfo

Basically, when you throw a CustomFilterBadRequestException, JAX-RS creates a new instance to map the exception you threw. This new instance has a default value of uriInfo. So thus it is not saved.

Whatever you do, don’t make uriInfo static. That would cause huge concurrency issues.



来源:https://stackoverflow.com/questions/49670142/why-instance-variable-inside-custom-exception-mapper-has-to-be-static

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!