(是的,我知道这个问题与another question posted类似;但是,这个问题从未得到解答。)
我尝试使用Clojure和Axis 2使用QuickBooks WebConnector(从现在开始的QBWC)访问QuickBooks数据。 QBWC使用SOAP与外部应用程序通信,这就是我的Clojure应用程序使用Axis 2作为SOAP接口的原因。我使用来自GitHub的micha's clj-soap来提供与Axis 2的Java调用的更高级(抽象)Clojure互操作。
问题在于使用QBWC验证我的SOAP Web服务。使用我的SOAP Web服务的authenticate
方法,QBWC会抛出错误。在QBWC日志文件中,它说明如下:
QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012: Authentication failed due to following error message: Object reference not set to an instance of an object.
StackTrace = at QBWebConnector.WebService.do_authenticate(String& ticket, String& companyFileName)
Source = QBWebConnector
下面是Clojure代码,该代码为我使用的Axis 2服务器定义了一个名为SOCAccess的Web服务。
(对于那些不熟悉Clojure但熟悉Java的人,下面的代码创建了一个名为developer.intuit.com.SOCAccess
的类,并定义了与QBWC通信所需的许多方法(包括authenticate
, serverVersion
等。插入符号表示返回或参数类型.Clojure编译成Java字节码,默认情况下它不使用强类型,这转换为大多数类型提示为Object
,但由于Java2WSDL的工作方式,需要强类型。例如:
类型^String
最终为<xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
类型^Object
最终为<xs:element minOccurs="0" name="return" nillable="true" type="xs:anyType"/>
类型^"[Ljava.lang.String;"
与String[]
相同,最终为<xs:element maxOccurs="unbounded" minOccurs="0" name="return" nillable="true" type="xs:string"/>
)
(soap/defservice developer.intuit.com.SOCAccess
(authenticate2 ^"[Ljava.lang.String;" [^String username ^String password]
(authenticate2* username password))
(authenticate ^"[Ljava.lang.String;" [^String username ^String password]
(authenticate* username password))
(prefix35authenticate ^"[Ljava.lang.String;" [^String username ^String password]
(authenticate* username password))
(sendRequestXML ^Object
[^String ticket ^String hcp-response ^String company-file-name ^String qb-xml-country
^Integer qb-xml-major-vers, ^Integer qb-xml-minor-vers]
(send-request-xml ticket hcp-response company-file-name qb-xml-country qb-xml-major-vers qb-xml-minor-vers))
(receiveResponseXML ^Integer [^String ticket ^String response ^String hresult ^String message]
(receive-response-xml ticket response hresult message))
(connectionError ^Object [^String ticket ^String hresult ^String message]
(connection-error ticket hresult message))
(getLastError ^String [^String ticket]
(get-last-error ticket))
(closeConnection ^String [^String ticket]
(close-connection ticket))
(getServerVersion ^String [^String ticket] (server-version ticket))
(serverVersion ^String [^String ticket] (server-version ticket))
(clientVersion ^String [^String version] (client-version version))
(interactiveDone ^String [^String ticket] (interactive-done ticket))
(interactiveRejected ^String [^String ticket ^String reason] (interactive-rejected ticket reason)))
一旦我启动AxisServer
并使用类名.addService
调用"developer.intuit.com.SOCAccess"
,输出窗口将打印以下内容,这是一个根据上述代码编译的类:
Jul 07, 2014 11:22:20 AM org.apache.axis2.transport.http.server.DefaultConnectionListener run
INFO: Listening on port 6060
一切似乎都正常运行。
但是,当我在运行的JVM中对我的Web服务进行SOAP调用(authenticate "my-username" "my-password")
时,返回值应该是String[]
并且println()输出显示它确实是一个String[]
,但返回值只显示为数组的第一个元素,这很奇怪。我的猜测是,这是QBWC发生Object reference not set to an instance of an object
错误的原因,因为它试图将String
的第n个元素视为数组。
======
有什么想法?我意识到这是一个很长的问题。让我知道您希望我以代码,WSDL等方式提供什么。
谢谢!
20140707.20:06:40 UTC : QBWebConnector.WebServiceManager.DoUpdateSelected() : updateWS() for application = 'SOCAccess' has STARTED
20140707.20:06:40 UTC : QBWebConnector.RegistryManager.getUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock = FALSE
20140707.20:06:40 UTC : QBWebConnector.RegistryManager.setUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock has been set to True
20140707.20:06:40 UTC : QBWebConnector.RegistryManager.setUpdateLock() : ********************* Update session locked *********************
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : Initiated connection to the following application.
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : AppName: SOCAccess
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : AppUniqueName (if available): SOCAccess
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : AppURL: http://localhost:6060/axis2/services/SOCAccess
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.do_serverVersion() : *** Calling serverVersion().
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.do_serverVersion() : Received from serverVersion() following parameter:<serverVersionRet="">
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.do_serverVersion() : This application sent a null for server version. Allowing update operation.
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.do_clientVersion() : *** Calling clientVersion() with following parameter:<productVersion="2.1.0.27">
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.do_clientVersion() : Received from clientVersion() following parameter:<clientVersionRet="">
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.do_clientVersion() : This application agrees with the current version of QBWebConnector. Allowing update operation.
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.do_authenticate() : Authenticating to application 'SOCAccess', username = 'alexandergunnarson'
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.do_authenticate() : *** Calling authenticate() with following parameters:<userName="alexandergunnarson"><password=<MaskedForSecurity>
20140707.20:06:40 UTC : QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012: Authentication failed due to following error message.
Object reference not set to an instance of an object.
More info:
StackTrace = at QBWebConnector.WebService.do_authenticate(String& ticket, String& companyFileName)
Source = QBWebConnector
20140707.20:06:40 UTC : QBWebConnector.RegistryManager.setUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock has been set to False
20140707.20:06:40 UTC : QBWebConnector.RegistryManager.setUpdateLock() : ********************* Update session unlocked *********************
20140707.20:06:40 UTC : QBWebConnector.WebServiceManager.DoUpdateSelected() : Update completed with errors. See log (QWClog.txt) for details.
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">
<soapenv:Body>
<axis2ns34:authenticate xmlns:axis2ns34=\"http://developer.intuit.com/\">
<axis2ns35:args0 xmlns:axis2ns35=\"http://developer.intuit.com/\">
alexandergunnarson
</axis2ns35:args0>
<axis2ns36:args1 xmlns:axis2ns36=\"http://developer.intuit.com/\">
password
</axis2ns36:args1>
</axis2ns34:authenticate>
</soapenv:Body>
</soapenv:Envelope>
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">
<soapenv:Body>
<ns:authenticateResponse xmlns:ns=\"http://developer.intuit.com/\">
<return>my-session-token</return>
<return>none</return>
<return>60</return>
<return>60</return>
</ns:authenticateResponse>
</soapenv:Body>
</soapenv:Envelope>
自从我上次发布以来,发生了很多事情。
1)我试图实现ArrayOfString,但是它没有很好地集成到WSDL中。
2)我从Intuit网站下载了QuickBooks WSDL,并使用WSDL2Java(在Axis2中)生成一个名为QBWebConnectorSvcStub.java的巨型(10K LOC).java文件。
3)我尝试扩展类并重写方法,但我一直遇到很多异常/错误。
4)然后我尝试编辑QBWebConnectorSvcStub
类的源代码,特别关注某些方法(首先编辑authenticate
,serverVersion
和clientVersion
,因为这样做了QBWC首先要求的是什么。对于这些方法,我将返回值绑定到Clojure类中的函数,将QBWebConnectorSvcStub方法的输入传递给相应的Clojure函数并返回所述函数的输出。基本上我让Clojure函数完成工作,QBWebConnectorSvcStub
充当SOAP中间人。
5)此时,我回到了与之前相同的错误(虽然幸运,clientVersion
按预期工作,如日志所示:Received from clientVersion() following parameter:<clientVersionRet="">
:
QBWebConnector.SOAPWebService.do_authenticate() : Authenticating to application 'QBWebConnectorSvcStub', username = 'alexandergunnarson'
QBWebConnector.SOAPWebService.do_authenticate() : *** Calling authenticate() with following parameters:<userName="alexandergunnarson"><password=<MaskedForSecurity>
QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012: Authentication failed due to following error message.
Object reference not set to an instance of an object.
为此,SOAP输出到QuickBooks是:
<ns:authenticateResponse xmlns:ns="http://developer.intuit.com/">
<return xmlns:ax22="http://io.java/xsd" xmlns:ax21="http://rmi.java/xsd" xmlns:ax25="http://developer.intuit.com/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax25:QBWebConnectorSvcStub_AuthenticateResponse">
<authenticateResult>
<string xmlns="http://developer.intuit.com/">
my-session-token
</string>
<string xmlns="http://developer.intuit.com/">
nvu
</string>
<string xmlns="http://developer.intuit.com/">
60
</string>
<string xmlns="http://developer.intuit.com/">
60
</string>
</authenticateResult>
<authenticateResultSpecified>
true
</authenticateResultSpecified>
</return>
</ns:authenticateResponse>
幸运的是(!)现在只有一个返回值,与以前不同。
看了example working authenticate SOAP request后,或许还有一个问题,因为我拿出了SOAP信封/标题?他们给我带来了nullPointerExceptions等问题。我会尝试将它们放回去。
这次痛苦冒险的下一部分现在是here。
答案 0 :(得分:1)
我不确定您的QBC文件是什么样的(为Quickbooks Web Connector定义应用程序的xml文件),但我通过更改样式设置修复了类似的问题
<Style>RPC</Style>
到
<Style>DocWrapped</Style>
如果未定义,您可能需要尝试“DocWrapped”或“RPC”值。来自QBWC_proguide:
的样式详情Web服务使用的SOAP编码样式。如果没有提供, 使用的默认值是Document。 Document是.NET使用时的标准编码风格 [WebMethod]属性应用于函数声明。 (可选)您可以指定DocWrapped值。 DocWrapped 与我们构建的Axis Web服务非常好地互操作 建议使用WSDL2Java从中生成Java Web类 Web连接器使用的标准WSDL(http:// developer.intuit.com/uploadedFiles/Support/ QBWebConnectorSvc.wsdl) 或者,您可以选择指定值RPC。 RPC风格是 Java类所用的Axis使用的标准编码样式 通过JWS或自动转换为SOAP服务 Java2WSDL工具。