I am using JAX WS to expose a WebService. Some of the operations of this service can generate exceptions. Not internal server exceptions, but rather exceptions that are dependent on the input arguments of the operation invocation.
If I specify that my operation throws a custom Exception, like so:
#WebService
#SOAPBinding(style = Style.RPC, use = Use.LITERAL)
public class MyServiceEndpointImpl implements MyServiceEndpoint {
#WebMethod
public void throwsException throws InvalidInputException;
}
I end up with the following stacktrace when running the application:
com.sun.xml.ws.model.RuntimeModelerException: runtime modeler error: Wrapper class com.mypackage.ws.services.jaxws.InvalidInputExceptionBean is not found. Have you run APT to generate them?
at com.sun.xml.ws.model.RuntimeModeler.getClass(RuntimeModeler.java:285)
at com.sun.xml.ws.model.RuntimeModeler.processExceptions(RuntimeModeler.java:1006)
at com.sun.xml.ws.model.RuntimeModeler.processRpcMethod(RuntimeModeler.java:969)
at com.sun.xml.ws.model.RuntimeModeler.processMethod(RuntimeModeler.java:546)
at com.sun.xml.ws.model.RuntimeModeler.processClass(RuntimeModeler.java:370)
at com.sun.xml.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:256)
at com.sun.xml.ws.server.EndpointFactory.createSEIModel(EndpointFactory.java:322)
at com.sun.xml.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:188)
at com.sun.xml.ws.api.server.WSEndpoint.create(WSEndpoint.java:467)
at org.jvnet.jax_ws_commons.spring.SpringService.getObject(SpringService.java:333)
at org.jvnet.jax_ws_commons.spring.SpringService.getObject(SpringService.java:45)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:121)
Adding #XmlRootEntity to InvalidInputException does not solve the problem.
If this is not the recommended way to report faults over web services, then is there a better way? Should my exceptions inherit from RuntimeException and rely on the transport for the error handling (i.e., everything will end up wrapped in a SOAPException)? I was hoping for something like Spring-WS' SoapFaultAnnotationExceptionResolver. Is there something similar at all available for JAX-WS?
Did you try to annotate your exception with #WebFault? Also, do you implement getFaultInfo()?
EDIT: I realize my answer was maybe not detailed enough. As reminded in this thread (for example):
The JAX-WS 2.0 specification demands
that the exception annotated with
#WebFault must have two constructors
and one method [getter to obtain the fault information]:
WrapperException(String message, FaultBean faultInfo)
WrapperException(String message, FaultBean faultInfo, Throwable cause)
FaultBean getFaultInfo()
The WrapperException is replaced by
the name of the exception, and
FaultBean is replaced by the class
name that implements the fault bean.
The fault bean is a Java bean that
contains the information of the fault
and is used by the Web service client
to know the cause for the fault.
This is detailed in section 2.5 Fault of the JAX-WS specification. Does your exception conform to this? Can you post the code?
The OP is right. As per specification 2.1, section 3.7 Service Specific Exception, it is not required to use the #WebFault annotation, JAX-WS can generate the wrapper beans dynamically for exceptions that do not match the pattern described in section 2.5 (just provide a getter for the information you want to be present in the fault). For exceptions that match the pattern described in section 2.5 (i.e. exceptions that have a getFaultInfo method and #WebFault annotation), the FaultBean is used as input to JAXB when mapping the exception to XML Schema.
So the solution suggested above (matching the pattern described in section 2.5) is only a workaround. The generation of wrapper beans should just work for other exceptions. And I don't know why this fails here.
An addition to the answer above. I ended up with this as my InvalidInputException implementation:
#WebFault(faultBean = "com.mypackage.ws.exception.FaultBean")
public class InvalidInputException extends Exception {
private static final long serialVersionUID = 1L;
private FaultBean faultBean;
public InvalidInputException() {
super();
}
public InvalidInputException(String message, FaultBean faultBean, Throwable cause) {
super(message, cause);
this.faultBean = faultBean;
}
public InvalidInputException(String message, FaultBean faultBean) {
super(message);
this.faultBean = faultBean;
}
public FaultBean getFaultInfo() {
return faultBean;
}
}
And FaultBean is just a simple POJO with currently no data at all. Now, according to the JAX-WS specification (see 3.7 Service Specific Exception), it conforms to what is required of an exception annotated with #WebFault, so it will not create a wrapper bean for it, which probably is what was failing.
This is a decent workaround, but it does not explain the error in the question.
Related
I have a Spring Boot Java application. There is a service class that throws a "401 Unauthorized" HttpClientErrorException since the access token used in the application has expired. I want to handle this exception globally for which I have used the #ControllerAdvice annotation.
The error is:
Caused by: org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
The class is:
#Slf4j
#EnableWebMvc
#ControllerAdvice(basePackages = Service.class)
public class HttpClientErrorHandler{
#ExceptionHandler(HttpClientErrorException.class)
#ResponseStatus(HttpStatus.UNAUTHORIZED)
public String errorHandle(HttpClientErrorException e) {
log.error("log HttpClientErrorException: ", e);
return "HttpClientErrorException_message";
}
}
Since the exception was caused in the service class, I have mentioned it specifically in the basePackages. The entire configuration for the program is specified in the application.yml file. I have not used the xml configuration. I don't understand why the #ControllerAdvice annotation is not working. The program still throws the exception. Can someone explain?
#ControllerAdvice(basePackages = Service.class)
The exception is bubbled to #Controller class, and #ControllerAdvice is supposed to apply to controller, so you should set basePackageClasses to your controller package instead of your service package.
By default, #ControllerAdvice is applied to all Controller so you can remove the basePackageClasses unless you want to narrow down the controller advise
I had also faced similar issue,
try adding #Order(Ordered.HIGHEST_PRECEDENCE) below #ControllerAdvice.
We add it to get priority over Spring's default DefaultHandlerExceptionResolver. To understand more about why we add it read this answer.
Also no need to give base packages, it will consider all packages by default.
To handle exception of any other type you can include below existing exception handler for HttpClientErrorException you already have written,
#ExceptionHandler(Exception.class)
public Strring handleAnyExceptions(Exception ex) {
return "your message";
}
Hope it helps !
In JAX-RS I have several exceptions extending WebApplicationException, for example NotAuthorizedException and NotFoundException. These are mapped to the corresponding HTTP status codes, so for basic use cases I can just throw instances of these exceptions.
In Spring MVC I noticed that I have to write my own exception classes, and add the corresponding #ResponseStatus annotations:
#ResponseStatus(HttpStatus.UNAUTHORIZED)
private class NotAuthorizedException extends RuntimeException {
NotAuthorizedException(String message) {
super(message);
}
}
Is there a simpler way? Do pre-defined exception classes exist?
My Application - Java 1.6, Spring 3.1.2, Hibernate 4.1.1, Thymeleaf 2.0.15
Currently in my application, there is no any exception/error handling mechanism is implemented. I handling exceptions in ordinary cultural way. But now I need to introduce a "Robust Error Handling Mechanism". Please suggest me to implement Custom Error/Exception Handling mechanism with Example.
Thanks and appriciate from experts like you.
I'll make as an answer its easier to format. When you say "But I need to implement some Generalized Custom Exception so that same Exception could be thrown acrross the application." Its how I understood it and something that #ControllerAdvice is directly handling, but it applies only to Controllers. Than again, all you lower layers can declare throws on the method, and delegate it to Controller for exception handling. As an example, the following would be the error handling controller handling your custom exception
#ControllerAdvice
public class GlobalErrorHandler {
#ExceptionHandler(value = VermaException.class)
#ResponseBody
public String heightError(VermaException ex) {
return "error";
}
}
Your exception
public class VermaException extends Exception {
}
now whenever the the exception is thrown from the controller class, it will be captured and handled in your GlobalErrorHandler.
Again pasting the reference http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
UPDATE after comment
#ControllerAdvice is added in the version 3.2, for the earlier version you can have a CommonController extended by your controller, containing the error handler methods e.g. per Controller solution
#Controller
public class CommonController {
#ExceptionHandler
public #ResponseBody String handle(VermaException e) {
return "error";
}
}
an extending contorller
#Controller
public class ExceptionController extends CommonController {
#RequestMapping("/exception")
public #ResponseBody String exception() {
throw new VermaException();
}
}
For logging purposes, we're trying to catch various Spring's runtime exceptions via Spring's own AOP and I must say I've been unsuccessful, so I would appreciate any ideas as to how to approach this.
I've tried something like this:
#Aspect
#Component
public class SomeAspect {
#AfterThrowing(pointcut = "execution(* org.springframwork.oxm..*(..))", throwing = "exception")
#Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
public void adviseSpringErrorEvents(JoinPoint joinPoint, final UnmarshallingFailureException exception) throws Throwable {
LOG.debug(this.getClass().getSimpleName() + " - Error message advice fired on method: " + joinPoint.getSignature().getName());
}
}
The class is autoproxied and the rest of the advice in the aspect class correctly fire, so there has to be a problem with the AspectJ expression.
UPDATE: The code inside the method does not run and it is not my intention to catch the exception in the advice.
Any ideas? Thx in advance.
P.S. Spring framework version is 3.0.6.
Here are a couple of things that stand out to me:
Your point cut is for the spring package that the exception you are trying to catch it is in, it should be where you are trying to join execution(* com.mypackage..*(..)).
You are throwing throwable but you do not need to declare anything being thrown. The exception being advised of will not propagate through this code.
Things to try:
Expand your exception parameter to Exception. Maybe the exception you are looking for is in a different hierarchy.
Widen the pointcut to * package level - but probably best not to do both 1 and 2 at the same time.
Increase logging to a more severe level to be sure it is not getting gobbled by your logging framework.
EJB 3.1 Session Bean:
import javax.ejb.*;
public class FooException extends EJBException {
}
#Stateless #Local
public class Foo {
public void bar() throws FooException {
if (/* something wrong */) {
throw new FooException();
}
}
}
Now the test:
import org.junit.*;
public class FooTest {
#Test(expected = FooException.class)
public void testException() {
new InitialContext().lookup("Foo").bar();
}
}
The problem is that EJBException is caught in the test, not FooException. Looks like EJB container looses information about my custom exception type and throws a basic type (EJBException). What is wrong here? (it's OpenEJB 3.1)
First of all, you don't need to use the #Local annotation here. This designates an interface as a local interface or when used at a bean (in your case) can be used to point to a local interface (via the value attribute). Neither case is applicable here. Your code as given will also not compile. lookup("Foo") will return an Object that needs to be casted.
Anyway about the problem, the EJB container doesn't loose any information but wraps your exception in an EJBException. This is because FooException ultimately inherits from RuntimeException. Any such exception is treated by the container as a nonapplication exception and for those the EJB spec defines that they should be wrapped.
In your situation you already extend from EJBException, so it seems like this is a corner case. JBoss AS 6 for instance doesn't do the extra wrapping in this situation, but apparently OpenEJB does.
You can solve this problem by either not letting FooException inherit from EJBException, or by catching the exception in your test, unwrapping it and rethrowing the unwrapped exception.
Since your bar method is declaring that it throws FooException, my guess is that you didn't realize that EJBException is a RuntimeException and thus a nonapplication exception. Why did you let FooException inherrit from EJBException? Did you think this was somehow required, or does this need to server some special purpose?
(as an extra hint, make sure you understand the difference between application and nonapplicaton exceptions with respect to rolling back any transaction and destroying the pooled bean)