I am working on a Grails 2.0.x application that needs to consume some web services. Simple enough, I have written many clients in the past, using Axis and Spring-WS in Java, and WCF in .Net. Almost everything I have done so far was easy with Grails and Groovy, so I set out to create a client in Grails.
First off, I found GroovyWS and discovered the ease in which one can create clients with this tool. All was well when running Grails locally, but when the application deployed to our dev integration server (Tomcat 6, Java 6), it was throwing some exceptions about not finding the JAXB types for the specified class name. Apparently, the JAXB implementation on the dev integration was creating classes of different names than the implementation running on my local machine, from the same WSDL. I started debugging but quickly found myself in dependency hell, so I stepped back and tried a different client.
I had used Spring-WS before on a Spring 2.5 Java project and knew how it worked, so I gave it a shot. Even with this implementation, I was getting errors and again finding myself in dependency hell. There was still one more client I had used in the past, so I thought I would give it a try. Running wsdl2java against Axis 1.4 resulted in a client where classes actually would not compile. I attribute this to the complexity of the service itself and Axis’ inability to correctly parse out the types correctly. In any case, no dice on Axis 1.4.
Then I remembered JAX-WS. It is the most up-to-date web service tool supported by Java. After some issues with wsimport failing to generate a client at all (the WSDL has not WS-I BP 1.1 compliant and was later fixed by the service developer), I was able to successfully generate the client. I integrated it with my code, fired up Grails, invoked the service and bam!:
runtime modeler error: SEI rsastationinventorymgmtcontract.StationInventoryMgmtPT has method __execute annotated as BARE but it has more than one parameter bound to body. This is invalid. Please annotate the method with annotation: @SOAPBinding(parameterStyle=SOAPBinding.ParameterStyle.WRAPPED)
What?! So JAX-WS doesn’t know how to correctly generate a client from a WSDL? I was doubtful and wanted to prove it worked. I created a simple Java application containing the source files for the generated client and a single Java class to test the service. I fired up the 1.6 JVM and ran the class, and lo and behold, the client invoked the service successfully. Then I thought, ‘Oh no, more dependency issues?!’ Then I thought of something. What if I ‘forced’ the JAX-WS implementation used at runtime? Surely that would help, right? I added the following to the Grails BuildConfig.groovy:
grails.project.dependency.resolution = {
...
dependencies {
...
runtime('com.sun.xml.ws:jaxws-rt:2.1.4')
}
}
I built the application and fired up Grails, and was able to invoke the service successfully.
All in all, I have been happy with my development experience in Grails, but dealing with web service clients left me wanting more from the framework in this area. Maybe it is just my unfamiliarity with the framework, but this solution was not obvious to me and left me scratching my head for a while.