O'Reilly logo

Java Web Services: Up and Running by Martin Kalin

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

An Example with Richer Data Types

The operations in the TimeServer service take no arguments and return simple types, a string and an integer. This section offers a richer example whose details are clarified in the next chapter.

The Teams web service in Example 1-11 differs from the TimeServer service in several important ways.

Example 1-11. The Teams document-style web service

package ch01.team;

import java.util.List;
import javax.jws.WebService;
import javax.jws.WebMethod;

public class Teams {
    private TeamsUtility utils;

    public Teams() { 
       utils = new TeamsUtility(); 

    public Team getTeam(String name) { return utils.getTeam(name); }

    public List<Team> getTeams() { return utils.getTeams(); }

For one, the Teams service is implemented as a single Java class rather than as a separate SEI and SIB. This is done simply to illustrate the possibility. A more important difference is in the return types of the two Teams operations. The operation getTeam is parameterized and returns an object of the programmer-defined type Team, which is a list of Player instances, another programmer-defined type. The operation getTeams returns a List<Team>, that is, a Java Collection.

The utility class TeamsUtility generates the data. In a production environment, this utility might retrieve a team or list of teams from a database. To keep this example simple, the utility instead creates the teams and their players on the fly. Here is part of the utility:

package ch01.team;

import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

public class TeamsUtility {
    private Map<String, Team> team_map;

    public TeamsUtility() {
       team_map = new HashMap<String, Team>();

    public Team getTeam(String name) { return team_map.get(name); }
    public List<Team> getTeams() {
       List<Team> list = new ArrayList<Team>();
       Set<String> keys = team_map.keySet();
       for (String key : keys)
       return list;

    public void make_test_teams() {
       List<Team> teams = new ArrayList<Team>();
       Player chico = new Player("Leonard Marx", "Chico");
       Player groucho = new Player("Julius Marx", "Groucho");
       Player harpo = new Player("Adolph Marx", "Harpo");
       List<Player> mb = new ArrayList<Player>();
       mb.add(chico); mb.add(groucho); mb.add(harpo);
       Team marx_brothers = new Team("Marx Brothers", mb);


    private void store_teams(List<Team> teams) {
       for (Team team : teams)
          team_map.put(team.getName(), team);

Publishing the Service and Writing a Client

Recall that the SEI for the TimeServer service contains the annotation:

@SOAPBinding(style = Style.RPC) 

This annotation requires that the service use only very simple types such as string and integer. By contrast, the Teams service uses richer data types, which means that Style.DOCUMENT, the default, should replace Style.RPC. The document style does require more setup, which is given below but not explained until the next chapter. Here, then, are the steps required to get the web service deployed and a sample client written quickly:

  1. The source files are compiled in the usual way. From the working directory, which has ch01 as a subdirectory, the command is:

    % javac ch01/team/*.java

    In addition to the @WebService-annotated Teams class, the ch01/team directory contains the Team, Player, TeamsUtility, and TeamsPublisher classes shown below all together:

    package ch01.team;
    public class Player {
        private String name;
        private String nickname;
        public Player() { }
        public Player(String name, String nickname) {
        public void setName(String name) { this.name = name; }
        public String getName() { return name; }
        public void setNickname(String nickname) { this.nickname = nickname; }
        public String getNickname() { return nickname; }
    // end of Player.java
    package ch01.team;
    import java.util.List;
    public class Team {
        private List<Player> players;
        private String name;
        public Team() { }
        public Team(String name, List<Player> players) { 
        public void setName(String name) { this.name = name; }
        public String getName() { return name; }
        public void setPlayers(List<Player> players) { this.players = players; }
        public List<Player> getPlayers() { return players; }
        public void setRosterCount(int n) { } // no-op but needed for property
    	public int getRosterCount() { return (players == null) ? 0 : players.size(); }
    // end of Team.java
    package ch01.team;
    import javax.xml.ws.Endpoint;
    class TeamsPublisher {
        public static void main(String[ ] args) {
           int port = 8888;
           String url = "http://localhost:" + port + "/teams";
           System.out.println("Publishing Teams on port " + port);
           Endpoint.publish(url, new Teams());
  2. In the working directory, invoke the wsgen utility, which comes with core Java 6:

    % wsgen -cp . ch01.team.Teams

    This utility generates various artifacts; that is, Java types needed by the method Endpoint.publish to generate the service’s WSDL. Chapter 2 looks closely at these artifacts and how they contribute to the WSDL.

  3. Execute the TeamsPublisher application.

  4. In the working directory, invoke the wsimport utility, which likewise comes with core Java 6:

    % wsimport -p teamsC -keep http://localhost:8888/teams?wsdl

    This utility generates various classes in the subdirectory teamsC (the -p flag stands for package). These classes make it easier to write a client against the service.

Step 4 expedites the coding of a client, which is shown here:

import teamsC.TeamsService;
import teamsC.Teams;
import teamsC.Team;
import teamsC.Player;
import java.util.List;
class TeamClient {
    public static void main(String[ ] args) {
        TeamsService service = new TeamsService();
        Teams port = service.getTeamsPort();
        List<Team> teams = port.getTeams();
        for (Team team : teams) {
            System.out.println("Team name: " + team.getName() +
                               " (roster count: " + team.getRosterCount() + ")");
            for (Player player : team.getPlayers())
                System.out.println("  Player: " + player.getNickname());

When the client executes, the output is:

Team name: Abbott and Costello (roster count: 2)
  Player: Bud
  Player: Lou
Team name: Marx Brothers (roster count: 3)
  Player: Chico
  Player: Groucho
  Player: Harpo
Team name: Burns and Allen (roster count: 2)
  Player: George
  Player: Gracie

This example hints at what is possible in a commercial-grade, SOAP-based web service. Programmer-defined types such as Player and Team, along with arbitrary collections of these, can be arguments passed to or values returned from a web service so long as certain guidelines are followed. One guideline comes into play in this example. For the Team and the Player classes, the JavaBean properties are of types String or int; and a List, like any Java Collection, has a toArray method. In the end, a List<Team> reduces to arrays of simple types; in this case String instances or int values. The next chapter covers the details, in particular how the wsgen and the wsimport utilities facilitate the development of JWS services and clients.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required