简体   繁体   中英

Calling a WCF service from Java

EDIT: the issue was with the [MessageHeader] attributes in the ResponseMessage class; Metro/JAX-WS doesn't seem capable of handling these attributes. Changing them to [MessageBodyMember] solved the issue.


As the title says, I need to get some Java 1.5 code to call a WCF web service. I've downloaded and used Metro to generate Java proxy classes, but they aren't generating what I expect, and I believe this is because of the WSDL that the WCF service generates.

My WCF classes look like this (full code omitted for brevity):

public class TestService : IService
{
  public TestResponse DoTest(TestRequest request)
  {
    TestResponse response = new TestResponse();

    // actual testing code...

    response.Result = ResponseResult.Success;

    return response;
  }
}

public class TestResponse : ResponseMessage
{
  public bool TestSucceeded { get; set; }
}

public class ResponseMessage
{
  [MessageHeader]
  public ResponseResult Result { get; set; }

  [MessageHeader]
  public string ResponseDesc { get; set; }

  [MessageHeader]
  public Guid ErrorIdentifier { get; set; }
}

public enum ResponseResult
{
  Success,
  Error,
  Empty,
}

and the resulting WSDL (when I browse to http://localhost/TestService?wsdl=wsdl0 ) looks like this:

<xsd:element name="TestResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" name="TestSucceeded" type="xsd:boolean" /> 
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="ErrorIdentifier" type="q1:guid" xmlns:q1="http://schemas.microsoft.com/2003/10/Serialization/" /> 
<xsd:simpleType name="ResponseResult">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Error" /> 
<xsd:enumeration value="Success" /> 
<xsd:enumeration value="EmptyResult" /> 
</xsd:restriction>
</xsd:simpleType>
<xsd:element name="ResponseResult" nillable="true" type="tns:ResponseResult" /> 
<xsd:element name="Result" type="tns:ResponseResult" /> 
<xsd:element name="ResultDesc" nillable="true" type="xsd:string" />

...

<xs:element name="guid" nillable="true" type="tns:guid" /> 
<xs:simpleType name="guid">
<xs:restriction base="xs:string">
<xs:pattern value="[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}" /> 
</xs:restriction>
</xs:simpleType>

Immediately I see an issue with this WSDL: TestResponse does not contain the properties inherited from ResponseMessage . Since this service has always worked in Visual Studio I've never questioned this before, but maybe that could be causing my problem?

Anyhow, when I run Metro's wsimport.bat on the service the following error message is generated:

[WARNING] src-resolve.4.2: Error resolving component 'q1:guid'

and the outputted Java version of TestResponse lacks any of the properties from ResponseMessage .

I hacked the WSDL a bit and changed ErrorIdentifier to be typed as xsd:string , which makes the message about resolving the GUID type go away, but I still don't get any of ResponseMessage 's properties.

Finally, I altered the WSDL to include the 3 properties from ResponseMessage in TestResponse , and of course the end result is that the generated .java file contains them. However, when I actually call the WCF service from Java, those 3 properties are always null .

Any advice, apart from writing the proxy classes myself?

Some #%$^@! changed the [MessageBodyMember] attributes on the properties of ResponseMessage to [MessageHeader] without telling anyone. I changed them back to [MessageBodyMember] , regenerated the proxy classes and everything works correctly.

Onced I've finished the integration I'll be doing CVS diffs to find the person responsible, and then they shall SUFFER MY WRATH.

This problem has nothing to do with Java, but only with the WSDL being generated.

Why are you not using [DataContract] and [DataMember] on your TestResponse and ResponseMessage classes? Try that and see if it works.

Hm, I do not mean to be glib or reject Java-native solutions out of hand, but when it comes to the Wcf stack, the best advice is typically to use the Wcf stack.

More to the point: generate a CLR Wcf client [in language of choice auto-generate client via VS or svcutil against static wsdl or service endpoint] and then invoke this CLR proxy through some Java-CLR interop.

There are several reasons for this, not the least of which

  • Immediate compliance [by Wcf for Wcf]
  • Flexibility [it is not unreasonable to expect your remote service to change or leverage sophisticated communication protocols, such as message-level encryption, you want your client to change as easily as the service]

ps: I have strong misgivings about modifying existing service wsdls by hand. If the wsdl is indeed "the problem", then this indicates either a problem with service definition [ie server-side code] or service interpretation [ie an option on autogeneration utility]. Avoid manual manipulations of service contracts. Doing so would be like modifying IL byte code post-build.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM