Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

I wanted to go some way in the direction of a DSL for webservices but without using a big MDD tool. So I thought about how to have most advantages of a DSL with just Java and the normal Eclipse IDE. So I needed Java code that looks almost like a DSL and a tool to generate the webservice out of it. For the WSDl WSDL generation I used Apache CXF with JAXWS and JAXB annotations to describe the webservice. While this setup is quite standard I focused on keeping the syntax as simple as possible.

...

To describe a data object I use a java class with just attributes. The Namespace will come from the package name. To make JAXB understand this syntax only one annotation is necessary. Of course some more annotations are necessary if you want to use special fetauresfeatures.

Customer datatype

Code Block
java
java

package com.example.customerservice;

@XmlAccessorType( XmlAccessType.FIELD )
public class Customer {
    String name;
    String[] address;
    int numOrders;
    double revenue;
    BigDecimal test;
    Date birthDate;
    CustomerType type;
}

...

Shows how enumerations are handled:

Code Block
java
java

package com.example.customerservice;

public enum CustomerType {
    PRIVATE, BUSINESS
}

NoSuchCustomerException

 Defining Defining Exceptions is a little tricky as the default behaviour is to create Exception_Exception classes in the later generated Java code. So we have to use the @WebFault annotation to give the Bean for the data a name that is separate from the Exception name.

Code Block

package com.example.customerservice;

@WebFault(name="NoSuchCustomer")
@XmlAccessorType( XmlAccessType.FIELD )
public class NoSuchCustomerException extends RuntimeException {
    /**
      * We only define the fault details here. Additionally each fault has a message
      * that should not be defined separately
      */
    String customerName;
}

Service definition

Code Block
java
java

package com.example.customerservice;

@WebService
public interface CustomerService {
    public Customer[] getCustomersByName(@WebParam(name="name") String name) throws NoSuchCustomerException;
}

...

To generate the wsdl the maven plugin cxf-java2ws-plugin is used. See the pom.xml in the complete example for details.

Let´s take a look at the resulting WSDL

You can download the wsdl this example creates here.

Code Block
xml
xml

<xs:complexType name="customer">
    <xs:sequence>
        <xs:element minOccurs="0" name="name" type="xs:string"/>
        <xs:element maxOccurs="unbounded" minOccurs="0" name="address" nillable="true" type="xs:string"/>
        <xs:element name="numOrders" type="xs:int"/>
        <xs:element name="revenue" type="xs:double"/>
        <xs:element minOccurs="0" name="test" type="xs:decimal"/>
        <xs:element minOccurs="0" name="birthDate" type="xs:dateTime"/>
        <xs:element minOccurs="0" name="type" type="tns:customerType"/>
    </xs:sequence>
</xs:complexType>

...

The enumeration customerType is described as a simple type with a restriction:

Code Block
xml
xml

<xs:simpleType name="customerType">
    <xs:restriction base="xs:string">
        <xs:enumeration value="PRIVATE"/>
        <xs:enumeration value="BUSINESS"/>
    </xs:restriction>
</xs:simpleType>

...

The Exception we defined is generated as a complexType with the defined details and a message for the fault. It is important here that the Element and the Message have different names. We ensure this by using the @Webfault @WebFault Annotation above. Else the later Java Code generation will produce an ugly Exception name NoSuchCustomerException_Exception.

Code Block
xml
xml

<xs:element name="NoSuchCustomer" type="tns:NoSuchCustomer"/>
    <xs:complexType name="NoSuchCustomer">
        <xs:sequence>
            <xs:element name="customerName" nillable="true" type="xs:string"/>
        </xs:sequence>
 </xs:complexType>
 <wsdl:message name="NoSuchCustomerException">
    <wsdl:part name="NoSuchCustomerException" element="tns:NoSuchCustomer">
    </wsdl:part>
 </wsdl:message>

The wsdl defines a SOAP/HTTP binding by default but can also be used to build services based on JMS as I will show in my next post.

...

As you can see the generated WSDL looks quite clean and correctly expresses the service interface we wanted to describe. In most cases where you are not satisfied with what the conversion does you can correct the WSDL using JAX-WS or JAXB annotations. But I recommend to use them sparsly sparsely to keep the DSL easy to read.

...

You can download the complete example here.

References