Web services migration scenarios: JAX-RPC to JAX-WS and JAXB


 

+

Search Tips   |   Advanced Search

 

The following information includes issues that we might have while migrating from JAX-RPC to JAX-WS and JAXB.

Some methods used with JAX-RPC can be used with little or no change in a JAX-WS service.

JAX-RPC is still supported in WAS v7. We might want to migrate to take advantage of JAX-WS 2.x and JAXB 2.x enhancements such as SOAP 1.2 and SOAP MTOM.

 

Comparison of JAX-RPC to JAX-WS and JAXB models

If we are looking for additional information that describes the changes between the JAX-RPC and JAX-WS and JAXB models, IBMdeveloperWorks has published several Web services hints and tips topics.

 

Development models

The high level combined development models for JAX-RPC and JAX-WS and JAXB are shown the following image:

At a high level, the models are very similar. The only difference is that the JAX-RPC model produces both portable and non-portable artifacts; the JAX-WS and JAXB model does not produce non-portable artifacts. The image displays the following components:

 

The Development and runtime environments

A specialized development environment simplifies Web services migration by automating many of the tasks. For development of WebSphere-based applications, including Web services, we can use the assembly tools. We can read more about the use of the assembly tools in the assembly tool information center.

The following sample code in this topic was tested in the following runtime environment:

 

Examples

The following examples show some of the code changes that we might need to migrate the JAX-RPC Web services to JAX-WS and JAXB Web services. In particular, there is an emphasis on the changes in the implementation code that write, from both the client and the server side. If no new function is to be introduced, the changes required to move from JAX-RPC to JAX-WS and JAXB might be few.

 

Sample Web service

The first example is a sample JAX-RPC-based Web Service created from a WSDL file (top-down development); the same WSDL file is used to generate the JAX-WS and JAXB-based service. The WSDL file describes the Web service, SampleService, with these operations described by the following image: As shown in the image, the five operations offered are:

Also assume that Person is defined by the following schema fragment in the WSDL file

<complexType name="Person">
  <sequence>
    <element name="name" type="xsd:string"/>
    <element name="age" type="xsd:int"/>
    <element name="location" type="impl:Address/>
  </sequence>
</complexType>

Address is defined by:

<complexType name="Address">
  <sequence>
    <element name="street" type="xsd:string"/>
    <element name="city" type="xsd:string"/>
    <element name ="state" type="xsd:string"/>
    <element name="zip" type="xsd:int"/>
  </sequence>
</complexType>

The following image also shows that the operation, ckAvailability(xsd:int), which produces an invalidDateFault exception.

 

Service operations

Review the service code created by the tooling.

The following information includes examining what is created for a JAX-RPC runtime and also for a JAX-WS and JAXB runtime.

 

JAX-RPC

For JAX-RPC, the tooling accepts the WSDL file as input, and, amongst other files, generates the SampleService.java and SampleServiceImpl.java interfaces. The SampleService.java interface defines an interface and the generated code can be review in the following code block. The SampleServiceSoapBindingImpl.java interface provides the skeleton of an implementation, and you typically modify to add the own logic. JAX-RPC version of SampleService.java:


/**  
* SampleService.java  
*  
* This file was auto-generated from WSDL  
* by the IBM Web services WSDL2Java emitter.  
* cf20633.22 v82906122346  
*/  
 package simple;
   public interface SampleService extends java.rmi.Remote 
{   
  public java.lang.Integer calcShippingCost 
  (
    java.lang.Integer shippingWeight,
    java.lang.Integer shippingZone
  ) 
  throws java.rmi.RemoteException;    

  public java.lang.String getAccountNumber 
  (
    java.lang.String accountName
  )      
  throws java.rmi.RemoteException;    

  public java.lang.String[] ckAvailability
  (
    int[] itemNumbers
  )       
  throws java.rmi.RemoteException, simple.InvalidDateFault;    

  public java.util.Calendar calculateShippingDate
  (
    java.util.Calendar requestedDate
  )                      
  throws java.rmi.RemoteException;    

  public simple.Person findSalesRep
  (
    java.lang.String saleRepName
  )       
  throws java.rmi.RemoteException; }   

 

JAX-WS and JAXB

For JAX-WS and JAXB, the tooling accepts the WSDL file as input, and as in the case of JAX-RPC, generates interfaces:

As with JAX-RPC, the SampleService.java interface also defines an interface as shown in the following code block. The SampleServiceImpl.java interface provides the skeleton of an implementation, and you typically modify to add our own logic.

The code has been annotated by the tooling. JAX-WS and JAXB version of the SampleService.java interface:

 package simple;  
 import java.util.List;
  import javax.jws.WebMethod;
  import javax.jws.WebParam;
  import javax.jws.WebResult;
  import javax.jws.WebService;
  import javax.xml.datatype.XMLGregorianCalendar;
  import javax.xml.ws.RequestWrapper;
  import javax.xml.ws.ResponseWrapper;   

/**  
*  This class was generated by the JAX-WS SI.  
*  JAX-WS RI IBM 2.0_03-06/12/2007 07:44 PM(Raja)-fcs  
*  Generated source version: 2.0  
*   
*/ 


@WebService (
    name = "SampleService", 
    targetNamespace = "http://simple"
) 
 public interface SampleService 
{       

    /**      
    *       
    * @param shippingWeight      
    * @param shippingZone      
    * @return      
    * returns java.lang.Integer      
    */     
  
    @WebMethod     

    @WebResult
    (
        name = "shippingCost", 
        targetNamespace = ""
    )     

    @RequestWrapper
    (
        localName = "calcShippingCost",
        targetNamespace = "http://simple",
        className = "simple.CalcShippingCost"
    )     

    @ResponseWrapper
    (
        localName = "calcShippingCostResponse",
        targetNamespace = "http://simple",
        className = "simple.CalcShippingCostResponse"
    )     

    public Integer calcShippingCost
    (
        @WebParam(name = "shippingWeight", targetNamespace = "")         
        Integer shippingWeight,         
        @WebParam(name = "shippingZone", targetNamespace = "")         
        Integer shippingZone
    );      
  
    /**      
    *       
    * @param accountName      
    * @return      
    *     returns java.lang.String      
    */     
  
    @WebMethod     
  
    @WebResult
    (
        name = "accountNumber", 
        targetNamespace = ""
    )     
  
    @RequestWrapper
    (
        localName = "getAccountNumber",
        targetNamespace = "http://simple",
        className = "simple.GetAccountNumber"
    )     

    @ResponseWrapper
    (
        localName = "getAccountNumberResponse",
        targetNamespace = "http://simple",
        className = "simple.GetAccountNumberResponse"
    )     
  
    public String getAccountNumber
    (         
        @WebParam
        (
            name = "accountName", 
            targetNamespace = ""
        )         

        String accountName);      
  
    /**      
    *       
    * @param requestedDate      
    * @return      
    *     returns javax.xml.datatype.XMLGregorianCalendar      
    */     
  
    @WebMethod     
  
    @WebResult
    (
        name = "actualDate", 
        targetNamespace = ""
    )     
  
    @RequestWrapper
    (
        localName = "calculateShippingDate",
        targetNamespace = "http://simple",
        className = "simple.CalculateShippingDate"
    )     
  
    @ResponseWrapper
    (
        localName = "calculateShippingDateResponse",
        targetNamespace = "http://simple", 
        className = "simple.CalculateShippingDateResponse"
    )     
  
    public XMLGregorianCalendar calculateShippingDate
    (         
      @WebParam
      (
          name = "requestedDate",
          targetNamespace = ""
      )         
      XMLGregorianCalendar requestedDate);      
  
    /**      
    *       
    * @param itemNumbers      
    * @return      
    *     returns java.util.List<java.lang.String>      
    * @throws InvalidDateFault_Exception      
    */     

    @WebMethod     

    @WebResult
    (
        name = "itemAvailability",
        targetNamespace = ""
    )     

    @RequestWrapper
    (
        localName = "ckAvailability",
        targetNamespace = "http://simple",
        className = "simple.CkAvailability"
    )     

    @ResponseWrapper
    (
        localName = "ckAvailabilityResponse",
        targetNamespace = "http://simple", 
       className = "simple.CkAvailabilityResponse"
    )     
    

    public List<String> ckAvailability
    (         

      @WebParam
      (
          name = "itemNumbers",
          targetNamespace = ""
      )         

      List<Integer> itemNumbers
    )         

    throws InvalidDateFault_Exception;      


    /**      
    *       
    * @param saleRepName      
    * @return      
    *     return simple.Person      
    */     

    @WebMethod     

    @WebResult
    (
        name = "salesRepInfo", 
        targetNamespace = ""
    )     

    @RequestWrapper
    (
        localName = "findSalesRep",
        targetNamespace = "http://simple",
        className = "simple.FindSalesRep"
    )     

    @ResponseWrapper
    (
        localName = "findSalesRepResponse", 
        targetNamespace = "http://simple", 
        className = "simple.FindSalesRepResponse"
    )     

    public Person findSalesRep
    (         
        @WebParam
        (
            name = "saleRepName",
            targetNamespace = ""
        )         

        String saleRepName
    );  
  
}   

 

Comparing the code examples

At first glance, it might seem that there is little similarity between the interfaces. If we disregard the additional information added by the annotations for JAX-WS and JAXB, the code samples are similar. For example, the calcShippingCost method in the JAX-WS and JAXB version the following lines of code exist:


@WebMethod     

@WebResult (
    name = "shippingCost", 
    targetNamespace = ""
)     

@RequestWrapper (
    localName = "calcShippingCost",
    targetNamespace = "http://simple", 
    className = "simple.CalcShippingCost"
)     

@ResponseWrapper (
    localName = "calcShippingCostResponse",
    targetNamespace = "http://simple", 
    className = "simple.CalcShippingCostResponse"
)     
 public Integer calcShippingCost (         
    @WebParam
    (
        name = "shippingWeight", 
        targetNamespace = ""
    )         
    Integer shippingWeight,         

    @WebParam
    (
        name = "shippingZone", 
        targetNamespace = ""
    )         

    Integer shippingZone
);

But, if we discard the annotations, the following lines of code are:

 public Integer calcShippingCost (
    Integer shippingWeight,         
    Integer shippingZone
);

These lines are almost identical to what was generated for JAX-RPC. The only difference is that the JAX-RPC code can produce the java.rmi.RemoteException error as follows:

 public java.lang.Integer calcShippingCost (
    java.lang.Integer shippingWeight,       
    java.lang.Integer shippingZone
)  throws java.rmi.RemoteException;

Following this logic, three of the methods have essentially the same signatures:

 public Integer calcShippingCost (
    Integer shippingWeight,
     Integer shippingZone
)
 public String getAccountNumber (
    String accountName
)
 public Person findSalesRep (
    String saleRepName
) 

This means that migrating from JAX-RPC to JAX-WS does not directly affect these methods and the original implementation code that is successfully running in the JAX-RPC based environment can probably be used without modification for these methods.

However two of the methods do have different signatures:

For JAX-RPC:

 public java.util.Calendar calculateShippingDate (       
  java.util.Calendar requestedDate
)  
 public java.lang.String[] ckAvailability (
    int[] itemNumbers
)            throws java.rmi.RemoteException, simple.InvalidDateFault

JAX-WS and JAXB:

 public XMLGregorianCalendar calculateShippingDate (       
    XMLGregorianCalendar requestedDate
)    
 public List<String> ckAvailability (
    List<Integer> itemNumbers
)  throws InvalidDateFault_Exception 

You might find it easier to compare the skeleton implementation files since the annotations are not present in SampleServiceImpl.java.:

The differences in signatures are due to the following reasons:

 

Migrate the code

Now that the differences between code have been explained, review the original code for the methods that need changing and how to change this code so that it works in a JAX-WS and JAXB environment.

Assume that the original (JAX-RPC) implementation code is similar to following:

 public java.util.Calendar calculateShippingDate (
    java.util.Calendar requestedDate
)  throws java.rmi.RemoteException 
{


// Set the date to the date that was sent to us and add 7 days. requestedDate.add (
    java.util.Calendar.DAY_OF_MONTH, 7
);


// . . .
 return requestedDate;
}

We can write the new code to directly use the new types as in the following examples:

 public XMLGregorianCalendar calculateShippingDate (
    XMLGregorianCalendar requestedDate
) 
{
    try 
    {
        
// Create a data type factory.
        DatatypeFactory df = DatatypeFactory.newInstance();

        
// Set the date to the date that was sent to us and add 7 days.
        Duration duration = df.newDuration("P7D");
        requestedDate.add(duration);

    } 

    catch (DatatypeConfigurationException e) 
    {
        
// TODO Auto-generated catch block
        e.printStackTrace();
    }

    
// . . .

    return requestedDate;
}

 

Migrate the code for the ckAvailability method

When migrating the code for the ckAvailability method, changes were required because of the way that arrays and exceptions are mapped from XML is different between JAX-RPC and JAX-WS. Assume that the original JAX-RPC Web service code is similar to the following example:

 public java.lang.String[] ckAvailability(int[] itemNumbers)
{
    
    String[] myString = new String[itemNumbers.length];
    for (int j = 0; j < myString.length; j++) 
    {
        . . .
        if ( ... )

         throw new simple.InvalidDateFault("InvalidDateFault"

         . . .
         if ( . . .) 
             myString[j] = "available:  " + jitemNumbers[j] ;
         else
             myString[j] = "not available:  " + jitemNumbers[j];
 
    }
    return myString;
}

The previous code accepts an int[] as input and returns a String[].

For the JAX-WS and JAXB version, these are List<Integer> and List<String> elements respectively. Processing for these arrays, and discarding the Exception code, the JAX-RPC code is similar to the following:

 public java.lang.String[] ckAvailability(int[] itemNumbers)
{
    
    String[] myString = new String[itemNumbers.length];
    for (int j = 0; j < jitemNumbers.length; j++) 
    {
        . . .
        if ( . . .) 
            myString[j] = "available:  " + itemNumbers.get(j);
        else
            myString[j] = "not available:  " + itemNumbers.get(j); 
    }
    return myString;
}

The following JAX-WS and JAXB equivalent code exists using Lists instead of arrays:

 List <String> ckAvailability(List <Integer> itemNumbers)
{
    
    ArrayList<String> retList = new ArrayList<String>();
    for (int count = 0; count < itemNumbers.size(); count++) 
    {
        . . .
        if ( . . .) 
            retList.add("available:  " + itemNumbers.get(j));
        else
            retList.add("not available:  " + itemNumbers.get(j)); 
    }
    return retList;
}

The differences in the mappings of exceptions from XML to Java forces the JAX-WS code to use. InvalidDateFault_Exception instead of InvalidDateFault.

This means that replace throw new simple.InvalidDateFault("InvalidDateFault" with some other code. Therefore, the following line is used for the new code:

 throw new InvalidDateFault_Exception( "test InvalidDateFault_Exception", new InvalidDateFault());  

The final JAX-WS and JAXB implementation of the method might be similar to the following code:

 List <String> ckAvailability(List <Integer> itemNumbers)
{
    
    ArrayList<String> retList = new ArrayList<String>();

    for (int count = 0; count < itemNumbers.size(); count++) 
    {
 
        if ( . . . ) 
        {
            throw new InvalidDateFault_Exception
            (
                "test InvalidDateFault_Exception",    
                new InvalidDateFault());
        }

        . . .
   
        if ( . . .) 
           retList.add("available:  " + itemNumbers.get(count));
        else
           retList.add("not available:  " + itemNumbers.get(count)); 

        return retList;
}

There are multiple ways that we might choose to migrate the code.

With practice and an effective development environment, migrating from JAX-RPC to JAX-WS can be straightforward.



 

Related tasks


Task overview: Implement Web services applications