此时我有点失落。我绝不是SOAP / JAXb专家,但是,我正在尝试创建一个泛型类,它将为任何服务编组/调用/解组。我使用Weather Service wsdl作为出发点来证明这个概念。
我终于得到了编组,调用和解组来执行而没有错误,但是,响应对象没有被填充。任何人都可以帮助识别我做错了什么吗?如果可能的话,我也在寻找答案的一个很好的解释,这样我就可以从这次经历中学习。
同样,在击败时没有错误。问题是GetCityWeatherByZIPResponse.GetCityWeatherByZIPResult的值是null。我知道文档正在返回正确的结果,因为结果打印输出如下:
结果打印输出:
<?xml version="1.0" encoding="UTF-8"?><GetCityWeatherByZIPResponse xmlns="http://ws.cdyne.com/WeatherWS/">
<GetCityWeatherByZIPResult>
<Success>true</Success>
<ResponseText>City Found</ResponseText>
<State>MO</State>
<City>Saint Charles</City>
<WeatherStationCity>Farmington</WeatherStationCity>
<WeatherID>4</WeatherID>
<Description>Sunny</Description>
<Temperature>79</Temperature>
<RelativeHumidity>47</RelativeHumidity>
<Wind>CALM</Wind>
<Pressure>30.00S</Pressure>
<Visibility/>
<WindChill/>
<Remarks/>
</GetCityWeatherByZIPResult>
</GetCityWeatherByZIPResponse>
Response: GetCityWeatherByZIPResult: null
测试Web服务: http://wsf.cdyne.com/WeatherWS/Weather.asmx
初始调用(通过JBehave完成):
@Given("I call the weather soap service")
public void givenICallTheWeatherSoapService() {
GetCityWeatherByZIP weather = new GetCityWeatherByZIP();
weather.setZIP("63304");
try {
new WeatherTools();
WeatherSoap weatherSoap = new WeatherSoap();
GetCityWeatherByZIPResponse response = weatherSoap.getCityWeatherByZip("63304");
System.out.println("Response: " + response);
} catch (JAXBException | ParserConfigurationException | SOAPException | IOException e) {
Assert.fail(e.getMessage());
}
}
肥皂服务类:
public class WeatherSoap extends PTFSoapClient {
public WeatherSoap() throws JAXBException, ParserConfigurationException, SOAPException {
super(PTFApplication.getConfig(Environment.executionEnv.getEnv(), "Weather SOAP endpoint"));
}
public GetCityWeatherByZIPResponse getCityWeatherByZip(String zip) throws JAXBException, SOAPException, IOException {
GetCityWeatherByZIP weatherByZip = new GetCityWeatherByZIP();
weatherByZip.setZIP(zip);
try {
sendRequest(weatherByZip);
return (GetCityWeatherByZIPResponse) unmarshallResponse(GetCityWeatherByZIPResponse.class);
} catch (ParserConfigurationException | XMLStreamException e) {
e.printStackTrace();
return null;
}
}
}
基础框架类对调用进行通用化(可用于所有SOAP调用):
public class PTFSoapClient {
private JAXBContext context;
private Marshaller marshaller;
private Object object;
private SOAPMessage message;
private String endpoint;
private SOAPMessage response;
public PTFSoapClient(String endpoint) {
this.endpoint = endpoint;
}
public void toConsole() throws JAXBException, SOAPException, IOException {
message.writeTo(System.out);
System.out.print("\n");
}
public SOAPMessage sendRequest(Object obj) throws JAXBException, ParserConfigurationException, SOAPException {
object = obj;
context = JAXBContext.newInstance(obj.getClass());
marshaller = context.createMarshaller();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().newDocument();
marshaller.marshal(object,doc);
MessageFactory factory = MessageFactory.newInstance();
message = factory.createMessage();
message.getSOAPBody().addDocument(doc);
message.saveChanges();
SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection();
response = connection.call(message, endpoint);
connection.close();
try {
System.out.println("Response:");
response.writeTo(System.out);
System.out.println("");
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
public Object unmarshallResponse(Class<?> classname) throws JAXBException, XMLStreamException, SOAPException, IOException {
Document doc = response.getSOAPBody().extractContentAsDocument();
try {
System.out.println("Document: ");
printDocument(doc, System.out);
System.out.println("");
} catch (TransformerException e) {
e.printStackTrace();
}
Unmarshaller unmarshaller = JAXBContext.newInstance(classname).createUnmarshaller();
return unmarshaller.unmarshal(doc);
}
public static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "UTF-8")));
}
}
基础解组对象:
@XmlRootElement(name = "GetCityWeatherByZIPResponse",
namespace = "http://ws.cdyne.com/WeatherWS/")
public class GetCityWeatherByZIPResponse {
GetCityWeatherByZIPResult GetCityWeatherByZIPResult;
public GetCityWeatherByZIPResult getGetCityWeatherByZIPResult() {
return GetCityWeatherByZIPResult;
}
public void setGetCityWeatherByZIPResult(GetCityWeatherByZIPResult GetCityWeatherByZIPResult) {
this.GetCityWeatherByZIPResult = GetCityWeatherByZIPResult;
}
@Override
public String toString() {
return "GetCityWeatherByZIPResult: " + GetCityWeatherByZIPResult;
}
}
Sub umarshal object:
public class GetCityWeatherByZIPResult {
boolean Success;
String ResponseText;
String State;
String City;
String WeatherStationCity;
String WeatherID;
String Description;
int Temperature;
int RelativeHumidity;
String Wind;
String Pressure;
String Visibility;
String WindChill;
String Remarks;
public boolean isSuccess() {
return Success;
}
public void setSuccess(boolean success) {
Success = success;
}
public String getResponseText() {
return ResponseText;
}
public void setResponseText(String responseText) {
ResponseText = responseText;
}
public String getState() {
return State;
}
public void setState(String state) {
State = state;
}
public String getCity() {
return City;
}
public void setCity(String city) {
City = city;
}
public String getWeatherStationCity() {
return WeatherStationCity;
}
public void setWeatherStationCity(String weatherStationCity) {
WeatherStationCity = weatherStationCity;
}
public String getWeatherID() {
return WeatherID;
}
public void setWeatherID(String weatherID) {
WeatherID = weatherID;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public int getTemperature() {
return Temperature;
}
public void setTemperature(int temperature) {
Temperature = temperature;
}
public int getRelativeHumidity() {
return RelativeHumidity;
}
public void setRelativeHumidity(int relativeHumidity) {
RelativeHumidity = relativeHumidity;
}
public String getWind() {
return Wind;
}
public void setWind(String wind) {
Wind = wind;
}
public String getPressure() {
return Pressure;
}
public void setPressure(String pressure) {
Pressure = pressure;
}
public String getVisibility() {
return Visibility;
}
public void setVisibility(String visibility) {
Visibility = visibility;
}
public String getWindChill() {
return WindChill;
}
public void setWindChill(String windChill) {
WindChill = windChill;
}
public String getRemarks() {
return Remarks;
}
public void setRemarks(String remarks) {
Remarks = remarks;
}
}
答案 0 :(得分:2)
在namespace
注释上指定@XmlRootElement
属性时,它仅适用于该一个元素。
@XmlRootElement(name = "GetCityWeatherByZIPResponse",
namespace = "http://ws.cdyne.com/WeatherWS/")
public class GetCityWeatherByZIPResponse {
您的XML文档指定了默认命名空间。这意味着没有另一个显式名称空间映射的所有元素也是http://ws.cdyne.com/WeatherWS/
名称空间的一部分。
<?xml version="1.0" encoding="UTF-8"?><GetCityWeatherByZIPResponse xmlns="http://ws.cdyne.com/WeatherWS/">
<GetCityWeatherByZIPResult>
<Success>true</Success>
您将要在包级别指定命名空间映射,以便它适用于所有元素映射。这是使用名为@XmlSchema
的特定类的包级别package-info
注释完成的。
@XmlSchema(
namespace = "http://ws.cdyne.com/WeatherWS/",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
了解更多信息
我在博客上写了更多关于JAXB和名称空间限定的内容:
属性的默认元素与XML不匹配。对于预期元素名称下面的属性,将为getCityWeatherByZIPResult
,因此您需要使用@XmlElement
注释覆盖默认值。
@XmlElement(name="GetCityWeatherByZIPResult")
public GetCityWeatherByZIPResult getGetCityWeatherByZIPResult() {
return GetCityWeatherByZIPResult;
}
当您遇到解组问题时,请填充对象模型并封送它以查看基于当前映射的预期XML。