Edgaras Karka
Edgaras Karka

Reputation: 7852

How to remove try/catch repetitions in class methods?

I have RESTeasy service. And have implemented simple error handling on methods using try catch and feel something is not very well with it. I've noticed try catch repetition on all my methods. So I want ask way how to avoid repetition (to reduce code size) of try catch but not lost functionality.

@Path("/rest")
@Logged
@Produces("application/json")
public class CounterRestService {

  @POST
  @Path("/create")
  public CounterResponce create(@QueryParam("name") String name) {
    try {
        CounterService.getInstance().put(name);
        return new CounterResponce();
    } catch (Exception e){
        return new CounterResponce("error", e.getMessage());
    }   
}

@POST
@Path("/insert")
public CounterResponce create(Counter counter) {
    try {
        CounterService.getInstance().put(counter);
        return new CounterResponce();
    } catch (Exception e){
        return new CounterResponce("error", e.getMessage());
    }
}

@DELETE
@Path("/delete")
public CounterResponce delete(@QueryParam("name") String name) {
    try {
        CounterService.getInstance().remove(name);
        return new CounterResponce();
    } catch (Exception e){
        return new CounterResponce("error", e.getMessage());
    }
}
... // other methods with some try catch pattern

response

public class CounterResponce {
private String status;

@JsonSerialize(include=Inclusion.NON_NULL)
private Object data;

public CounterResponce() {
    this.status = "ok";
}

public CounterResponce(Object o) {
    this.status = "ok";
    this.data = o;
}

public CounterResponce(String status, Object o){
    this.status = status;
    this.data = o;
}

public String getStatus() {
    return status;
}
public void setStatus(String status) {
    this.status = status;
}
public Object getData() {
    return data;
}
public void setData(Object data) {
    this.data = data;
}
}

exceptions source

public class CounterService {

private Map<String, StatisticCounter> counters = new HashMap<String, StatisticCounter>();

private static CounterService instance = null;

protected CounterService() {}

public static CounterService getInstance() {
      if(instance == null) {
         instance = new CounterService();
      }
      return instance;
}

public StatisticCounter get(String name){
    StatisticCounter c =  counters.get(name);
    if(c == null)throw new IllegalArgumentException("Counter "+name+" not exist");
    return c;
}

public void put(String name){
    if(name==null)throw new IllegalArgumentException("null can`t be as name");
    if(counters.get(name)!=null)throw new IllegalArgumentException("Counter "+name+" exist");
    counters.put(name, new Counter(name));
 }...

Upvotes: 1

Views: 2410

Answers (2)

cassiomolin
cassiomolin

Reputation: 131067

The comments in your question are pointing you in a good direction. Since the answers do not mention it, I'll summarize the general idea in this answer.

Extending WebApplicationException

JAX-RS allows to define direct mapping of Java exceptions to HTTP error responses. By extending WebApplicationException, you can create application specific exceptions that build a HTTP response with the status code and an optional message as the body of the response.

The following exception builds a HTTP response with the 404 status code:

public class CustomerNotFoundException extends WebApplicationException {

    /**
    * Create a HTTP 404 (Not Found) exception.
    */
    public CustomerNotFoundException() {
      super(Responses.notFound().build());
    }

    /**
    * Create a HTTP 404 (Not Found) exception.
    * @param message the String that is the entity of the 404 response.
    */
    public CustomerNotFoundException(String message) {
      super(Response.status(Responses.NOT_FOUND).
      entity(message).type("text/plain").build());
    }
}

WebApplicationException is a RuntimeException and doesn't need to the wrapped in a try-catch block or be declared in a throws clause:

@Path("customers/{customerId}")
public Customer findCustomer(@PathParam("customerId") Long customerId) {
    Customer customer = customerService.find(customerId);
    if (customer == null) {
        throw new CustomerNotFoundException("Customer not found with ID " + customerId);
    }
    return customer;
}

Creating ExceptionMappers

In other cases it may not be appropriate to throw instances of WebApplicationException, or classes that extend WebApplicationException, and instead it may be preferable to map an existing exception to a response.

For such cases it is possible to use a custom exception mapping provider. The provider must implement the ExceptionMapper<E extends Throwable> interface. For example, the following maps the JAP EntityNotFoundException to a HTTP 404 response:

@Provider
public class EntityNotFoundExceptionMapper 
    implements ExceptionMapper<EntityNotFoundException> {

    @Override
    public Response toResponse(EntityNotFoundException ex) {
      return Response.status(404).entity(ex.getMessage()).type("text/plain").build();
    }
}

When an EntityNotFoundException is thrown, the toResponse(E) method of the EntityNotFoundExceptionMapper instance will be invoked.

The @Provider annotation declares that the class is of interest to the JAX-RS runtime. Such class may be added to the set of classes of the Application instance that is configured.

Upvotes: 1

K. M. Fazle Azim Babu
K. M. Fazle Azim Babu

Reputation: 195

  1. Introduce a private method such as "apply" which can take function as parameter if you use Java 8. This method will have the error handling and/or mapping, response mapping and response generation code centralized.
  2. From create and delete methods, invoke this apply method and pass the desired counter operation you wish to perform as a lambda expression.

Upvotes: 1

Related Questions