In a previous post we learned how to create a SOAP web service with the XFire plugin in Grails. The generated WSDL defined that the properties of our objects could be null by default and the minimum occurence is 0. And because of this we must work with JAXBElement
objects to get the real object values. In this post we change the property mapping so the properties cannot be null and have a minimum occurence of 1. And then we can change our client code and deal with the object values directly instead of via a JAXBElement
object.
We can change the default mapping of our objects that is generated by the XFire plugin. We must add an Aegis mapping XML file to our classpath and in this file we can define the custom mapping we want to apply. The name of the file is <ClassName>.aegis.xml
and must be in the same package as the class we are writing the custom mapping for. If we add the XML files to the src/java
directory of our Grails application then the files will be copied to the classpath automatically.
After we have created the XML mapping files we must add an extra runtime dependency. So we change the grails-app/conf/BuildConfig.groovy
file and add a dependency to Jaxen, because this is needed to make the custom mapping work.
<!-- File: src/java/com/mrhaki/groovyws/server/Author.aegis.xml --> <mappings> <mapping> <property name="name" minOccurs="1" nillable="false"/> <property name="blogItems" minOccurs="1" componentType="com.mrhaki.groovyws.server.BlogItem"/> </mapping> </mappings>
<!-- File: src/java/com/mrhaki/groovyws/server/BlogItem.aegis.xml --> <mappings> <mapping> <property name="title" minOccurs="1" nillable="false"/> <property name="text" minOccurs="1" nillable="false"/> </mapping> </mappings>
<!-- File: src/java/com/mrhaki/groovyws/server/SearchRequest.aegis.xml --> <mappings> <mapping> <property name="authorName" minOccurs="1" nillable="false"/> </mapping> </mappings>
// File: grails-app/conf/BuildConfig.groovy grails.project.class.dir = "target/classes" grails.project.test.class.dir = "target/test-classes" grails.project.test.reports.dir = "target/test-reports" grails.project.dependency.resolution = { inherits("global") { } log "warn" repositories { grailsPlugins() grailsHome() grailsCentral() mavenCentral() } dependencies { runtime('jaxen:jaxen:1.1.1') { transitive = false } } }
We can run our Grails application with $ grails run-app
and open the URL http://localhost:8080/server/services/blog?wsdl
to see the changes in the generated WSDL file.
Because the definition of our SOAP web service is changed we can also change the client code. We now no longer have use JAXBElement
objects, so our code is much cleaner. We can access the object types directly. For example for the dynamic SearchRequest
object we can set the authorName
property directly. In our old client code we had to create a JAXBElement
object to set the value.
package com.mrhaki.groovyws.client import groovyx.net.ws.WSClient class BlogWSClient { String wsdlUrl def proxy def findAuthor(String name) { createProxy() def searchRequest = createSearchRequest(name) proxy.findAuthor searchRequest } private def createSearchRequest(String name) { def searchRequest = proxy.create('com.mrhaki.groovyws.server.SearchRequest') searchRequest.authorName = name searchRequest } private void createProxy() { if (!proxy) { proxy = new WSClient(wsdlUrl, this.class.classLoader) proxy.initialize() } } }
package com.mrhaki.groovyws.client import spock.lang.Specification class BlogWSClientSpec extends Specification { def client = new BlogWSClient(wsdlUrl: 'http://localhost:8080/server/services/blog?wsdl') def "get author with name mrhaki and two blog items"() { when: def author = client.findAuthor('mrhaki') then: 'mrhaki' == author.name def arrayOfBlogItems = author.blogItems def blogItems = arrayOfBlogItems.blogItem 2 == blogItems.size() 'Title1' == blogItems[0].title 'Title2' == blogItems[1].title 'Sample blogitem one.' == blogItems[0].text 'Sample blogitem two.' == blogItems[1].text } }
In the next post we see how we can add logging interceptors to our client so we can see the input and output from the invocation of the SOAP web service.