4

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();
    }
pbuchheit
  • 1,371
  • 1
  • 20
  • 47
  • Possible duplicate of [JAX-WS - Map Exceptions to faults](https://stackoverflow.com/questions/2064447/jax-ws-map-exceptions-to-faults) – Optional Nov 25 '17 at 08:05
  • Java 6, now support TLS 1.2, check out below http://www.oracle.com/technetwork/java/javase/overview-156328.html#R160_121 – DevJava Nov 28 '17 at 15:47
  • @ LAKHDAR Omar I'm aware that there is a version of java 6 that supports TLSv1.2. Unfortunately, those versions of the JDK are not publicly available that I'm aware of. The only way to get them is with a paid support contract with oracle. If I'm wrong about that and there is some reputable way to get access to the newer versions of the java 6 jdk please let me know. – pbuchheit Nov 28 '17 at 16:32
  • Paying for support is reputable :-) – Stephen C Dec 01 '17 at 13:51
  • I guess that was poorly worded. I meant a legal way to obtain the updated jdk without paying thousands of dollars a year. – pbuchheit Dec 01 '17 at 16:00
  • Let me guess, you added a default no-arg constructor? :P – Chris Neve Dec 04 '17 at 12:18

3 Answers3

3

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.

pbuchheit
  • 1,371
  • 1
  • 20
  • 47
0

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.

Har Krishan
  • 273
  • 1
  • 11
  • Thanks for the suggestion, but if you look again at the code I posted that is exactly what I am doing. – pbuchheit Nov 29 '17 at 13:45
  • I cannot see code where you are populating AddressServiceFault and then setting in AddressValidationServiceException and then throwing the AddressValidationServiceException. In your service's method getValidAddressXMLByLocation catch the exception, populate AddressServiceFault and set in AddressValidationServiceException and then throw, it will work – Har Krishan Nov 29 '17 at 13:51
  • I updated the example to include the code where the exception is actually thrown. Populating and throwing the exception does not seem to be the cause. – pbuchheit Nov 29 '17 at 15:45
-1

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.

jausen brett
  • 1,111
  • 7
  • 10