Using the QuickBooks SDK via JACOB Java-COM Bridge

So you want to be a hero?

You had better be prepared for a little heroics if you want to use the QuickBooks SDK with Java because it isn’t exactly straightforward. I saw a few mentions of people having done this, but certainly didn’t find any tutorials. Maybe I will be the first person on the planet to write this up. BOW TO YOUR NEW GOD!

Anyway, the problem is that the QBSDK is done with Microsoft’s COM and Java has no built-in COM support. I should mention that you can use Java with the Online Edition or apparently by setting up a Tomcat server and sending qbXML through a SOAP-to-COM pipe or something like that. In my case, I had a bunch of existing Java code that I wanted to connect as directly as possible to QuickBooks – preferably using QBFC.

If you don’t know what I’m talking about with QBSDK, qbXML, and QBFC then you should read this informative tutorial.

After hunting around the web, I found a free library called JACOB: Java-COM Bridge. The theory is that I could go from Java -> JACOB -> QBFC -> QuickBooks. I managed to create a proof of concept for this theory that I will begin sharing with you now.

SETUP

  1. Obviously, install QuickBooks, run its updates, and create a test company file (I’m using QuickBooks Premier Nonprofit Edition 2007)
  2. Sign up with the Intuit Developer Network and then download/install the SDK. Note that you must say “yes” to installing the .NET stuff or the install will fail. (I’m using QBSDK 7.0)
  3. Download and extract JACOB (I’m using version 1.14)
  4. Being on a 32-bit OS, I copied the x86 JACOB DLL (jacob-1.14-x86.dll) into C:\WINDOWS\system32
  5. For Eclipse users, go to the Java Build Path property, click the Add External JARs button, and add jacob.jar to your project. For non-Eclipse users, make sure that the JAR is in your CLASSPATH.

NOTES ABOUT JACOB

Obviously everything you do with the QBSDK must be enveloped by JACOB API calls. The main beasts in JACOB seem to be Dispatch and Variant. Basically, you’ll use Dispatch to call functions on COM objects, and Variant to serve as parameters and outputs to those functions.

While JACOB seems to work well for me so far, the project lacks documentation of the HOWTO/tutorial variety. By cruising the web for examples and looking over the API, you can sort of figure out how things work. As I was wrestling with it, I stumbled across a QBFC wrapper for Ruby. Looking at the project’s source code helped me figure out a couple of things in the JACOB-QBFC connection.

One thing that JACOB lacks is the ability to lookup COM constants. Some of the QBFC functions require you to pass in one of their constants – hard to do when you can’t access them. The workaround for this is in the How can I get the value of constants? question in the JACOB FAQ. In short, you are supposed to use the Visual Basic editor in Excel to open the “object browser”, search for the constant, read its value, then code it into your program. Not exactly an elegant solution, but oh well. Note that when you’re in the object browser, you’ll need to go to Tools -> References and add the QBFC7Lib.

THE FIRST TIME HURTS

The first time you connect to QuickBooks through your application, you need to have QuickBooks already running. If you do not, then you’ll get an error message like:

This application is not allowed to log into this QuickBooks company data file automatically. The QuickBooks administrator can grant permission for an automatic login through the Integrated Application preferences.

The reason is that QuickBooks needs to pop open a dialog box and ask you if the application is really allowed to connect. After you’ve registered your application with QuickBooks, you’ll be able to access the data without the need to open it first.

SHOW ME THE CODE!

This code assumes that you have some vendors defined. If all goes according to plan, then it should print out all your defined vendors. Note that I am not doing all the various error, status, and type checking that the documentation mentions.

import com.jacob.com.*;

public class Foo {
  public static void main(String[] args) {
    System.out.println("Hello world!");
    // QBFC constants looked up using the object browser
    Variant ctLocalQDB = new Variant(1);
    Variant omDontCare = new Variant(2);
    // major and minor version of qbXML used to talk to QuickBooks
    Variant qbXMLMajor = new Variant(6);
    Variant qbXMLMinor = new Variant(0);
    // location of the company file to access
    String qbFile = "C:\\Documents and Settings\\rdavis\\Desktop\\FfAMETest.QBW";
    // connect to QuickBooks
    Dispatch qbsm = new Dispatch("QBFC7.QBSessionManager");
    Dispatch.call(qbsm, "OpenConnection2", "", "My Sample App", ctLocalQDB);
    Dispatch.call(qbsm, "BeginSession", qbFile, omDontCare);
    // build and execute a request to obtain all vendors
    Dispatch msgSet = Dispatch.call(qbsm, "CreateMsgSetRequest", "US", qbXMLMajor, qbXMLMinor).toDispatch();
    Dispatch.call(msgSet, "AppendVendorQueryRq");
    Dispatch resSet = Dispatch.call(qbsm, "DoRequests", msgSet).toDispatch();
    Dispatch resList = Dispatch.get(resSet, "ResponseList").toDispatch();
    int count = Dispatch.get(resList, "Count").getInt();
    for (int i = 0; i < count; i++) {
      Dispatch res = Dispatch.call(resList, "GetAt", new Variant(i)).toDispatch();
      // blindly assume that we have a vendor response
      Dispatch vendList = Dispatch.get(res, "Detail").toDispatch();
      int vcount = Dispatch.get(vendList, "Count").getInt();
      for (int j = 0; j < vcount; j++) {
        Dispatch vend = Dispatch.call(vendList, "GetAt", new Variant(j)).toDispatch();
        Dispatch dname = Dispatch.get(vend, "Name").toDispatch();
        String name = Dispatch.call(dname, "GetValue").getString();
        System.out.println("Vendor: " + name);
      }
    }
    // close the QuickBooks connection
    Dispatch.call(qbsm, "EndSession");
    Dispatch.call(qbsm, "CloseConnection");
    System.out.println("Goodbye world!");
  }
}

CONCLUSION

Using QBFC is already a somewhat verbose process and running it through JACOB certainly doesn't make the code more terse. Hopefully I'll be able to create my own little API to shield most of my code from needing to mess with all these Dispatches. My needs might be simple enough that I can wrap all the ugly stuff in a few function calls. After I get really down and dirty with QBFC I may write another post detailing my exploits.

This entry was posted in HOW-TOs, Micro$oft, Programming. Bookmark the permalink.

53 Responses to Using the QuickBooks SDK via JACOB Java-COM Bridge

  1. David says:

    Thanks for the post. This was just the info I needed to get started interfacing a Java app to QuickBooks. Ya gotta love Google. I’ll keep an eye out for any future posts you do on this subject.

    Thanks

  2. Paul says:

    After spending days on Google I’ve finally found someone who’s doing something similar to what I want to do.

    Scenario:
    There is a clinic that sells glasses, contact lenses, eye drops, etc. Patients buy these things and the sale is recorded on the clinic’s browser-based application. That application is used for all their patient management and so on, they don’t want to have to open up QuickBooks to record the sale obviously. So I’ve been asked to write a module to add onto their Java-based web application that will take each transaction and pop it into QuickBooks. It only needs to input transactions, it never needs to read anything out of QuickBooks

    The first thing I’d like to ask is do I go for the approach of entering each sale into QuickBooks transaction-by-transaction, or do I accumulate the sales for the day and then do a dump of the data into QuickBooks, OR do I accumulate the data for the day and then open up QuickBooks and do an import (that’s not very elegant).

    Secondly, what have been your findings on how to do this? I’m new to QuickBooks, and frankly feel a bit intimidated by the idea of attempting this, although I’m a pretty sharp programmer in both Java and PHP.

  3. theoden says:

    Paul: as a disclaimer, I don’t have much experience with Java-QuickBooks interaction aside from the proof of concept that I posted here. But as you mentioned, I can see two basic ways to approach it: 1) incorporate the QBSDK code into your Java webapp and add the transactions to QuickBooks in real time, or 2) run a batch job on an hourly/daily/whatever basis that imports any unprocessed transactions.

    If you’re going to do (1), then you might want to research the QuickBooks Online Edition. The reason is that I think this Java-COM bridge stuff needs everything (QuickBooks, the Java app, the QBSDK) to be installed on the same Windows box. With the Online Edition, I think you can talk to QuickBooks remotely using SOAP.

    For (2), you could set something up similar to the example I listed in this blog post. I guess you’d write a Java program that would query the clinic’s database for new transactions, then import them into QuickBooks via the Java-COM bridge.

    If I were you, I would want to do something along the lines of (1) because you keep your code centralized and there is potentially less complexity with fewer points of failure. The issues would probably be the cost of the Online Edition, figuring out to how to get it set up and configured, and trying to get the Java webapp to talk to it.

    Good luck!

  4. Sam says:

    Great Post! While messing around I decided to code-up a sample for performing an insert. the code is as follows:

    public static void main(String[] args) {
    // connect to QuickBooks
    Dispatch qbsm = new Dispatch(“QBFC7.QBSessionManager”);
    Dispatch.call(qbsm, “OpenConnection2”, “”, “My Sample App”, ctLocalQDB);

    System.out.println(“Starting Session 1”);
    String qbFile = “C:\\test\\sample_service-based business.qbw”;
    Dispatch.call(qbsm, “BeginSession”, qbFile, omDontCare);
    Dispatch msgSet = Dispatch.call(qbsm, “CreateMsgSetRequest”, “US”, qbXMLMajor, qbXMLMinor).toDispatch();

    Dispatch setMsg = Dispatch.call(msgSet, “AppendVendorAddRq”).toDispatch();

    Dispatch name = Dispatch.get(setMsg, “Name”).toDispatch();
    Dispatch.call(name, “setValue”, “testing”);
    Dispatch cName = Dispatch.get(setMsg, “CompanyName”).toDispatch();
    Dispatch.call(cName, “setValue”, “testing company”);

    Dispatch address = Dispatch.get(setMsg, “VendorAddress”).toDispatch();
    Dispatch addrline = Dispatch.get(address, “Addr1”).toDispatch();
    Dispatch.call(addrline, “setValue”, “address”);
    Dispatch addrCity = Dispatch.get(address, “City”).toDispatch();
    Dispatch.call(addrCity, “setValue”, “City”);
    Dispatch addrState = Dispatch.get(address, “State”).toDispatch();
    Dispatch.call(addrState, “setValue”, “State”);
    Dispatch addrZip = Dispatch.get(address, “PostalCode”).toDispatch();
    Dispatch.call(addrZip, “setValue”, “59236”);

    Dispatch resSet = Dispatch.call(qbsm, “DoRequests”, msgSet).toDispatch();
    Dispatch resList = Dispatch.get(resSet, “ResponseList”).toDispatch();

    // close the QuickBooks connection
    Dispatch.call(qbsm, “EndSession”);
    Dispatch.call(qbsm, “CloseConnection”);
    System.out.println(“Ending Session 1”);
    }

  5. Sam says:

    the corresponding insert would look something like this in C#

    vendorAddRequest.Name.SetValue(“ACME, Inc”);
    vendorAddRequest.CompanyName.SetValue(“ACME, Inc”);
    vendorAddRequest.VendorAddress.Addr1.SetValue(“123 Some St”);
    vendorAddRequest.VendorAddress.City.SetValue(“Somecity”);
    vendorAddRequest.VendorAddress.State.SetValue(“ST”);
    vendorAddRequest.VendorAddress.PostalCode.SetValue(“12345);

  6. mark says:

    Do you have any update about the Java API?

  7. Arden says:

    I am using QuickBooks Simple Start 2008, I have to set authFlags. The following is VB code from guide:
    ======================================================
    Dim authFlags As Long
    authFlags = 0
    authFlags = authFlags Or &H8&
    authFlags = authFlags Or &H4&
    authFlags = authFlags Or &H2&
    authFlags = authFlags Or &H1&
    authFlags = authFlags Or &H80000000

    Dim qbXMLCOM As QBXMLRP2Lib.RequestProcessor2
    Dim prefs As QBXMLRP2Lib.AuthPreferences
    Set prefs = qbXMLCOM.AuthPreferences
    prefs.PutAuthFlags (authFlags)
    ======================================================
    How can I covert the code into java using JACOB?

    Thanks a lot.
    Arden

  8. Arden says:

    Finally, I make it works.
    ==============================================================
    long authFlags = 0;
    authFlags = authFlags | SupportQBSimpleStart;
    authFlags = authFlags | SupportQBPro;
    authFlags = authFlags | SupportQBPremier;
    authFlags = authFlags | SupportQBEnterprise;
    authFlags = authFlags | ForceAuthDialog;

    Variant qbAuthFlags = new Variant();
    qbAuthFlags.putLong(authFlags);

    Dispatch qbsm = new Dispatch(“QBFC7.QBSessionManager”);

    Dispatch auth = Dispatch.call(qbsm, “QBAuthPreferences”).toDispatch();

    Dispatch.call(auth, “PutAuthFlags”, qbAuthFlags);

  9. Akkarin says:

    I was trying to get the names of my customers and then some data from custom defined fields, it was annoyingly painful and here is the most useful place I found, so the code to do it is below.
    DataExtRet is a list of all the custom data you have so you have to go through the list and find what you’re wanting.
    Also if you’re wanting to access private information the OwnerId has to be the guid of the data and not 0.

    Dispatch currentSession = new Dispatch(“QBFC7.QBSessionManager”);
    Dispatch.call(currentSession, “OpenConnection2”, “”, “My Sample App”, ctLocalQDB);
    Dispatch.call(currentSession, “BeginSession”, qbFile, omDontCare);
    Dispatch msgSet = Dispatch.call(currentSession, “CreateMsgSetRequest”, “UK”, qbXMLMajor, qbXMLMinor).toDispatch();
    Dispatch req = Dispatch.call(msgSet, “AppendCustomerQueryRq”).toDispatch();
    Dispatch inc = Dispatch.get(req, “IncludeRetElementList”).toDispatch();
    Dispatch.call(inc,”Add”, “Name”);
    Dispatch.call(inc,”Add”, “DataExtRet”);
    Dispatch owner = Dispatch.get(req, “OwnerIDList”).toDispatch();
    Dispatch.call(owner,”Add”, “0”);
    Dispatch resSet = Dispatch.call(currentSession, “DoRequests”, msgSet).toDispatch();
    Dispatch resList = Dispatch.get(resSet, “ResponseList”).toDispatch();

  10. Lenny says:

    Support for Java by Intuit is a joke.

    Did you know that the Quickbooks SDK actually points to this page in their Java section???

    This is taken from the Quickbooks SDK Programming manual, regarding java:

    *************************************
    Using Java with QB SDK
    If you want to use Java with the QB SDK, you need to use a Java to COM bridge, for example the Jacob bridge product. For more information, search the web, and take a look at the blog Using the QuickBooks SDK via JACOB Java-Com Bridge.from Theoden’s Coding Tips.
    *******************************************

    What a joke. Very professional on your part Intuit.

    While Theoden has developed working method, lets face it, this is a pain in the butt to use.

    Don’t get me wrong, we should all be thankful he actually went and did this work; and that he offered to create a class wrapper to facilitate use. However, I’m guessing that he must be tied up in other projects, since there is no sign of this API.

    I’ve created one. It uses qbXML instead of QBFC, which I believe is the best way to go for QBJava interaction. Simply create the XML file, pass it as a String to my program along with the path to the company file you want to modify and that’s it. The program will pass along Quickbooks reply.

    If interested, contact me at temporal_69-qb*yahoo.com (substitute the * for @)

  11. theoden says:

    Wow… I had no idea that I was linked to in the SDK manual. The story is that a co-worker wound up writing the API, reworking it several times in the year since I originally made this post. Since Intuit has apparently passed the Java buck to this blog, I’ll make inquiries about open-sourcing the code. I’ll update you with a comment in a day or so…

    • theoden says:

      Unfortunately it looks like I will not be able to open-source the code 🙁 Perhaps one day Intuit will develop their own Java API. JACOB is licensed under the LGPL so that would make it easier on them I’d imagine…

  12. ariel says:

    Don’t worry theoden I undestand…
    Btw… I have like a week searching for something that make me understand what the hell is happening around quickbooks.
    I made a complete website using Spring MVC and Spring Webflow (java)… now I have to integrate it with quickbooks. Demo I just found things for .net and well I was like agh damn this is getting hot lol…

    well this was pretty god for me… thinking that is the first time that something that work with java is working… 🙂
    So you did pretty god….

    I will continue using searching, cuz I almost sure that I have to use the webconnect for quickbooks, but I still don’t have any idea about how I can integrate with it…

  13. nabobnick says:

    For anyone interested that would like a more Java friendly QBFC like interface I have written a program (about 2 years ago) that takes a QBFC.tlh file and generates a code for a DLL (compiled with Visual Studio Express C++) that wraps the COM and code for a JAR that wraps the DLL. It could probably use some tweaking if the API has changed in newer versions of QuickBooks, I think it was build on 6.0. It’s provided as is, and if it needs fixing you’ll probably have to learn little about COM. Consider it under a BSD license (no license text or copyrights appear in the code). Attribution would be nice at the very least. Feel free to come up with a better name for it. Code is found at http://nutzy.net/downloads/CashQ%20Generator.zip and a sample usage at http://nutzy.net/downloads/CashQExample.java.

  14. nabobnick says:

    Almost forgot some code that is needed: http://nutzy.net/downloads/CashQ.zip. This is the fully generated Java part of the source code (most of which is regenerated by the previous code). Some of the files in here are assumed to already exist when the Generator runs (like the files in the COM directory). There may be others however in the root (over 1000 files in there) but I have forgotten for sure. So when the generator runs it points to this directory to store files in with the “hard coded” files preexisting. QBBase.java might be one of them (the lower level base classes are the best candidates hints from memory I can give at the present).

  15. nabobnick says:

    Sorry one last thing. Improvements over JACOB include the fact that you get Java Enums to represent the COM enums. If you use an IDE you get full code completion on the whole API, no guessing the strings of method names. I’ve tried to keep memory management to a minimum. Here’s most of the useful info out of the “manual” I wrote:

    CashQ provides access to the QBFC API by wrapping the COM objects using JNI.

    Since COM is used it must be initialized before accessing any of the QBFC

    classes and methods, then when done it must be uninitialized to free up the

    resources used by COM. COM must be initialized/uninitialized for each thread

    of your application separately. Use the static methods COM.initialize() and

    COM.uninitialize() at the start and end of each thread where QBFC classes and

    methods may be used.

    All methods in CashQ, even constructors, have the possibility of errors related

    to failures at the COM level. Due to this, every method and constructor may throw

    a Java exception named COMException. This exception subclasses RuntimeException

    and provides access to the integer HRESULT code and string error message retrieved

    from COM. Use the toString() method to retrieve a nicely formatted String that

    includes the hexadecimal version of the HRESULT code with the error message. To

    retrieve the code and message by themselves use getHRESULT() and getMessage().

    Since CashQ uses COM it must track references to COM objects that must be released

    when you are done with them. This extra memory clean up has been kept to a minimum.

    Only the following classes need to be released after use: QBSessionManager,

    QBOESessionManager, MsgSetRequest, MsgSetResponse, SubscriptionMsgSetRequest, and

    SubscriptionMsgSetResponse. All other references to COM objects are child

    references of one of these six classes and will be released when the parent

    instance is released. Call the release() method when you are finished with an

    instance of one of these classes.

    The naming of classes and methods in CashQ closely follow the original naming in

    QBFC with a few exceptions. Instead of accessing functionality through interfaces

    such as ICheckQuery the corresponding CashQ Java class would be named CheckQuery

    without the “I” prefix. Method names have been changed to match Java naming

    conventions by making the first character of the name lower case. For example,

    the “AppendCheckQueryRq” method from MsgSetRequest is now “appendCheckQueryRq”.

    Lastly any methods that begin with “Put” will begin with “set” instead.

    There are four methods that in the original QBFC API use return values using

    parameters, either by pointers in C++ or out parameters in C#. Since Java does

    not support returning values through parameters four special classes were made

    to return the values from these methods. Each class simply contains getters

    for each parameter from the original QBFC function call. They are as follows:

    QBSessionManager.getVersion() returns QBVersion

    MsgSetRequest.verify() returns QBErrorMessage

    QBDateTimeType.getTimeZone() returns QBTimeZone

    QBTimeIntervalType.getValue() returns QBTimeInterval

  16. nabobnick says:

    Guess I shouldn’t post when exhausted here is the CPP code similar to the Java code I think there are “hard coded” class files present, but the majority are regenerated. Also created a small CPP project to generate the TLH file to use. http://nutzy.net/downloads/CashQ_CPP.zip and http://nutzy.net/downloads/create_tlh.zip

  17. Jeremy says:

    Has anyone had any luck using the QBXML library with Java/Jacob vs using the QBFC library? I’ve generated the Jacob stubs against the type library QBXMLRP2 using the latest version of jacob and jacobgen. I’ve tried the following code without success. It always dies when attempting to call any of AuthPreferences methods with “Can’t map name to dispid”. I was trying to avoid having to expose the full QBFC COM api, so that’s why I’m trying to go with the supposedly simpler QBXML api.

    Here’s the code:

    RequestProcessor2 rp = null;
    String ticket = null;
    String response = null;
    try {
    rp = new RequestProcessor2();
    rp.openConnection2(APPLICATION_ID, APPLICATION_NAME, QBXMLRPConnectionType.localQBD);
    int authflags = 0;
    authflags = authflags | 0x01;
    AuthPreferences authPref = rp.authPref();
    authPref.putUnattendedModePref(QBXMLRPUnattendedModePrefType.umpRequired);
    authPref.putAuthFlags(authflags);
    ticket = rp.beginSession(
    //”C:/Documents and Settings/All Users/Documents/Intuit/QuickBooks/Company Files/EXAMPLE.QBW”,
    “”,
    QBFileMode.qbFileOpenDoNotCare);
    response = rp.processRequest(ticket, request);
    logger.info(“Response:\n” + response);
    } catch (Exception e) {
    logger.error(“Error with request”, e);
    return;
    } finally {
    if (rp != null) {
    if (ticket != null) {
    rp.endSession(ticket);
    }
    rp.closeConnection();
    }
    }

  18. Tonté says:

    Lenny or Jeremy,

    Are you still actively building a java integration to QB via XML? If you are, I would like to collaborate with you and any body else in this effort; as I think that is the way to go. My approach is to use JAXB to auto generate the Java object for the XML from the QB DTDs/Schemas and use Lenny’s or Jeremy’s mechanism to pass the XML to QB via QBFC by way of (I guess) JACOB. I would like to use what you have as a starting point. Would you share the source code with me? I tried emailing Lenny; but without any luck.

    Thanks!

    Tonté

  19. Chris says:

    I’ve got these samples to work but having a tough time with complex transactions like creating sales receipts and invoices. Does anyone have samples using this approach with JACOB or anything else Java? TIA – Chris

  20. Chris says:

    p.s. email me at chris dot greaves at redtraincom

  21. Dieter says:

    Does this QB SDK apply to QuickBooks sold in Germany from the company LexWare ?
    If not, is there any clue how to export bookings for this LexWare version of QuickBooks ?

  22. Lenny says:

    Hi all,

    Back again after a bit of an absence. The good news is that I’ve completed a full API for accessing QuickBooks seamlessly with Java. With this package, it becomes as easy as in the Visual Studio solutions to interface with QuickBooks.

    No need for JACOB heroics (Although a big nod goes to Theoden for pointing a bunch of people in the right direction). You can either build a QBXML object using the API, or use your existing qbXML code directly. The program will handle communications, and return QB’s response as a qbXML string to be parsed in your XML parser of choice.

    Here’s a quick example of the code in action. This would be the procedure for adding a new customer:
    //**********************************************//
    //Create customerAdd request
    CustomerAdd newCust = new CustomerAdd();
    newCust.Name = “John’s Pizzeria”;
    newCust.FirstName = “John”;
    newCust.LastName = “Smith”;
    newCust.CompanyName = “John’s Pizza”;
    newCust.Phone = “555-555-5555”;

    //Create billing address for this customer
    BillAddress newBilling = new BillAddress();
    newBilling.Addr1 = “123 Main St”;
    newBilling.Addr2 = “Suite #2”;
    newBilling.City = “Beverly Hills”;
    newBilling.State = “CA”;
    newBilling.PostalCode = “90210”;

    //Add it to the customer
    newCust.BillAddress = newBilling;

    //Since we can add many at the same time, we create a list of new customers to add
    ArrayList listOfNewCustomers = new ArrayList();

    //Add our new customer to the list
    listOfNewCustomers.add(newCust);

    QBXML query = new QBXML(); //Initialize Query
    query.QBXMLMsgsRq = new QBXMLMsgsRq(); //Create Message Request
    query.QBXMLMsgsRq.CustomerAddRq = new CustomerAddRq(); //Initialize customer request.
    query.QBXMLMsgsRq.CustomerAddRq.CustomerAdd = listOfNewCustomers; //Add the list of new customer

    //Add a requestID. Don’t forget this step!!! QB needs a requestId and onError attribute for all requests.
    query.QBXMLMsgsRq.onError = “stopOnError”;
    query.QBXMLMsgsRq.CustomerAddRq.requestID = “15”; //Set a request ID.

    String asString = query.toString(); //This is a human readable qbXML String.

    try {
    JQBConnector c = new JQBConnector(“C:/Release/egqb.exe”,”C:\\Test.QBW”); //Initialize Connector and company file.
    String ret = c.send(asString); //Send qbXML message to QB.
    System.out.println(ret); //Print result.
    } catch (JQBException ex) {
    ex.printStackTrace();

    }
    //******************************************************//

    Easy huh? This is what the Java community should have received from Intuit in their SDK.

    Questions? lenny (at) dragonpg.com
    The API can be obtained at : http://www.dragonpg.com/software/quickbooks/
    Take a look at the Java Quickbooks API Documentation here: http://www.dragonpg.com/software/quickbooks/doc/

  23. Xenobyte says:

    I prefer using QBXMLrp2.dll (qbXML)over the QuickBooks Foundation Classes (QBFC). QBFC have a tendency to get blow out by standard QuickBooks updates, while qbxmlrp2.dll is part of the install so the foundation classes do not have to loaded. On the flip side, using QBFC easier to get the concepts of QuickBooks coding.

    @Lenny: Good luck on Intuit doing anything that they do not want to do.

  24. Pingback: Using the QuickBooks SDK via JACOB Java-COM Bridge - Java Tutorial

  25. A Perl transliteration of the original JACOB source code is here:
    http://perlmonks.org/?node_id=908940

    Thank you for publishing this example. It will help me greatly.

  26. Checo says:

    How do you assign attributes to the Message Set Request? I want to translate the second line of the code below to jacob

    IMsgSetRequest requestMsgSet = sessionManager.CreateMsgSetRequest(“US”,1,.0);
    requestMsgSet.Attributes.OnError = ENRqOnError.roeContinue;

  27. Marc Holman says:

    I am writing a java desktop application which will connect to a server and pull various data products. Customers will be charged a ‘per-click’ fee (i.e. Sally at Acme pulls a data report costing $5 anywhere from 1 to several thousand times per day — I want her name, customer ID, product price, date/time, etc. sent to quickbooks each time she does this). So we could potentially have anywhere from 10 to eventually several hundred instances of this application out there.

    Anyone have any suggestions as to how I might approach this? I want to use ONLY java so would quickbooks would this api here allow for this integration? What version of quickbooks online would you recommend?

  28. theoden says:

    @Marc I’m hardly at expert at this, but If you have QuickBooks Online, then I think you can use Intuit “Data Services”: https://ipp.developer.intuit.com/0010_Intuit_Partner_Platform/0050_Data_Services

  29. Jeff says:

    Has anyone been able to create a purchase order through Java? I’ve been working on this for a couple of days, but I can’t populate the ORPurchaseOrderLineAddList. I’m assuming I need to append multiples here, but none of the examples I’ve seen goes through this. If anyone can point me in the right direction I’d be grateful.

    Thanks!

  30. Chris says:

    Super helpful! Thanks so much for posting this. 🙂

  31. Bert Riley says:

    Hello! I’m using QB SDK to cycle through transactions and delete them from a particular date onwards. The code works…up to a point. I’m using the ‘TxnType.GetValue’ to get the transaction type, which happens to be a number, and store it as a variable. When I try to use this value, in TxnDelType.SetValue, it does not work. It only works if I use the transaction type as the enumerated value eg tdlInvoice, etc. How can I convert the transaction type number to the enumerated value.

  32. jc says:

    This is an old thread but hopefully I can get an answer from here.

    I ran the example to retrieve all Vendors and works very well, thanks for that! The insert example provided by Sam in 2008 might also work, haven’t tried it yet. I’m wondering if there is a way to fetch for a single Vendor record and also a way to edit it. Also, I see that “AppendVendorAddRq” is used for the Vendor scenarios but what about for other objects? Is there a site with documentation?

    Thanks for any help!

  33. sam says:

    I try to run this program but it is not working in QB SDK13. Any one tell me how to run in eclipse with SDK13.
    Thanks for Reply.

  34. Maynard says:

    Has anyone tried using JACOB for IBM PCOMM emulator?

  35. Timothy says:

    @sam, I have some source code available if you’d like to look it over. I am using QBSDK 13 with QB Pro 2013 Request Processor in JDK 1.7. Let me know your email and I’ll send it to you. Be sure that the request process is up and running, your application has received permission from the company file administrator, and the SDK is installed.

    @Checo, (if you still check this) Did you ever figure out how to add the “OnError” attribute in java? If so, I’d really like to know. The work-around is having a different session manager and message set for each request (as I’ve had to resort to this because of time constraints) but I’d really like a more elegant solutions by adding the “OnError” attribute. This one issue is annoying!

  36. Lumumba says:

    Hello Jeff, did you manage to add a purchase order to Quickbooks?
    Does anyone know how to add a purchase order to Quicbooks using QuickBooks SDK via JACOB Java-COM Bridge. I have spent the whole week working on this. Your help will be much appreciated.

  37. We are getting error while connecting with the QuickBooks Enterprise Solutions 15.0(desktop version) using the Jacob library.

    The code we are using is :
    import com.jacob.com.*;
    import com.jacob.activeX.*;
    public class Foo {
    public static void main(String[] args) {
    System.out.println(“Hello world!”);
    // QBFC constants looked up using the object browser
    Variant ctLocalQDB = new Variant(1);
    Variant omDontCare = new Variant(2);
    // major and minor version of qbXML used to talk to QuickBooks
    Variant qbXMLMajor = new Variant(6);
    Variant qbXMLMinor = new Variant(0);
    // location of the company file to access
    String qbFile = “C:\\Users\\Public\\Documents\\Intuit\\QuickBooks\\Sample Company Files\\QuickBooks Enterprise Solutions 14.0\\Oceanic Test.qbw”;
    // connect to QuickBooks
    Dispatch qbsm = new Dispatch(“QBFC13.QBSessionManager”);
    Dispatch.call(qbsm, “OpenConnection2”, “”, “My Sample App”, ctLocalQDB);
    Dispatch.call(qbsm, “BeginSession”, qbFile, omDontCare);
    // build and execute a request to obtain all vendors
    Dispatch msgSet = Dispatch.call(qbsm, “CreateMsgSetRequest”, “US”, qbXMLMajor, qbXMLMinor).toDispatch();
    Dispatch.call(msgSet, “AppendVendorQueryRq”);
    Dispatch resSet = Dispatch.call(qbsm, “DoRequests”, msgSet).toDispatch();
    Dispatch resList = Dispatch.get(resSet, “ResponseList”).toDispatch();
    int count = Dispatch.get(resList, “Count”).getInt();
    for (int i = 0; i < count; i++) {
    Dispatch res = Dispatch.call(resList, "GetAt", new Variant(i)).toDispatch();
    // blindly assume that we have a vendor response
    Dispatch vendList = Dispatch.get(res, "Detail").toDispatch();
    int vcount = Dispatch.get(vendList, "Count").getInt();
    for (int j = 0; j < vcount; j++) {
    Dispatch vend = Dispatch.call(vendList, "GetAt", new Variant(j)).toDispatch();
    Dispatch dname = Dispatch.get(vend, "Name").toDispatch();
    String name = Dispatch.call(dname, "GetValue").getString();
    System.out.println("Vendor: " + name);
    }
    }
    // close the QuickBooks connection
    Dispatch.call(qbsm, "EndSession");
    Dispatch.call(qbsm, "CloseConnection");
    System.out.println("Goodbye world!");
    }
    }

    We are getting the following error:
    Hello world!
    Exception in thread "main" com.jacob.com.ComFailException: Can't co-create object
    at com.jacob.com.Dispatch.createInstanceNative(Native Method)
    at com.jacob.com.Dispatch.(Dispatch.java:99)
    at Foo.main(Foo.java:16)

    Line 16 – Dispatch qbsm = new Dispatch(“QBFC13.QBSessionManager”);

    We are using Windows server 64 bit. We have checked over web and they are saying to add dll file(jacob-1.18-M2-x64.dll) that is given in the dowloaded Jacob. We tried all the things that are available but not able to resolve the error.
    Please suggest where we are doing wrong.

    Thanks,
    Astrea IT Services

  38. Kayd says:

    Hello, I know this thread is old but I think it’s going to be very helpful for me. I have a java desktop application I will like to send transactions from it to quickbooks. I will appreciate tutorials and documentation for me to go through.

    Great job all!

    • theoden says:

      As the years go by I continue to be surprised by the traffic this blog post continues to receive. I wrote this over 7 years ago, but I’m glad it still seems to be helping people out!

  39. Mark says:

    HI guys!!!!!

    I have a task about quickbooks on how to add, deduct item inventory and add a chart of accounts. Can you give me links where I can study do finish this task….. Any help is Highly Appreciated..

  40. Pavan says:

    Hello,

    We are getting the following error:
    Exception in thread “main” com.jacob.com.ComFailException: Can’t co-create object
    at com.jacob.com.Dispatch.createInstanceNative(Native Method)
    at com.jacob.com.Dispatch.(Dispatch.java:99)

    I have tried everything. Placing the dll in system32 and using regsvr32 to register the dll but with no success. If anyone was able to solve this then kindly suggest any mechanism to counter this. Any help would be greaty appreciated.

    Thanks

    Thanks,
    Pavan

  41. Ahmad says:

    You should use JDK x32 bit Pavan.

  42. Douglas says:

    Hi!
    I’m trying to do an insert on QB based on the code above.
    I get this error :
    Exception in thread “main” com.jacob.com.ComFailException: Invoke of: DoRequests
    Source: QBFC7.QBSessionManager.1
    Description: Missing ‘onError’ attribute.

    My code is (the one from sam above):

    Dispatch setMsg = Dispatch.call(msgSet, “AppendVendorAddRq”).toDispatch();
    Dispatch name = Dispatch.get(setMsg, “Name”).toDispatch();
    Dispatch.call(name, “setValue”, “testing”);
    Dispatch cName = Dispatch.get(setMsg, “CompanyName”).toDispatch();
    Dispatch.call(cName, “setValue”, “testing company”);
    Dispatch address = Dispatch.get(setMsg, “VendorAddress”).toDispatch();
    Dispatch addrline = Dispatch.get(address, “Addr1”).toDispatch();
    Dispatch.call(addrline, “setValue”, “address”);
    Dispatch addrCity = Dispatch.get(address, “City”).toDispatch();
    Dispatch.call(addrCity, “setValue”, “City”);
    Dispatch addrState = Dispatch.get(address, “State”).toDispatch();
    Dispatch.call(addrState, “setValue”, “State”);
    Dispatch addrZip = Dispatch.get(address, “PostalCode”).toDispatch();
    Dispatch.call(addrZip, “setValue”, “59236”);
    resSet = Dispatch.call(qbsm, “DoRequests”, msgSet).toDispatch();
    resList = Dispatch.get(resSet, “ResponseList”).toDispatch();

    error appears at this line : resSet = Dispatch.call(qbsm, “DoRequests”, msgSet).toDispatch();

    Any help would be amazing 🙂

  43. Brindha says:

    Exception in thread “main” java.lang.UnsatisfiedLinkError: no jacob-1.18-x64 in java.library.path

    How to resolve this issue.

  44. Antonio says:

    Brindha – This solution sucks, but I had to put the jacob-1.18-x86.dll in the jdk\bin folder.

    Note: I wasn’t able to even get the UnstatisfiedLinkError using 64 bit dll. I kept getting “Can’t co-create object”, but got past it by switching to 32 bit JVM.

    Does anyone know if it’s possible to use 64 bit JVM? Everywhere I am seeing, everyone says you must use 32 bit JVM, but if that’s the case then why do they provide 64 bit dll?

  45. Bhaumik says:

    Hi,
    I am working on the above POC, but getting com.jacob.com.ComFailException: Can’t co-create. I am able to call other COMs like Outlook.Application or Onenote.Application.
    I’m using Quickbooks Desktop 2020 version with Jacob 1.19.

    So is there any concrete solution for this?

    Thank you.

  46. Damon says:

    Hey, just want to report that I have been using this solution for a couple years now and it works as well as any QB integration. A few tips:
    – You have to use 32 bit version of Java (i.e. Java 8 or less)
    – Find the xsd files in the QBSDK files and use the jaxb command line tool to convert the xml schema into classes. I bundled all the classes into a jar, but you could just use the ones you need too.
    – Use the XML Validator and qbXMLTest+ tools that come with the qbSDK
    – Refer to the programmers guide that comes with the qbSDK

    The basic code (which I have wrapped in a DAO) looks like this:
    ———————————————————————
    //Open a Connection
    Dispatch requestProc = new Dispatch(“QBXMLRP2.RequestProcessor”); //notice this is different than the example on this page.
    Dispatch.call(requestProc, “OpenConnection2”, “”, “Your App Name Here”, 1);

    try {
    String xml = …Your XML Request…; //hint:use jaxb
    //Begin a session
    private Variant ticket = Dispatch.call(requestProc, “BeginSession”, “…path to your QB file here…”, 2);
    String response = Dispatch.call(requestProc, “ProcessRequest”, ticket, xml).toString();
    //…use jaxb to parse string back to object and handle object.
    //…check the status severity and status message – throw error if needed
    } finally {
    //End Session
    if(requestProc != null && ticket != null)
    Dispatch.call(requestProc, “EndSession”, ticket);
    }
    //After all processing is done, Close connection
    if(requestProc != null)
    Dispatch.call(requestProc, “CloseConnection”);

    —————————————————————————————
    Lastly, here is a sample request to help you with flow…
    —————————————————————————————

    800009F5-1511193547
    My Test Company

    2019-10-15
    0-1

    My Test Company
    3644 West Apple Rd
    Big Rock
    IL
    84870

    9876

    80000009-1511193457
    JAM

    {63bd4065-94af-4b5d-ba1c-a81f889e4199}

    TxnID
    TimeCreated
    ExternalGUID
    RefNumber

  47. Damon says:

    Sorry, not trying to spam here, but it looks like I needed to escape some characters, so re-posting with escapes.

    Hey, just want to report that I have been using this solution for a couple years now and it works as well as any QB integration. A few tips:
    – You have to use 32 bit version of Java (i.e. Java 8 or less)
    – Find the xsd files in the QBSDK files and use the jaxb command line tool to convert the xml schema into classes. I bundled all the classes into a jar, but you could just use the ones you need too.
    – Use the XML Validator and qbXMLTest+ tools that come with the qbSDK
    – Refer to the programmers guide that comes with the qbSDK

    The basic code (which I have wrapped in a DAO) looks like this:
    ———————————————————————
    //Open a Connection
    Dispatch requestProc = new Dispatch(“QBXMLRP2.RequestProcessor”); //notice this is different than the example on this page.
    Dispatch.call(requestProc, “OpenConnection2”, “”, “Your App Name Here”, 1);

    try {
    String xml = …Your XML Request…; //hint:use jaxb
    //Begin a session
    private Variant ticket = Dispatch.call(requestProc, “BeginSession”, “…path to your QB file here…”, 2);
    String response = Dispatch.call(requestProc, “ProcessRequest”, ticket, xml).toString();
    //…use jaxb to parse string back to object and handle object.
    //…check the status severity and status message – throw error if needed
    } finally {
    //End Session
    if(requestProc != null && ticket != null)
    Dispatch.call(requestProc, “EndSession”, ticket);
    }
    //After all processing is done, Close connection
    if(requestProc != null)
    Dispatch.call(requestProc, “CloseConnection”);

    —————————————————————————————
    Lastly, here is a sample request to help you with flow…
    —————————————————————————————
    <?xml version=”1.0″ encoding=”US-ASCII” standalone=”no”?>
    <?qbxml version=”13.0″?>
    <QBXML>
    <QBXMLMsgsRq onError=”stopOnError”>
    <SalesOrderAddRq requestID=”2″>
    <SalesOrderAdd>
    <CustomerRef>
    <ListID>800009F5-1511193547</ListID>
    <FullName>My Test Company</FullName>
    </CustomerRef>
    <TxnDate>2019-10-15</TxnDate>
    <RefNumber>0-1</RefNumber>
    <ShipAddress>
    <Addr1>My Test Company</Addr1>
    <Addr2>3644 West Apple Rd</Addr2>
    <City>Big Rock</City>
    <State>IL</State>
    <PostalCode>84870</PostalCode>
    </ShipAddress>
    <PONumber>9876</PONumber>
    <SalesRepRef>
    <ListID>80000009-1511193457</ListID>
    <FullName>JAM</FullName>
    </SalesRepRef>
    <ExternalGUID>{63bd4065-94af-4b5d-ba1c-a81f889e4199}</ExternalGUID>
    </SalesOrderAdd>
    <IncludeRetElement>TxnID</IncludeRetElement>
    <IncludeRetElement>TimeCreated</IncludeRetElement>
    <IncludeRetElement>ExternalGUID</IncludeRetElement>
    <IncludeRetElement>RefNumber</IncludeRetElement>
    </SalesOrderAddRq>
    </QBXMLMsgsRq>
    </QBXML>

  48. Patrick says:

    Is there any way to do this using the x64 bit java?

  49. Jose says:

    @Patrick,
    Yes, you have to create a DLL surrogate in the registry.
    I posted a how to just because I had so many problems, to help out.
    https://youtu.be/yenpA-6Q3gs
    There is a link to the github project so you can look at the code.

    Take care.

  50. Patrick says:

    Hi Jose thank you for the article. I was able to develop the application in java but i have a challenge deploying the same as a service. would you happen to have any ideas?

Leave a Reply

Your email address will not be published. Required fields are marked *