Working with Complex Data Types, Part 4

This is the last in a series of book excerpts from Java and SOAP on working with complex data types. In this excerpt, learn about returning custom types, using a stock market example.

Returning Custom Types

It's equally useful (and equally common) to return custom types from service method calls. We can enhance our trading service by offering a method that takes a single stock symbol as a parameter and returns its high and low trading prices for the day. The classes HighLow_ServerSide and HighLow_ClientSide represent the high/low prices on the server and client, respectively.

The server-side class includes a parameterized constructor as a convenience for creating the return value; the client-side class includes a toString( ) method to make it easy for our client application to display the contents of the object after it's returned from the server. Let's add a new method to the BasicTradingService class called getHighLow( ). That method takes a single string parameter for the stock symbol and returns an instance of HighLow_ServerSide. Here's the class with its new method, with the unchanged code omitted:

In order to make this new method available in Apache SOAP, we'll need to redeploy the service using a modified deployment descriptor. We need to add getHighLow to the list of methods, and add an entry in the mappings section for the high/low object. The second mapping entry defines the HighLowa custom type, namespace-qualified using the service name urn:BasicTradingService. Here is the modified deployment descriptor:

Now we can create a client application that invokes the getHighLow service method and receives a high/low object in return. For the Apache SOAP client, we'll use the HighLow_ClientSide class to represent the return value. Here's the new application:

smr.MapTypes( ) maps the HighLow custom type to the HighLow_ClientSide Java class. Just as before, we can use Apache's BeanSerializer to convert between XML and Java, since our class conforms to the JavaBeans property accessor pattern. We set up a single String parameter called stock to pass to the getHighLow method (although we don't actually make use of it in the server code). After the method is invoked, we cast the return value of resp.getReturnValue( ) to an instance of HighLow_ClientSide. Then we pass the return parameter variable, ret, to the System.out.println( ) method for display. This is all we need, since we implemented the toString( ) method in our HighLow_ClientSide class. When you run this example, you'll get the following output:

High: 110.375 Low: 109.5

Here's the SOAP envelope returned from this method invocation. The return element is typed as a HighLow that is namespace-qualified by the urnBasicTradingService namespace. The properties, which are child elements of the return element, are typed as floats and appear along with their corresponding values.

To return a HighLow using GLUE, we'll take the same steps we did for passing custom types. Again we'll separate our client-side work into another package, javasoap.book.ch5.client. Just restart the application of BasicTradingApp to get the service deployed. Now run the wsdl2java utility from the directory corresponding to the javasoap.book.ch5.client package:

The following code is the new IBasicTradingService interface generated by wsdl2java. The getHighLow( ) method returns an instance of HighLow_ServerSide; remember that this class is the new one generated by GLUE as part of the javasoap.book.ch5.client package, not the one being used by our server class, BasicTradingApp.

The next class, HighLow_ServerSide, is simply a Java data structure reflecting the data fields that will be mapped to the HighLow custom type. I added the toString( ) method by hand to make it simpler to display the results.

Now let's create a client application using GLUE that invokes the getHighLow service method and displays the contents of the resulting return value. There's not much to this, really; we simply read the map file, perform the bind, and then call the getHighLow method on the bound interface. The resulting instance of javasoap.book.ch5.client.HighLow_ServerSide is passed to System.out.println( ) for display. Just as in the Apache SOAP example, the toString( ) method of the class handles the creation of the display string.

Here's the SOAP envelope returned from the server. You should be able to follow this by now. GLUE uses a reference to a separately serialized instance of the custom type, just as it did when returning an array.

In this chapter, we've taken an in-depth look at the use of arrays and custom data types, and discussed how these structures are supported by Apache SOAP and GLUE. There are other useful types that you may find support for in these, or other, SOAP implementations. These types might include Java Vector and Hashtable classes, Java collections, and a variety of other commonly used Java classes.

We've seen that Apache SOAP and GLUE approach complex types in different ways, and both do a good job of supporting them. However, there may be times when you need to work with a custom type that either can't, or shouldn't, be serialized in the way provided by your SOAP implementation. This situation may arise because there simply is no support for a particular type of data, as is the case with multidimensional or sparse arrays, or perhaps for some other reason related to your application. We'll tackle this issue in the next chapter.

Robert Englander
is Principal Engineer and President of MindStream Software, Inc. (www.mindstrm.com). He provides consulting services in software architecture, design, and development, as well as developing frameworks for use on client projects.