Programming WebLogic Web Services
The following sections describe how to use non-built-in data types in WebLogic Web Services:
You can create a WebLogic Web Service that uses non-built-in data types as the Web Service parameters and return value. Non-built-in data types are defined as data types other than the supported built-in data types, such as int
and String
. For the full list of built-in types, see Supported Built-In Data Types.
WebLogic Server transparently handles the conversion of the built-in data types between their XML and Java representation. However, if your Web Service operation uses non-built-in data types, you must provide the following information so that WebLogic Server can perform the conversion:
web-services.xml
deployment descriptor file.WebLogic Server includes the servicegen
and autotype
Ant tasks which automatically generate the preceding components by introspecting the stateless session EJB or Java class back-end component for your Web Service. These Ant tasks can handle many non-built-in data types, so most programmers will not ever have to create the components manually.
Sometimes, however, you may need to create the non-built-in data type components manually. Your data type may be so complex that the Ant task cannot correctly generate the components. Or maybe you want more control over how the data is converted between its XML and Java representations rather than relying on the default conversion procedure used by WebLogic Server.
For a full list of the supported non-built-in data types, see Non-Built-In Data Types Supported by servicegen and autotype Ant Tasks.
For procedural instructions on using servicegen
and autotype
, see Assembling WebLogic Web Services Using Ant Tasks. For reference information, see Web Service Ant Tasks and Command-Line Utilities.
The following procedure describes how to create non-built-in data types and use the servicegen
Ant task to create a deployable Web Service:
servicegen
Ant task as described in Assembling WebLogic Web Services Using the servicegen Ant Task, with the following addition: when creating the build.xml
file that calls the servicegen
Ant task, be sure you specify the typeMappingFile
attribute of servicegen
, setting it equal to the name of the data type mapping file you created in the preceding step.BEA recommends that you create an exploded directory, rather than an EAR file, by specifying a value for the destEar
attribute of servicegen
that does not have an .ear
suffix. You can later package the exploded directory into an EAR file when you are ready to deploy the Web Service.
web-services.xml
file (which was generated by the servicegen
Ant task), adding the XML Schema representation of your data type that you created in the first step of this procedure. See Updating the web-services.xml File With XML Schema Information.clientgen
Ant task to generate a Java client, follow the procedure described in Running the clientgen Ant Task with the following additions to the build.xml
file that calls clientgen
:Web Services use SOAP as the message format to transmit data between the service and the client application that invokes the service. Because SOAP is an XML-based protocol, you must use XML Schema notation to describe the structure of non-built-in data types used by Web Service operations.
Warning: XML Schema is a powerful and complex data description language, and its use is not recommended for the faint of heart.
The following example shows the XML Schema that describes a non-built-in data type called EmployBean
:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:stns="java:examples.newTypes"
attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="java:examples.newTypes">
<xsd:complexType name="EmployeeBean">
<xsd:sequence>
<xsd:element name="name"
type="xsd:string"
nillable="true"
minOccurs="1"
maxOccurs="1">
</xsd:element>
<xsd:element name="id"
type="xsd:int"
minOccurs="1"
maxOccurs="1">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
The following XML shows an instance of the EmployeeBean
data type:
<EmployeeBean>
<name>Beverley Talbott</name>
<id>1234</id>
</EmployeeBean>
For detailed information about using XML Schema notation to describe your non-built-in data type, see the XML Schema specification.
You use the Java representation of the non-built-in data type in your EJB or Java class that implements the Web Service operation.
The following example shows one possible Java representation of the EmployeeBean
data type whose XML representation is described in the preceding section:
package examples.newTypes;
/**
* @author Copyright (c) 2002 by BEA Systems. All Rights Reserved.
*/
public final class EmployeeBean {
private String name = "John Doe";
private int id = -1;
public EmployeeBean() {
}
public EmployeeBean(String n, int i) {
name = n;
id = i;
}
public String getName() {
return name;
}
public void setName(String v) {
this.name = v;
}
public int getId() {
return id;
}
public void setId(int v) {
this.id = v;
}
public boolean equals(Object obj) {
if (obj instanceof EmployeeBean) {
EmployeeBean e = (EmployeeBean) obj;
return (e.name.equals(name) && (e.id == id));
}
return false;
}
}
The serialization class performs the actual conversion of your data between its XML and Java representations. You write only one class that contains methods to serialize and deserialize your data. In the class you use the WebLogic XML Streaming API to process the XML data.
The WebLogic XML Streaming API provides an easy and intuitive way to consume and generate XML documents. It enables a procedural, stream-based handling of XML documents.
For detailed information on using the WebLogic XML Streaming API, see Programming WebLogic XML.
For more information on the WebLogic Web Services and XML APIs used in this section, see the Javadocs.
The following example shows a class that uses the XML Streaming API to serialize and deserialize the data type described in Writing the XML Schema Data Type Representation and Writing the Java Data Type Representation; the procedure after the example lists the main steps to create such a class:
package examples.newTypes;
import weblogic.webservice.encoding.AbstractCodec;
import weblogic.xml.schema.binding.DeserializationContext;
import weblogic.xml.schema.binding.DeserializationException;
import weblogic.xml.schema.binding.Deserializer;
import weblogic.xml.schema.binding.SerializationContext;
import weblogic.xml.schema.binding.SerializationException;
import weblogic.xml.schema.binding.Serializer;
import weblogic.xml.stream.Attribute;
import weblogic.xml.stream.CharacterData;
import weblogic.xml.stream.ElementFactory;
import weblogic.xml.stream.EndElement;
import weblogic.xml.stream.StartElement;
import weblogic.xml.stream.XMLEvent;
import weblogic.xml.stream.XMLInputStream;
import weblogic.xml.stream.XMLName;
import weblogic.xml.stream.XMLOutputStream;
import weblogic.xml.stream.XMLStreamException;
public final class EmployeeBeanCodec extends
weblogic.webservice.encoding.AbstractCodec
{
public void serialize(Object obj,
XMLName name,
XMLOutputStream writer,
SerializationContext context)
throws SerializationException
{
EmployeeBean emp = (EmployeeBean) obj;
try {
//outer start element
writer.add(ElementFactory.createStartElement(name));
//employee name element
writer.add(ElementFactory.createStartElement("name"));
writer.add(ElementFactory.createCharacterData(emp.getName()));
writer.add(ElementFactory.createEndElement("name"));
//employee id element
writer.add(ElementFactory.createStartElement("id"));
String id_string = Integer.toString(emp.getId());
writer.add(ElementFactory.createCharacterData(id_string));
writer.add(ElementFactory.createEndElement("id"));
//outer end element
writer.add(ElementFactory.createEndElement(name));
} catch(XMLStreamException xse) {
throw new SerializationException("stream error", xse);
}
}
public Object deserialize(XMLName name,
XMLInputStream reader,
DeserializationContext context)
throws DeserializationException
{
// extract the desired information out of reader, consuming the
// entire element representing the type,
// construct your object, and return it.
EmployeeBean employee = new EmployeeBean();
try {
if (reader.skip(name, XMLEvent.START_ELEMENT)) {
StartElement top = (StartElement)reader.next();
//next start element should be the employee name
if (reader.skip(XMLEvent.START_ELEMENT)) {
StartElement emp_name = (StartElement)reader.next();
//assume that the next element is our name character data
CharacterData cdata = (CharacterData) reader.next();
employee.setName(cdata.getContent());
} else {
throw new DeserializationException("employee name not found");
}
//next start element should be the employee id
if (reader.skip(XMLEvent.START_ELEMENT)) {
StartElement emp_id = (StartElement)reader.next();
//assume that the next element is our id character data
CharacterData cdata = (CharacterData) reader.next();
employee.setId(Integer.parseInt(cdata.getContent()));
} else {
throw new DeserializationException("employee id not found");
}
//we must consume our entire element to leave the stream in a
//good state for any other deserializer
if (reader.skip(name, XMLEvent.END_ELEMENT)) {
XMLEvent end = reader.next();
} else {
throw new DeserializationException("expected end element not found");
}
} else {
throw new DeserializationException("expected start element not found");
}
} catch (XMLStreamException xse) {
throw new DeserializationException("stream error", xse);
}
return employee;
}
public Object deserialize(XMLName name,
Attribute att,
DeserializationContext context)
throws DeserializationException
{
//NOTE: not used in this example
// extract the desired information out of att, consuming the
// entire element representing the type,
// construct your object, and return it.
return new EmployeeBean();
}
}
To create the serialization class using the WebLogic XML Streaming API, follow these steps:
import weblogic.webservice.encoding.AbstractCodec;
import weblogic.xml.schema.binding.DeserializationContext;
import weblogic.xml.schema.binding.DeserializationException;
import weblogic.xml.schema.binding.Deserializer;
import weblogic.xml.schema.binding.SerializationContext;
import weblogic.xml.schema.binding.SerializationException;
import weblogic.xml.schema.binding.Serializer;
import weblogic.xml.stream.Attribute;
import weblogic.xml.stream.CharacterData;
import weblogic.xml.stream.ElementFactory;
import weblogic.xml.stream.EndElement;
import weblogic.xml.stream.StartElement;
import weblogic.xml.stream.XMLEvent;
import weblogic.xml.stream.XMLInputStream;
import weblogic.xml.stream.XMLName;
import weblogic.xml.stream.XMLOutputStream;
import weblogic.xml.stream.XMLStreamException;
weblogic.webservice.encoding.AbstractCodec
Because JAX-RPC does not define a standard mechanism for accessing XML, the AbstractCodec
class provides the glue to allow user written serialization classes to be used in the WebLogic Web Services runtime.
serialize()
method, used to convert the data from Java to XML. The signature of this method is as follows:void serialize(Object obj,
XMLName name,
XMLOutputStream writer,
SerializationContext context)
throws SerializationException;
Your Java object will be contained in the Object
parameter. Use the XML Streaming API to write the Java object to the XMLOutputStream
parameter. Use the XMLName
parameter as the name of the resulting element.
Warning: Do not update the SerializationContext
parameter; it is used internally by WebLogic Server.
deserialize()
method, used to convert the data from XML to Java. The signature of this method is as follows:Object deserialize(XMLName name,
XMLInputStream reader,
DeserializationContext context)
throws DeserializationException;
The XML that you want to deserialize is contained in the XMLInputStream
parameter. Use the WebLogic XML Streaming API to parse the XML and convert it into the returned Object
. The XMLName
parameter contains the expected name of the XML element.
Call the deserialize()
method recursively to build contained Object
s.
When you use the XML Streaming API to read the stream of events that make up your XML document, be sure you always finish reading an element all the way up to and including the EndElement
event, rather than finish reading once you have read all the actual data. If you finish before reaching an EndElement
event, the deserialization of subsequent elements might fail.
Warning: Do not update the DeserializationContext
parameter; it is used internally by WebLogic Server.
deserialize()
method:Object deserialize(XMLName name,
Attribute att,
DeserializationContext context)
throws DeserializationException;
The data type mapping file is a subset of the web-services.xml
deployment descriptor file. It centralizes some of the information about non-built-in data types, such as the name of the Java class that describes the Java representation of the data, the name of the serialization class that converts the data between XML and Java, and so on. The servicegen
Ant task uses this data type mapping file when creating the web-services.xml
deployment descriptor for the WebLogic Web Service that uses the non-built-in data type.
To create the data type mapping file, follow these steps:
<type-mapping>
...
</type-mapping>
<type-mapping-entry>
child element of the <type-mapping>
element. Include the following attributes:xmlns:
name
—Declares a namespace.class-name
—Specifies the fully qualified name of the Java class.type
—Specifies the name of XML Schema type for which this data type mapping entry applies. serializer
—The fully qualified name of the serialization class that converts the data from its Java to its XML representation. For details on creating this class, see Writing the Serialization Class.deserializer
—The fully qualified name of the serialization class that converts the data from its XML to its Java representation. For details on creating this class, see Writing the Serialization Class.The following example shows a possible data type mapping file with one <type-mapping>
entry for the XML Schema data type shown in Updating the web-services.xml File With XML Schema Information:
<type-mapping>
<type-mapping-entry
xmlns:p2="java:examples.newTypes"
class-name="examples.newTypes.EmployeeBean"
type="p2:EmployeeBean"
serializer="examples.newTypes.EmployeeBeanCodec">
deserializer="examples.newTypes.EmployeeBeanCodec"
</type-mapping-entry>
</type-mapping>
The web-services.xml
file generated by servicegen
will not have the XML Schema information for the non-built-in data type for which you have created your own custom serialization class. For this reason, you must manually add the XML Schema information to the deployment descriptor, as described in the following steps:
web-services.xml
file generated by the servicegen
Ant task, find the <types>
child element of the <web-service>
element:<types>
...
</types>
<types>
element, as shown in the following example:<types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:stns="java:examples.newTypes"
attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="java:examples.newTypes">
<xsd:complexType name="EmployeeBean">
<xsd:sequence>
<xsd:element name="name"
type="xsd:string"
nillable="true"
minOccurs="1"
maxOccurs="1">
</xsd:element>
<xsd:element name="id"
type="xsd:int"
minOccurs="1"
maxOccurs="1">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</types>