Home>

Beginners often don't know why java exceptions are designed like this,They usually handle exceptions simply

I. Background

I wrote this article from a friend who asked what is the difference between checked exception and unchecked exception in java.My answer at the time was:I only use runtime exceptions when programming. Actually, I have a premise to say something,It should be said exactly:writing business code in a mature development framework,I only use or follow runtime exceptions. Because, because frameworks often encapsulate exception handling uniformly,This allows programmers to better focus on business code,Some business errors usually occur during the operation of the system,Therefore, business exceptions are usually designed as a subclass of runtimeexception.

My answer obviously cannot satisfy my friends! Because, no matter who is new to Java,When we learn io class and jdbc programming,We use a lot of try ... catch ..., this kind of repeated try ... catch will make us deeply remember java exceptions! Beginners often don't know why java exceptions are designed like this,They usually do simple processing of exceptions-simply print out the exceptions in the catch block,The most commonly used is this statement:

e.printstacktrace ().

We also with some memories,Exceptions such as array out of bounds:

java.lang.arrayindexoutofboundsexception:6

It will also make us fresh,Because when we debug the program,It often appears! We will find that this kind of exception does not need to use try ... catch ... in the code to catch it.

The two examples above,In fact, it is the checked exception and unchecked exception that my friend asked. The exceptions that require try ... catch ... are checked exceptions, and those that do not need are unchecked exceptions. If i want to say their difference,I said that one of them should try ... catch ...Is this answer OK?I think such an answer is pale.Some classmates will further say,Obviously, try ... catch is to force the caller of the method that throws the exception to handle the exception explicitly.Then e.printstacktrace () does not count the exception,I think that's just a simple and lazy way to deal with it! What kind of processing is considered clever,Java language designers actually expect that after an exception occurs,The caller can recover the exception in the catch,Enables the program to continue execution.However, "smart programmers are lazy" Hehe, in most cases we choose to only log and ui user prompts after an exception occurs,I will talk about the unified exception handling in the Jersey framework later.Read here,Some would say,The difference between checked exception and unchecked exception is thatOne needs to deal with,One does not need to be processed.Is this answer correct?I think it is wrong! My point is:whether it is a checked exception or an unchecked exception, we have to deal with it!

In the previous paragraph, we still didn't seem to solve the difference between checked exception and unchecked exception. I don't think how to give the answer is important.What matters is how do we handle these exceptions,And how we use exceptions in development.

My point is (web system development):

1. Encapsulate checked exceptions at the framework level and convert them into unchecked exceptions to avoid writing tedious try ... catch code during development.

2. Business-level development,Define different runtime exceptions according to the responsibilities of the program code (it is an unchecked exception, generally defined as a subclass of runtime exception)

3. Through the first two points,There will be only unchecked exceptions in the custom exceptions in the system. The system is only in the upper layer of the client to exchange data.Set up a unified exception handling mechanism,And transfer some anomalies into information that users can understand to communicate to users.

4. Others such as business layer,Data persistence layer,Wait until the bottom layer is only responsible for throwing the exception,But be careful not to lose the exception stack (this is a mistake easy for beginners to make).

The background is long enough! Let's get to the topic,See how the unified exception handler for the Jersey framework is used!

Second, the unified exception handling mechanism of the jersey framework

There are the following conventions:

1.The example uses jersey1.x version

2.Spring version is 2.5

3. For simplicity,Example project does not use maven mechanism

Example business scenario description:

1. We read a properties configuration file,The contents of the configuration file are:

key1=hello
key2=iteye.com

2. Initiate a http://localhost:8888/a/resources/test&n=11 get request, requiring n to be a number and must be less than 10. If n is wrong, an unchecked exception error will be generated.

3. In this example, the data access layer will read a file.Reading a file error will generate a checked exception error.

Example project structure design

Code snippet description

1. Data storage file:test.properties

key1=hello
key2=iteye.com

This is the file we want to read,For simplicity,It is a properties file.

2. Data access class:testdao.java

package com.iteye.redhacker.jersey.dao;
import java.io.ioexception;
import java.io.inputstream;
import java.net.url;
import java.util.properties;
import org.springframework.stereotype.component;
import com.iteye.redhacker.jersey.exception.daoexception;
import com.iteye.redhacker.jersey.exception.exceptioncode;
@component
public class testdao {
public string sayhello () {
classloader classloader=testdao.class.getclassloader ();
string inifile="com/iteye/redhacker/jersey/dao/test.properties";
url url=classloader.getresource (inifile);
inputstream is;
try {
is=url.openstream ();
} catch (ioexception e) {
throw new daoexception (e, exceptioncode.read_file_failed);
}
properties proper=null;
try {
if (proper == null) {
proper=new properties ();
}
proper.load (url.openstream ());
} catch (ioexception e) {
throw new daoexception (e, exceptioncode.read_config_failed);
} finally {
if (is!=null) {
try {
is.close ();
is=null;
} catch (ioexception e) {
throw new daoexception (e, exceptioncode.colse_file_failed);
}
}
}
return proper.getproperty ("key1") + "," + proper.getproperty ("key2");
}
}

In that class,All checked exceptions are converted into unchecked exceptions (our custom exceptions). When calling the sayhello () method, there is no need to try ... catch ...

3. Business implementation class:testservice.java

package com.iteye.redhacker.jersey.service;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
import com.iteye.redhacker.jersey.dao.testdao;
import com.iteye.redhacker.jersey.exception.exceptioncode;
import com.iteye.redhacker.jersey.exception.serviceexception;
@component
public class testservice {
@autowired
private testdao testdao;
public string sayhello (int n) {
//The business stipulates that n cannot be greater than 10
if (n>10) {
throw new serviceexception (exceptioncode.must_be_less_than_10);
}
return testdao.sayhello ();
}
/**
* @param testdao the testdao to set
* /
public void settestdao (testdao testdao) {
this.testdao=testdao;
}
}

In that class,We throw an own business exception,It is an unchecked exception.

Note:we use @autowired to inject the testdao class, @autowired is an annotation provided by spring;We must provide a set method to annotate the property, otherwise the annotation will fail.

4. Request access class:testresources.java

package com.iteye.redhacker.jersey.delegate;
import javax.ws.rs.get;
import javax.ws.rs.path;
import javax.ws.rs.produces;
import javax.ws.rs.queryparam;
import javax.ws.rs.core.mediatype;
import com.iteye.redhacker.jersey.service.testservice;
import com.sun.jersey.api.spring.autowire;
@path ("/test")
@autowire
public class testresources {
private testservice testservice;
@get
@produces (mediatype.text_plain)
public string sayhello (@queryparam ("n") int n) {
return testservice.sayhello (n);
}
/**
* @param testservice the testservice to set
* /
public void settestservice (testservice testservice) {
this.testservice=testservice;
}
}

Here is a resource defined by Jersey,We can access this resource by initiating a get request, accessing the uri as/resources/test, and passing a query parameter n, for example:/resources/test?n=1

Note:we used @autowire not a spring annotation,It is an annotation of the jersey-srping integration package;We must provide a set method to annotate the property, otherwise the annotation will fail.

5, unified exception handler class:exceptionmappersupport.java

package com.iteye.redhacker.jersey.jaxrs;
import javax.servlet.servletcontext;
import javax.servlet.http.httpservletrequest;
import javax.ws.rs.core.context;
import javax.ws.rs.core.mediatype;
import javax.ws.rs.core.response;
import javax.ws.rs.core.response.status;
import javax.ws.rs.ext.exceptionmapper;
import javax.ws.rs.ext.provider;
import org.apache.log4j.logger;
import org.springframework.web.context.webapplicationcontext;
import com.iteye.redhacker.jersey.exception.baseexception;
import com.iteye.redhacker.jersey.exception.exceptioncode;
import com.sun.jersey.api.notfoundexception;
/**
 * Unified exception handler
 * /
@provider
public class exceptionmappersupport implements exceptionmapper<exception>{
private static final logger logger=logger
.getlogger (exceptionmappersupport.class);
private static final string context_attribute=webapplicationcontext.root_web_application_context_attribute;
@context
private httpservletrequest request;
@context
private servletcontext servletcontext;
/**
* Exception Handling
*
* @param exception
* @return response object after exception handling
* /
public response toresponse (exception exception) {
string message=exceptioncode.internal_server_error;
status statuscode=status.internal_server_error;
webapplicationcontext context=(webapplicationcontext) servletcontext
.getattribute (context_attribute);
//handle unchecked exception
if (exception instanceof baseexception) {
baseexception baseexception=(baseexception) exception;
string code=baseexception.getcode ();
object [] args=baseexception.getvalues ​​();
message=context.getmessage (code, args, exception.getmessage (),request.getlocale ());
} else if (exception instanceof notfoundexception) {
message=exceptioncode.request_not_found;
statuscode=status.not_found;
}
//both checked exception and unchecked exception are recorded in the log
logger.error (message, exception);
return response.ok (message, mediatype.text_plain) .status (statuscode)
.build ();
}
}

In this class, we handle the unchecked exception we defined, and also handle unknown exceptions (including unknown unchecked exception and checked exception). Our processing method is:a. Record abnormal logs;b. Throw a standard http standard error status code and error message to the client.The client handles the error information by itself,It is worth noting thatThis approach is advocated by rest,It properly uses the HTTP standard status code;

In this class we also use Spring's international configuration components,Used to internationalize the error key thrown by the system,This is conducive to the international upgrade of our project.

6, custom exception base class:baseexception.java

package com.iteye.redhacker.jersey.exception;
/**
 * Exception base class,Runtime exceptions of all modules inherit this class
 * /
public class baseexception extends runtimeexception {
  /**
   * the serialversionuid
   * /
  private static final long serialversionuid=1381325479896057076l;
  /**
   * message key
   * /
  private string code;
  /**
   * message params
   * /
  private object [] values;
  /**
   * @return the code
   * /
  public string getcode () {
    return code;
  }
  /**
   * @param code the code to set
   * /
  public void setcode (string code) {
    this.code=code;
  }
  /**
   * @return the values
   * /
  public object [] getvalues ​​() {
    return values;
  }
  /**
   * @param values ​​the values ​​to set
   * /
  public void setvalues ​​(object [] values) {
    this.values ​​= values;
  }
  public baseexception (string message, throwable cause, string code, object [] values) {
    super (message, cause);
    this.code=code;
    this.values ​​= values;
  }
}

This class defines the basic template for project exception classes,Other exceptions inherit with it.It is worth noting thatIt cleverly uses some features of the international configuration,You can even throw an error message defined like this,By passing parameters,Reuse error message:

{0} th {1} parameter error

7, other exceptions are basically the same,Just different types,Let's take a look at daoexception.java

package com.iteye.redhacker.jersey.exception;
public class daoexception extends baseexception {
/**
* constructors
*
* @param code
	 *      error code
* /
public daoexception (string code) {
super (code, null, code, null);
}
/**
* constructors
*
* @param cause
* Exception interface
* @param code
	 *      error code
* /
public daoexception (throwable cause, string code) {
super (code, cause, code, null);
}
/**
* constructors
*
* @param code
	 *      error code
* @param values
* A set of abnormal information pending parameters
* /
public daoexception (string code, object [] values) {
super (code, null, code, values);
}
/**
* constructors
*
* @param cause
* Exception interface
* @param code
	 *      error code
* @param values
* A set of abnormal information pending parameters
* /
public daoexception (throwable cause, string code, object [] values) {
super (code, null, code, values);
}
private static final long serialversionuid=-3711290613973933714l;
}

It inherits baseexception. When this exception is thrown,We directly and preliminary judged from the abnormal name,The error comes from the dao layer.

8, errmsg.properties is used to define exception information,Take a look:

read.file.failed=Failed to read the file
read.config.failed=Failed to read configuration items
must.be.less.than.10=The parameter must be less than 10
colse.file.failed=Failed to close the file
request.not.found=No corresponding service was found
internal.server.error=Server internal error

Third, deployment and testing

You can download the source code in the attachment to this article.After importing eclipse, view the source code.

Deployment is simple,Just add your tomcat/config/server.xml:

<host>
...
<context path="/a" reloadable="true" docbase="d:/workspace/test/jerseyexceptionmappertest/web" />
</host>

Just start tomcat!

Do two tests:

1,

2,

For the first test, you can also see the following exception error in the log:

[2013-08-15 00:25:55] [error] parameter must be less than 10
com.iteye.redhacker.jersey.exception.serviceexception:must.be.less.than.10
at com.iteye.redhacker.jersey.service.testservice.sayhello (testservice.java:20)
at com.iteye.redhacker.jersey.delegate.testresources.sayhello (testresources.java:21)
at sun.reflect.nativemethodaccessorimpl.invoke0 (native method)
at sun.reflect.nativemethodaccessorimpl.invoke (nativemethodaccessorimpl.java:39)
at sun.reflect.delegatingmethodaccessorimpl.invoke (delegatingmethodaccessorimpl.java:25)
at java.lang.reflect.method.invoke (method.java:597)
at com.sun.jersey.spi.container.javamethodinvokerfactory $1.invoke (javamethodinvokerfactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.abstractresourcemethoddispatchprovider $typeoutinvoker._dispatch (abstractresourcemethoddispatchprovider.java:185)
at com.sun.jersey.server.impl.model.method.dispatch.resourcejavamethoddispatcher.dispatch (resourcejavamethoddispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.httpmethodrule.accept (httpmethodrule.java:288)
at com.sun.jersey.server.impl.uri.rules.resourceclassrule.accept (resourceclassrule.java:108)
at com.sun.jersey.server.impl.uri.rules.righthandpathrule.accept (righthandpathrule.java:147)
at com.sun.jersey.server.impl.uri.rules.rootresourceclassesrule.accept (rootresourceclassesrule.java:84)
at com.sun.jersey.server.impl.application.webapplicationimpl._handlerequest (webapplicationimpl.java:1483)
at com.sun.jersey.server.impl.application.webapplicationimpl._handlerequest (webapplicationimpl.java:1414)
at com.sun.jersey.server.impl.application.webapplicationimpl.handlerequest (webapplicationimpl.java:1363)
at com.sun.jersey.server.impl.application.webapplicationimpl.handlerequest (webapplicationimpl.java:1353)

Regarding some other tests,Everyone can try it,For example, deliberately delete test.properties. When the file to be read cannot be found,How checked exception translates into our own definition of an unchecked exception, and records the log,Returns the standard HTTP error status code and error information to the client.

Summary

1. It is not difficult to see through the jersey framework,In terms of web project development,For the processing of checked exceptions and unchecked exceptions, we have unified processing at the framework level as much as possible.So that we pay more attention to the realization of the business.

2. If it is a non-web project, I think that the architect of the program should also try to handle exceptions uniformly;If you do n’t do it uniformly,When a checked exception is encountered, we should properly handle it,Instead of simply doing an e.printstacktrace ();if we can't recover the exception,Then we should at least fully record the abnormal error information in the log file.In order to troubleshoot in the event of a subsequent program failure.

Full text (end)