Note: my knowledge of soap is not very deep, but I have done the following in a production system.
If you have a WSDL available, a good approach is to generate the (Java) client code and then use it via Java interop. You can smooth out the rough edges and shed the extra java types by using the clojure.java.data library to define to-java and from-java methods. https://github.com/clojure/java.data The state-of-the-art in java code generation from a WSDL seems to be Apache cxf http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html Below is a mini-tutorial of its use. In the project.clj, add the configuration and dependencies that cxf needs. We'll be using cxf through a maven plugin that wraps it (cxf-codegen-plugin). The maven plugin is configured via a pom, so we'll use leinigen's :pom-additions and :pom-plugins keys to inject stuff into the pom it generates. (defproject my-soap-client "0.0.1-SNAPSHOT" :description "Example of using leinigen to generate a pom to generate Java from WSDLs using maven and cxf-codegen-plugin" :source-paths [] ;; NOTE: No Clojure code! :java-source-paths ["src"] ;; NOTE: Where the *generated* java will go! ;; NOTE: Adding source path to clean targets because it is generated code! :clean-targets ^{:protect false} [:target-path :compile-path :java-source-paths] :pom-addition [:properties [:project.build.sourceEncoding "UTF-8"]] ;; This is all Maven stuff, documented here: https://maven.apache.org/guides/mini/guide-configuring-plugins.html#Configuring_Build_Plugins ;; What you see below is serialized as XML in the generated pom.xml :pom-plugins [[org.apache.maven.plugins/maven-source-plugin "2.4" {:executions [:execution [:id "bundle-sources"] [:goals [:goal "jar-no-fork"]]]}] [org.apache.cxf/cxf-codegen-plugin "3.1.1" {:executions [:execution [:id "my-execution-id"] [:phase "generate-sources"] [:configuration [:sourceRoot "${project.basedir}/src"] ;; NOTE: Options documented here: http://cxf.apache.org/docs/wsdl-to-java.html ;; Some WSDLs may need more or fewer options than shown here. [:wsdlOptions [:wsdlOption ;; NOTE: Consider downloading the wsdl to a file. [:wsdl "https://example.org/mywsdl"] [:extraargs [:extraarg "-verbose"] [:extraarg "-mark-generated"] [:extraarg "-exsh"] [:extraarg "true"] [:extraarg "-autoNameResolution"]]]]] [:goals [:goal "wsdl2java"]]]}]]) Then with this project.clj in place, you build your java code like so: #!/bin/sh lein do clean, pom && mvn package # This will define variables used below. source target/maven-archiver/pom.properties BUILT_JAR=target/${artifactId}-${version}.jar SRC_JAR=target/${artifactId}-${version}-sources.jar # You can then use the "full" form of lein deploy to create a maven-compatible release artifact # Include this in your *real* clojure project as a dependency! # TODO: I don't know how (or if it is possible) to get leinigen to deploy separate # java/maven source or javadoc jars too. lein deploy releases "${groupId}/${artifactId}" "${version}" "${BUILT_JAR}" pom.xml Up until now we have done nothing that really involves Clojure. This could have been a plain Java maven project with a handcrafted pom.xml. The jar itself is just compiled java class files. I just used leinigen because it was more familiar. In your actual Clojure project, require this java-soap-client project you deployed: [my-soap-client "0.0.1-SNAPSHOT"] Then use it via Java interop. Details may vary (see your WSDL or the SOAP service documentation), but usually there's a Service object you need to instantiate somehow, and then call getSoapXX on it to get a Port object which has methods on it corresponding to the SOAP methods the service provides. I think both of these are stateless and long-lived and can be shared by threads. (import '(my.soap.service ServiceClass)) (let [service (ServiceClass.) port (.getSoap12 service)] ;; Sometimes the WSDL does not include the url of the soap service and you have to set it manually (import '(javax.xml.ws BindingProvider)) (.. ^BindingProvider port (getRequestContext) (put BindingProvider/ENDPOINT_ADDRESS_PROPERTY endpoint)) ;; Now call your SOAP methods! (.mySoapMethod port) ) Depending on the SOAP service and its WSDL, probably have a huge jumble of Java types to deal with in requests and responses, and you may even have raw XML to contend with, too. Your life will be much easier if you immediately convert instances from the Java client into plain Clojure data structures, and convert those data structures into the proper types right before you call the SOAP methods. clojure.data.java makes doing this much easier: you define a to-java and a from-java multimethod for the SOAP types you care about. It is also generic enough to handle many Java-bean like objects automatically. Example: (require '[clojure.java.data :refer [to-java from-java]]) (defmethod from-java WeirdSoapType [^WeirdSoapType x] ;; Contrived example: default to-java implementation will turn Bean-like things into maps automatically via reflection. {:a (.getA x) :b (.getB x}}) ;; You can make custom to-java also. (from-java (.getWeirdType port)) (.sendBeanyThing port (to-java TypeSoapWants {:c 1 :d 2})) I hope there is a better way to use SOAP from Clojure than all this, but it's hard to use SOAP services easily in *any* programming language! On Wednesday, July 29, 2015 at 9:47:21 PM UTC-5, Mike wrote: > > Hello, > > I have decided what my first Clojure project will be, but I could use some > guidiance. I would like to be able to make SOAP calls to a webservice on > another machine. > > I have done some searching, and there is an old clj-soap library which > Sean Corfield has mostly abandoned. How are people doing this? WOuld > someone be so kind as to post a small example? > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
