简体   繁体   中英

Switching from Java 1.6 to 1.7 causes JAXB Exception

I recently ran into a problem with one of our legacy applications that depends on the UPS Tracking API. UPS changed their communication protocols to require TLSv1.2 . Unfortunately, the most recent public version of jdk 1.6 does not seem to support this protocol, so my options were to pay for an oracle support contract or upgrade to jdk 1.7. I went with the upgrade to 1.7

I changed the dependencies for my project and everything looked fine. When I tried to actually deploy to the application server it failed with the error:

com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions java.lang.StackTraceElement does not have a no-arg default constructor

I did some research and apparently the issue is caused by jaxb @WebMethod annotated methods that throw an exception with throwable . The solution to that (I thought) was to add a @WebFault annotation to the exception class. I followed the instructions here: http://java.globinch.com/enterprise-java/web-services/jax-ws/jax-ws-exceptions-faults-annotation-exception-and-fault-handling-examples/ and re-deployed.

The result was the same error. The only difference is that my stacktrace is indicating that it is using my custom fault bean rather than trying to generate a wrapper. I also looked at the solutions given here: map exceptions to faults and as far as I can tell, my classes meet the specification but the problem persists.

This issue is preventing me from being able to fix the UPS problems and causing major headache for my users. Any help would be much appreciated.

My Error Log

Caused by: org.jboss.ws.WSException: Failed to create JAXBContext at jaxb.hibernate.XMLAcccesorAvailableContextFactory.createContext(XMLAcccesorAvailableContextFactory.java:41) at org.jboss.ws.metadata.builder.jaxws.JAXWSMetaDataBuilder.createJAXBContext(JAXWSMetaDataBuilder.java:940) ... 82 more Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions java.lang.StackTraceElement does not have a no-arg default constructor. this problem is related to the following location: at java.lang.StackTraceElement at public java.lang.StackTraceElement[] java.lang.Throwable.getStackTrace() at java.lang.Throwable at private java.lang.Throwable[] com.tura.common.server.service.addressvalidation.AddressServiceFault.suppressed at com.tura.common.server.service.addressvalidation.AddressServiceFault

at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:106)

The Exception Class

@WebFault(faultBean = "com.tura.common.server.service.addressvalidation.AddressServiceFault")
public class AddressValidationServiceException extends Exception {

    private AddressServiceFault faultInfo;

    public AddressValidationServiceException() {
        super();
    }
    public AddressValidationServiceException(AddressServiceFault fault) {
        super(fault.getFaultString());
        this.faultInfo = fault;
    }

    public AddressValidationServiceException(String message, AddressServiceFault fault) {
        super(message);
        this.faultInfo = fault;
    }

    public AddressValidationServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public AddressValidationServiceException(String message, AddressServiceFault fault, Throwable cause) {
        super(message, cause);
        this.faultInfo = fault;
    }

    protected AddressServiceFault getFaultInfo() {
        return faultInfo;
    }
}

The Fault Bean class

public class AddressServiceFault {

    private String faultCode;

    private String faultString;

    protected String getFaultCode() {
        return faultCode;
    }

    protected void setFaultCode(String faultCode) {
        this.faultCode = faultCode;
    }

    protected String getFaultString() {
        return faultString;
    }

    protected void setFaultString(String faultString) {
        this.faultString = faultString;
    }
}

My WebService Class

@WebMethod
    public @WebResult(name = "validatedAddresses") String parseAddressStringByLocation(
            @WebParam(name = "sLocation") String sLocation) throws AddressValidationServiceException {
        StringBuffer sbUrl = new StringBuffer();
        StringBuffer sbQueryString = new StringBuffer();

        sbUrl.append("http://test.foo.com");

        try {
            sbQueryString.append("&location=");
            sbQueryString.append(URLEncoder.encode(sLocation, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            AddressServiceFault serviceFault = new AddressServiceFault();
            serviceFault.setMessage("Validation Failed");
            throw new AddressValidationServiceException("Address Validation Error: parseQueryStringByLocation.",
                    serviceFault, e);
        }

        sbUrl.append(sbQueryString);

        return sbUrl.toString();
    }

Looks like no one has come up with a solution in time, so I will go ahead and post how I fixed this. JAX-WS uses reflection to determine If an exception class should be wrapped or not. As a result it is VERY picky about the constructors and methods included in the exception. If you look close at the AddressValidationServiceException class, you will notice that it has this method:

protected AddressServiceFault getFaultInfo() {
        return faultInfo;
    }

The problem is in the visibility of that method. getFaultInfo() MUST be a public method, otherwise jax-ws will not correctly recognize and wrap the exception class. As soon as I changed that method to public everything started working. In fact, I was able to remove the @WebFault annotation entirely. As long as the exception class and the fault are formatted correctly, the explicit annotation is not needed.

One other 'gotcha' to be aware of. Java constructors are not inherited. If you have additional classes that extend your exception, each class in the hierarchy must explicitly define the

public MyClass(String message, MyServiceFault fault)

and

public MyClass(String message, MyServiceFault fault, Throwable cause)

constructors.

It seems like your Exception class needs to override getStackTrace() and getCause() methods. Take a look here , the answer from Domenic D. could be the solution.

There might be a problem with the jaxb-impl version, which is also described.

Throwable objects cannot be serialized to XML directly as the StackTraceElement doesn't have a no-argument constructor, which is required by JAXB.

Use custom SOAP fault (class annotated with @WebFault) and send the exception details with detail element under soapFault.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM