well, i am working on a open source project named app4j, i designed this exception handling method, but i am not quite sure about it. so please give me some advice. the original post is
here
1, use code to identify exception.
for app4j, there is only one exception type, the StandardException?(@see org.app4j.StandardException?) which is a runtime exception. codes are used to identify exceptions. one code one exception. and the exception information should be easily looked up by its code. this means app4j would easily support a global exception database. for development, i think iterate every exception is worthy. exceptions should be managed centrally.
2, register exception handlers for codes
when @Entry's attribute error set to true, the app4j would take the method as a exception handler, for example:
static final int ERROR_USER_EXISTS = 1000;
static final int ERROR_INVALID_INPUT = 1001;
@Entry(value="", error=true, codes={ERROR_USER_EXISTS, ERROR_INVALID_INPUT})
public void registerErrorHandler(Event e){
e.setForward("profile/register");
e.setErrorProcessed();
}
this method handles 2 exceptions, when register users, the user's name should be unique, so there is User exist exception, and it also handles user's invalid input error. if a code missing its handler, app4j has default handler to redirect request to error page.
3, replace checked exception to with a annotation @Error.
checked exceptions sometimes are necessary, especially for interfaces, if we omit a runtime exception, the program possibly crash. so if a interface method want to document its exception, in this way:
@Entry("register")
@Error({ERROR_USER_EXISTS})
public void register(Event e){
if(e.isReadonly()){
e.setForward("profile/register");
return;
}
String name = e.getParameter("name");
String password = e.getParameter("password");
String role = e.getParameter("role");
if(name != null && password != null && role != null){
if(profiles.get(name) != null){
e.setLastError(new StandardException(ERROR_USER_EXISTS, "User name exists"));
e.stop();
return;
}
Person p = new Person(e.getActor());
p.setName(name);
p.setPassword(password);
p.setRole(role);
this.profiles.put(p.getName(), p);
e.setAttribute(Actor.KEY, p, Event.Scope.SESSION);
e.setAttribute("user-name", p.getName());
e.setForward("profile/info");
}else{
if(name == null){
e.setLastError(new StandardException(ERROR_INVALID_INPUT, "User name can't be empty"));
}else if(password == null){
e.setLastError(new StandardException(ERROR_INVALID_INPUT, "User password can't be empty"));
}else if(role == null){
e.setLastError(new StandardException(ERROR_INVALID_INPUT, "User role can't be empty"));
}
e.stop();
}
}
with @Error, we specify the exception codes the method probably thrown, and app4j would look up the handler for the exception, if the handler is missing, the app would failed to install. in fact, for the next version of app4j, actions would compile at runtime, so the error handler would weave into the action.
@Error also supports java doc.
4, avoid try{...}catch(){...}.
App4j is based on event model, event popping from one action to another. when current action finds the execution preconditions are not satisfied, it will change the status of event, not throw a exception, the framework would detect that and stop event popping.