Over a million developers have joined DZone.

The Java Web App Journey... SOAP Services (Part 4, Finale)

Join us for the final episode of our series, where we fully web-enable and share a Java app. See how to tackle service responses, error handling, and more.

· Java Zone

Learn more about how the Java language, tools and frameworks have been the foundation of countless enterprise systems, brought to you in partnership with Salesforce.


We have a somewhat working SOAP service now.  Let's continue from where we left off in part 3.

You can get the code used in this article from the bottom of the previous article.

We have been using Eclipse, Tomcat 8, and MySQL — as mentioned, all the information is available in previous articles of the series.

In our make-believe story, your department boss approached you, remarked that other departments have liked your initial command-line app (that wraps the Shape Calculator), as well as the first release of the web application for the same. But still, others need to use it via a web service so they can incorporate it into their in-house business processes.

For now, they just want something — this is not customer-facing — it's really not much more than a pilot or proof-of-concept.

Between the other department and yours, some requirements were pinned down

To-Do: Service Responses

We have been fleshing out one of the operations as an example: queueCalculationRequest(), and we left off last at tackling sending back a response.

Here is the latest version of the operation:

    public SuccessOrErrorResponse queueCalculationRequest(
            ShapeName shapeName, 
            CalcType calcType, 
            double dimension) {

        logger.debug("\n\n\nExecuting operation queueCalculationRequest:"
                +shapeName+","+calcType+","+dimension+" ...\n\n\n");


        return null;

So we need to turn that null into a SuccessOrErrorResponse.

In tackling this response, it touches on how will we handle errors. Based on the agreed-upon requirements (#3), we are going to convert everything into some return code. (Not necessarily numeric).

We went round and round about how to handle exceptions (use try-catch vs. using AOP), but these are simple methods, and there are only a few.

Yes, we didn't like how much mixing of business logic and exception handling there would be (except that business handling boils down to about one line of code per operation — the rest IS exception handling).  And yes, there will be some code redundancy.

Of note as well is that if we do a top-down, wsdl-to-code approach (upcoming articles), the Apache CXF cxf-codegen-plugin running wsdltojava does use try-catch blocks when it generates the service implementation.

In any case, we can always come back and refactor if it is warranted.

If you think different, please share.

So I went with try-catch (gasp!) (tsk-tsk).

We want to be informative, but not too informative. And we want it to be simple and clear.

Implement SuccessOrErrorResponse

Working top-down as always, we enhance our queueCalculationRequest() operation to return something meaningful and to handle errors:

    public SuccessOrErrorResponse queueCalculationRequest(
            ShapeName shapeName, 
            CalcType calcType, 
            double dimension) {

        logger.debug("\n\n\nExecuting operation queueCalculationRequest:"
                +shapeName+","+calcType+","+dimension+" ...\n\n\n");

        SuccessOrErrorResponse response = null;
        try {

            response = new SuccessOrErrorResponse(RespCode.SUCCESS,"Request queued:"+shapeName+","+calcType+","+dimension);

        } catch (Exception e) {
            logger.error("Error attempting to queueCalculationRequest",e);
            response = new SuccessOrErrorResponse("Error Attempting to Queue Calculation Request",e);

        return response;

Those additions necessitated enhancing the SuccessOrErrorResponse class and creating an Enum.

For the Response class, we added three constructors:

  • Default — with some "bad" data to hopefully trigger to the developer he forgot to set some fields in the client code.

  • One typically used for SUCCESS.

  • And one for definite errors, with the corresponding exception.


package com.eli.calc.shape.service.ws.types;

public class SuccessOrErrorResponse {

    private RespCode code;

    private String description;

    private Class clazz;

    private String errMsg;

    private String causeMsg;

    public SuccessOrErrorResponse() {

        this.code = RespCode.ERROR;
        this.description = "DESCRIPTION NEEDS TO BE SET";
        Exception e = new Exception(
                "NEED AN EXCEPTION CLASS",
                new IllegalArgumentException("FAKE CAUSE"));
        this.clazz = e.getClass();
        this.errMsg = e.getMessage();
        this.causeMsg = e.getCause().getMessage();

    public SuccessOrErrorResponse(RespCode code, String description) {


        this.code = code;
        this.description = description;

        if (RespCode.SUCCESS.equals(code)) {
            this.clazz = null;
            this.errMsg = null;
            this.causeMsg = null;

    public SuccessOrErrorResponse(String description, Exception e) {


        if (null!=e) {
            this.clazz = e.getClass();
            this.errMsg = e.getMessage();
            if (e.getCause()!=null) { this.causeMsg = e.getCause().getMessage(); }
            else { this.causeMsg = null; }

    public RespCode getCode() {
        return code;

    public void setCode(RespCode code) {
        this.code = code;

    public String getDescription() {
        return description;

    public void setDescription(String description) {
        this.description = description;

    public Class getClazz() {
        return clazz;

    public void setClazz(Class clazz) {
        this.clazz = clazz;

    public String getErrMsg() {
        return errMsg;

    public void setErrMsg(String errMsg) {
        this.errMsg = errMsg;

    public String getCauseMsg() {
        return causeMsg;

    public void setCauseMsg(String causeMsg) {
        this.causeMsg = causeMsg;

    public String toString() {
        return "SuccessOrErrorResponse [code=" + code + ", description=" + description + ", clazz=" + clazz
                + ", errMsg=" + errMsg + ", causeMsg=" + causeMsg + "]";



package com.eli.calc.shape.service.ws.types;

public enum RespCode {


Test SuccessOrResponse

Let's try some tests:

  1. Bad values: "1","1","1".

  2. Partially bad values:

    1. { "CIRCLE","1","1" }.

    2. { "1","CALC_AREA","1" }.

    3. { "CIRCLE","CALC_AREA", "-1" }.

  3. Good values: { "CIRCLE","CALC_AREA","1" }.

  4. And finally, a system error: Let's shut down MySQL.

I am not going to show every test result, but let's run through a few.

Test #1: "1","1","1"

Image title

Test #3: "CIRCLE","CALC_AREA","1"

Image title

Test #4: Database Disconnect

Image title

We may decide that the above is giving away too much information, as the errMsg can include a long string of nested exceptions.


It is possible we were (lazy, rushed, conservative, pick your adjective) before, when we were developing our core project, the Shape Calculator. When passes a bad ShapeName, or a bad CalcType, it knows the distinction and says so in the exception. However, the exception itself is just a generic IllegalArgumentException. Perhaps we should have created distinct exceptions.

I bring that up because I added "BADSHAPE", "BADCALC", and "BADDIM" to the RespCode enum.

OR we can just replace those with BADVAL.

In our story, the Shape Calculator component is already being used by some people and departments, both via the command-line and via a web application...  so... changing/upgrading the base project isn't a choice done in a vacuum. Do we make the change anyway and not worry about it?

I chose to delay the choice until necessary. So, we'll leave things as they are, even if less than optimal. That means we are just going to use SUCCESS or ERROR (for now).

Implement Get All Pending Requests

Let's cover one more interesting method, since this one returns a List<CalculationRequest>.

I did a copy-paste of our previously implemented method, and made the appropriate changes:

    public PendingRequestsResponse getAllPendingRequests() {

        logger.debug("\n\n\nExecuting operation getAllPendingRequests...\n\n\n");

        PendingRequestsResponse response = null;
        try {

            List<CalculationRequest> list = calculator.getAllPendingRequests();

            response = new PendingRequestsResponse(list);

        } catch (Exception e) {
            logger.error("Error attempting to getAllPendingRequests",e);
            response = new PendingRequestsResponse(e);

        return response;

Implement PendingRequestsResponse

As we begin to dive into this new method, we arrive at having to decide what to do with PendingRequestsResponse. Because the more-generic SuccessOrErrorResponse cannot return any data, such as the List that we need.

My first thought is that we also still need to report back a Success or Error, in addition to any data.

Sooo... do we sub-class from SuccessOrErrorResponse, or do we just make it a member of our new class.

I chose to sub-class. Here's what we now have for PendingRequestsResponse:

package com.eli.calc.shape.service.ws.types;

import java.util.List;

import com.eli.calc.shape.domain.CalculationRequest;

public class PendingRequestsResponse extends SuccessOrErrorResponse {

    private List<CalculationRequest> pendingRequests;

    private int numPending;

    public PendingRequestsResponse() {

    public PendingRequestsResponse(List<CalculationRequest> pendingRequests) {

        super(RespCode.SUCCESS,"Pending Requests");

        this.pendingRequests = pendingRequests;
        this.numPending = (null!=pendingRequests?pendingRequests.size():0);

    public PendingRequestsResponse(Exception e) {

        super("Pending Requests",e);


    public List<CalculationRequest> getPendingRequests() {
        return pendingRequests;

    public void setPendingRequests(List<CalculationRequest> pendingRequests) {
        this.pendingRequests = pendingRequests;

    public int getNumPending() {
        return numPending;

    public void setNumPending(int numPending) {
        this.numPending = numPending;


Another Observation

I like to help myself out as much as possible because I easily forget what code does what, when, where, and how. I try to program so it will warn me when something is wrong (because I did something wrong). It's the same idea as having a method, like say in a JUnit test, that throws some exception saying "Unimplemented Test."

So I wanted to make both the SuccessOrErrorResponse and the PendingRequestsResponse somewhat "smart" in that regards, to try to guide the programmer. More specifically, with which constructor to choose. I didn't really bother adding any smarts to the setters.

At the same time, I didn't want the creation of these response classes to fail, so I didn't use exceptions to inform the programmer.

It was easier, of course, to be smarter with the PendingRequestsResponse because the very name of the class is its sole purpose. Thus, a constructor accepting a List<>, seems to say "Hey, use me when you were successful and have a list." Likewise, the constructor accepting only an exception.   

Build. Deploy. Test — getAllPending Requests

Image title

Final Additions

Implement Remaining Operations

What remains to be done is to fully implement the remaining operations in a similar manner and test them. (We won't go into that, but the latest code will have the changes).

Add Corrective Shutdown

When our server shuts down at the moment, there are errors at the end of the log. We need to add what we added to our previous web application. You can check that out in "Correcting A Server Shutdown Process" (part 1 and 2).

Latest Code

You can get the latest for this web service project here.

And for the underlying Shape Calculator project here.

What's Next?

At first, I thought I would re-do this SOAP web-service, and change the POM's WSDL-generation plugin to "true" for generating the wrapper: <genWrapperbean>true</genWrapperbean>.

Frankly, it's uninteresting. (Ahem.)  In our story: Your boss said no; he can't justify you spending more time. The service works, you have other things on your plate.

It is much more interesting to re-do the service using a WSDL-first, top-down approach.

And we need to re-do the web application so it uses these web services. Later, securing the web services, and more. So, stay tuned!

Discover how the Force.com Web Services Connector (WSC) is a code-generation tool and runtime library for use with Force.com Web services, brought to you in partnership with Salesforce.

java,soap,web service,error handling

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}