Salesforce.com provides two SOAP APIs to access objects in a Salesforce.com organization. The Enterprise API is strongly typed and produces a very “discoverable” code-level API. The Partner API is loosely typed and is not very discoverable. For more on the differences between the two APIs, see Salesforce.com API Gotchas Part 1 and the other parts of this blog post series (Part 2, Part 3, Part 4). Update: I’ve released an open source library that presents a better interface to the Partner API (as well as other Salesforce APIs).
Salesforce.com provides documentation and sample code for both the Partner API and the Enterprise API at the API page of their wiki, but the only Java sample code for the Partner API uses Apache Axis. Axis is a fairly old SOAP stack which was last updated in April of 2006. I prefer to use the JAX-WS reference implementation, but the JAX-WS sample code uses the Enterprise API (see also).
To remedy the lack of documentation on using the Partner API documentation with the JAX-WS reference implementation, this tutorial series will describe how to use JAX-WS to create stub code, how to use the stub code to log in as a Salesforce.com partner, and how to perform basic API operations.
Generating Stub Code from the WSDL
When generating stub code, you have two main choices:
- Use a command line tool provided with the JAX-WS download in
wsimport.batfor Windows folks)
- Use an Ant task
Whichever way you choose, you have a few parameters to figure out:
- The location of the WSDL
- Whether or not you want to keep the generated source (.java) or just keep the compiled bytecode (.class)
- The directory to use for the generated source, if you want to keep it
- The directory to use for the build products of the generated source
- The package to use for the generated classes
I prefer to keep the generated source, so the example usage will show you how to keep the source. A basic use of the CLI (command line interface) tool would look like this:
jaxws-ri/bin/wsimport.sh -p sfstub -d sfstub-build -s sfstub-src partner-15.wsdl
You’ll need to change ‘jaxws-ri’ to be the path to your downloaded copy of the JAX-WS reference implementation. ‘sfstub’ is the package used for the generated classes. ‘sfstub-build’ is where the .class files will go. ‘sfstub-src’ is where the .java files will go.
If you prefer to use Ant, you would first need to do a
<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport" classpathref="someClasspath" />
where ‘someClasspath’ is a classpath name that includes the JAX-WS RI tools. This is just one of the many ways to specify classpaths with Ant, so check the Ant documentation for more on classpaths if this is new to you. Once you have your
wsimport Ant task defined, you can use it like this:
<wsimport wsdl="partner-15.wsdl" sourcedestdir="sfstub-src" destdir="sfstub-build" package="sfstub" />
In real usage, you would probably replace many or all of those attribute values with Ant references, but to keep things simple I’ve just used plain values.
So now you’ve got some stub classes, right? Unfortunately, it’s not that simple. Whether you decide to use the CLI tool or the Ant task , when you try to generate your stub code from the Partner WSDL, you’ll quickly run into errors like the following:
[ERROR] A class/interface with the same name "yourpkg.DescribeLayout" is already in use. Use a class customization to resolve this conflict. line 928 of file:/path/to/partner-15.wsdl [ERROR] (Relevant to above error) another "DescribeLayout" is generated from here. line 640 of file:/path/to/partner-15.wsdl [ERROR] Two declarations cause a collision in the ObjectFactory class. line 928 of file:/path/to/partner-15.wsdl [ERROR] (Related to above error) This is the other declaration. line 640 of file:/path/to/partner-15.wsdl
This example run was done against the Release 15 WSDL, so if you’re using a different version your line numbers (or even error messages) may differ, but you’ll probably have some class that has a naming conflict. In this case, the problem arises because there is both a
complexType and a
element in the WSDL that are named “DescribeLayout”.
By using a JAXB binding file, we can customize the names of the generated classes to not have a conflict.
<bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="//xsd:schema[@targetNamespace='urn:partner.soap.sforce.com']"> <jaxb:globalBindings underscoreBinding="asCharInWord" /> <jaxb:schemaBindings> <jaxb:nameXmlTransform> <jaxb:typeName suffix="Type" /> </jaxb:nameXmlTransform> </jaxb:schemaBindings> </bindings> <enableWrapperStyle>false</enableWrapperStyle> <enableAsyncMapping>false</enableAsyncMapping> </bindings>
Put that XML in a file (let’s say
sf-jaxb-binding.xml). Here’s the modified usage for the CLI tool:
jaxws-ri/bin/wsimport.sh -p sfstub -d sfstub-build -s sfstub-src -b sf-jaxb-binding.xml partner-15.wsdl
… and for the Ant task:
<wsimport wsdl="partner-15.wsdl" sourcedestdir="sfstub-src" destdir="sfstub-build" binding="sf-jaxb-binding.xml" package="sfstub" />
The JAXB binding file will cause “Type” to be appended. (You could use any string you wanted as long as it solves the conflict.) This is occasionally odd-looking in cases like “SoapType” which then becomes “SoapTypeType”.
You can avoid using a binding by having JAXB automatically resolve name conflicts. To do this, add a parameter to enable automatic name conflict resolution in JAXB. For the CLI tool, that looks like this:
jaxws-ri/bin/wsimport.sh -p sfstub -B-XautoNameResolution -d sfstub-build -s sfstub-src partner-15.wsdl
For the Ant task:
<wsimport wsdl="partner-15.wsdl" sourcedestdir="sfstub-src" destdir="sfstub-build" package="sfstub" > <arg value="-B-XautoNameResolution" /> </wsimport>
This will result in having a
DescribeLayout class as well as a
DescribeLayout2 class. In this case,
DescribeLayout is the
DescribeLayout2 is the
It’s a judgment call whether or not you prefer the binding file method with class names like “SoapTypeType” or the automatic method with class names like “DescribeLayout2” where the class names are a little harder to predict. The Ant task may be easier to integrate into your build system, but shell scripts are also fairly simple to call (albeit less portable than pure Java tasks) from Ant. There are also differences in the way method parameters and return values are handled for API calls; this is described in more detail in Part 2.
Whichever way you choose, you should now have compiled stub classes ready for use.
Continue on to Part 2 where I’ll show to use these stub classes to log in to a Salesforce organization.