Salesforce.com Partner SOAP API JAX-WS Tutorial Part 1

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:

  1. Use a command line tool provided with the JAX-WS download in bin/wsimport.sh (wsimport.bat for Windows folks)
  2. 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:

    <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 element and DescribeLayout2 is the complexType.

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.

  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Google Bookmarks
  • DZone
  • HackerNews
  • LinkedIn
  • Reddit
  • http://www.nowhereatall.net Brian Kessler

    I may not be the target audience as I’m new to JAX-WS and SOAP, but I’m missing some crucial information: What do I need to put in the ’sfstub’ package?

  • Marshall Pierce

    Brian,
    ‘sfstub’ is simply the package that the wsimport tool will use when generating classes for you. You don’t need to do anything with that package other than import things from it:

    import sfstub.SObject;

    You can choose any name you wish instead of ‘sfstub’, of course.

  • http://www.nowhereatall.net Brian Kessler

    Cheers for the prompt response.

    Between the above and reviewing “Design and develop JAX-WS 2.0 Web services”, I was to successfully import my WSDL files.

    At first I tried importing directly from SalesForce.com’s web server at https://na6.salesforce.com/setup/build/generateEnterpriseWsdl.apexp

    but this resulted in an error:

    [ERROR] Failed to read the WSDL document: https://na6.salesforce.com/setup/build/generateEnterpriseWsdl.apexp, because 1) could not find the document; /2) the document could not be read; 3) the root element of the document is not .
    unknown location

    Saving the file to my harddrive and then importing from the local files, the import seemed mostly successful. I did, however, received a couple warnings:

    [WARNING] src-resolve: Cannot resolve the name ‘tns:ID’ to a(n) ‘type definition’ component.
    line 30 of file:/D:/Brian%20Stuff/Education/Force.com/WSDL/enterprise.wsdl.xml#types?schema1

    [WARNING] src-resolve: Cannot resolve the name ‘tns:ID’ to a(n) ‘type definition’ component.
    line 30 of file:/D:/Brian%20Stuff/Education/Force.com/WSDL/enterprise.wsdl.xml#types?schema1

    Could it make any difference that the import was not from a “live” file on a webserver?

    Is there something I should do to fix my URL so I could import directly?

    Is there anything I should do about these warnings?

    Cheers in advance.

  • Marshall Pierce

    You’ll probably want to store the WSDL locally because JAX-WS needs it at runtime. If you look in the generated stub for SforceService or whatever it’s called in the Enterprise WSDL, you’ll see the path to the WSDL hardcoded. Part 2 of the tutorial shows how to deal with the fact that the WSDL will not be at D:/Brian%20Stuff/Education/Force.com/WSDL/enterprise.wsdl.xml when you deploy it.

    I get those same warnings about ‘tns:ID’ but they don’t seem to have any negative effect, so I wouldn’t worry about it.

  • http://www.nowhereatall.net Brian Kessler

    Cheers for the feedback!

  • Pingback: Quick summary of how to get started with the Enterprise WSDL API via Java’s JAXB « Force 201 – Force.com Development

  • MinGyoon Woo
    • Marshall Pierce

      That contains the WSDL for v10 of the Partner API, which is very old.

  • Pingback: Salesforce.com JAX-WS Partner API using Netbeans Howto Part 1 « G3nt00r's Blog

  • Pingback: A new Java Salesforce API Library | Team Lazer Beez Blog

  • Edwin

    Is there a specific reason why the Metadata “update” functionality isn’t implemented? Create and Delete are, but not Update.

  • Pingback: Salesforce.com Partner SOAP API JAX-WS Tutorial Part 4 | Team Lazer Beez Blog

  • Pingback: Salesforce.com Partner SOAP API JAX-WS Tutorial Part 3 | Team Lazer Beez Blog

  • Pingback: Salesforce.com Partner SOAP API JAX-WS Tutorial Part 2 | Team Lazer Beez Blog

  • Muhammad Shehu

    Thank, It really help

  • Dipil Jain

    i’m also having the same issue as Brian.. with partner wsdl v28. trying to us wsimport on it is resulting in warnings about tns:ID.. can you please help.