Social Media

Apache CXF – Contract Last Example

This post looks at the JAX-WS “contract last”/”code first” implementation in samples\java_first_jaxws. This approach means that you create the Java code first, then create or generate the WSDL from that

Web Service Code

The web service uses JAX-WS annotations to annotate the interface and implementation. This generates the wsdl at runtime

Interface

[sourcecode lang=”java”] @WebService
public interface HelloWorld {

String sayHi(String text);

String sayHiToUser(User user);

@XmlJavaTypeAdapter(IntegerUserMapAdapter.class)
Map<Integer, User> getUsers();
}
[/sourcecode]

Implementation –

[sourcecode lang=”java”] @WebService(endpointInterface = "demo.hw.server.HelloWorld", serviceName = "HelloWorld")
public class HelloWorldImpl implements HelloWorld {
Map<Integer, User> users = new LinkedHashMap<Integer, User>();

public String sayHi(String text) {
System.out.println("sayHi called");
return "Hello " + text;
}

public String sayHiToUser(User user) {
System.out.println("sayHiToUser called");
users.put(users.size() + 1, user);
return "Hello " + user.getName();
}

public Map<Integer, User> getUsers() {
System.out.println("getUsers called");
return users;
}

}
[/sourcecode]

@WebService annotation denotes the class as a JAX-WS web service class. The parameters to this method are –

  • endpointInterface – Complete name of web service endpoint
  • name – Name of Web Service – maps to wsdl:portType
  • portName – Maps to wsdl:port
  • serviceName – Service endpont interface defined in Web Service contract
  • targetNamespace – Used for wsdl:portType and/or wsdl:service
  • wsdlLocation – Location of wsdl

The sayHi method takes a String, which is supported by JAX-WS, but we have to use XmlAdapter’s to support the User and Map objects in the other two methods

UserXmlAdapter

The User interface associates itself to the UserAdapter through the XmlJavaTypeAdapter annotation –

[sourcecode lang=”java”] @XmlJavaTypeAdapter(UserAdapter.class)
public interface User {
String getName();
}
[/sourcecode]

The User interface has its implementation under UserImpl, which links itself to the User type through the XmlType annotation –

[sourcecode lang=”java”] @XmlType(name = "User")
public class UserImpl implements User {
//…
}
[/sourcecode]

The mapping between the interface and implementation is then done through the XmlAdapter –

[sourcecode lang=”java”] public class UserAdapter extends XmlAdapter<UserImpl, User> {
public UserImpl marshal(User v) throws Exception {
if (v instanceof UserImpl) {
return (UserImpl)v;
}
return new UserImpl(v.getName());
}

public User unmarshal(UserImpl v) throws Exception {
return v;
}
}
[/sourcecode]

Map XmlAdapter

The getUsers method is interesting because it shows how XmlAdapter can be used as a workaround for JAXB not supporting Maps –

[sourcecode lang=”java”] public class IntegerUserMapAdapter extends XmlAdapter<IntegerUserMap, Map<Integer, User>> {
public IntegerUserMap marshal(Map<Integer, User> v) throws Exception {
IntegerUserMap map = new IntegerUserMap();
for (Map.Entry<Integer, User> e : v.entrySet()) {
IntegerUserMap.IntegerUserEntry iue = new IntegerUserMap.IntegerUserEntry();
iue.setUser(e.getValue());
iue.setId(e.getKey());
map.getEntries().add(iue);
}
return map;
}

public Map<Integer, User> unmarshal(IntegerUserMap v) throws Exception {
Map<Integer, User> map = new LinkedHashMap<Integer, User>();
for (IntegerUserMap.IntegerUserEntry e : v.getEntries()) {
map.put(e.getId(), e.getUser());
}
return map;
}
}
[/sourcecode]

CXFServlet and Spring Integration

The connectivity of the CXFServlet was covered in the previous post, and this section looks at how the cxf service is configured in cxf-servlet.xml –

[sourcecode lang=”xml”] <jaxws:server id="jaxwsService" serviceClass="demo.hw.server.HelloWorld" address="/hello_world">
<jaxws:serviceBean>
<bean class="demo.hw.server.HelloWorldImpl" />
</jaxws:serviceBean>
</jaxws:server>
[/sourcecode]

This connects in 3 key attributes –

  • serviceClass – HelloWorld interface
  • address – /hello_world – serving Url
  • serviceBean – HelloWorldImpl – implementation class

Running the example

The simplest way to run the example is through –

mvn clean install (builds the demo and creates a WAR file for optional Tomcat deployment)
mvn -Pserver (from one command line window — only if using a non-WAR standalone service)
mvn -Pclient (from a second command line window)

Or run in tomcat by dropping the war in the deploy directory, and accessing on –

http://localhost:8080/java_first_jaxws/services/hello_world?wsdl

This can be called from SOAPUI –

[sourcecode lang=”xml”] <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://server.hw.demo/">
<soapenv:Header/>
<soapenv:Body>
<ser:sayHiToUser>
<!–Optional:–>
<arg0>
<!–Optional:–>
<name>Martin</name>
</arg0>
</ser:sayHiToUser>
</soapenv:Body>
</soapenv:Envelope>
[/sourcecode]

You will get the output –

[sourcecode lang=”xml”] <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:sayHiToUserResponse xmlns:ns2="http://server.hw.demo/">
<return>Hello Martin</return>
</ns2:sayHiToUserResponse>
</soap:Body>
</soap:Envelope>
[/sourcecode]

About the Author Martin Farrell

My name is Martin Farrell. I have almost 20 years Java experience. I specialize inthe Spring Framework and JEE. I’ve consulted to a range of businesses, and have provide Java and Spring mentoring and training. You can learn more at About or on my consultancy website Glendevon Software

follow me on:

Leave a Comment: