我是Spring集成的新手,也是我的项目需求。我面临以下问题,将Pojo(java对象)编入SOAP响应(使用Spring集成ws):请找到相同的以下详细信息:
我有以下示例xsd文件:
</xsd:element>
<xsd:element name="MyUserResponses">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="unbounded" name="MyUserResponse"
type="tns:MyUserResponse" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="MyUserResponse">
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="1" name="SomeNumber" type="xsd:string"/>
<xsd:element minOccurs="0" maxOccurs="1" name="ReferenceID" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
我使用xjc编译器创建了以下java对象文件:
package com.myuser.echannel;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="SomeNumber" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="ReferenceID" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"someNumber",
"referenceID"
})
@XmlRootElement(name = "MyUserRequest")
public class MyUserRequest {
@XmlElement(name = "SomeNumber")
protected String someNumber;
@XmlElement(name = "ReferenceID")
protected String referenceID;
/**
* Gets the value of the someNumber property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getSomeNumber() {
return someNumber;
}
/**
* Sets the value of the someNumber property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setSomeNumber(String value) {
this.someNumber = value;
}
/**
* Gets the value of the referenceID property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getReferenceID() {
return referenceID;
}
/**
* Sets the value of the referenceID property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setReferenceID(String value) {
this.referenceID = value;
}
}
另一个Java对象:
package com.myuser.echannel;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for MyUserResponse complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="MyUserResponse">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="SomeNumber" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="ReferenceID" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MyUserResponse", propOrder = {
"someNumber",
"referenceID"
})
public class MyUserResponse {
@XmlElement(name = "SomeNumber")
protected String someNumber;
@XmlElement(name = "ReferenceID")
protected String referenceID;
/**
* Gets the value of the someNumber property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getSomeNumber() {
return someNumber;
}
/**
* Sets the value of the someNumber property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setSomeNumber(String value) {
this.someNumber = value;
}
/**
* Gets the value of the referenceID property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getReferenceID() {
return referenceID;
}
/**
* Sets the value of the referenceID property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setReferenceID(String value) {
this.referenceID = value;
}
}
MyUserResponses.java文件如下:
package com.myuser.echannel;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="MyUserResponse" type="{http://tempuri.org/}MyUserResponse" maxOccurs="unbounded" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"myUserResponse"
})
@XmlRootElement(name = "MyUserResponses")
public class MyUserResponses {
@XmlElement(name = "MyUserResponse")
protected List<MyUserResponse> myUserResponse;
/**
* Gets the value of the myUserResponse property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the myUserResponse property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getMyUserResponse().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link MyUserResponse }
*
*
*/
public List<MyUserResponse> getMyUserResponse() {
if (myUserResponse == null) {
myUserResponse = new ArrayList<MyUserResponse>();
}
return this.myUserResponse;
}
}
对象工厂:
package com.myuser.echannel;
import javax.xml.bind.annotation.XmlRegistry;
/**
* This object contains factory methods for each
* Java content interface and Java element interface
* generated in the com.myuser.echannel package.
* <p>An ObjectFactory allows you to programatically
* construct new instances of the Java representation
* for XML content. The Java representation of XML
* content can consist of schema derived interfaces
* and classes representing the binding of schema
* type definitions, element declarations and model
* groups. Factory methods for each of these are
* provided in this class.
*
*/
@XmlRegistry
public class ObjectFactory {
/**
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.myuser.echannel
*
*/
public ObjectFactory() {
}
/**
* Create an instance of {@link MyUserResponses }
*
*/
public MyUserResponses createMyUserResponses() {
return new MyUserResponses();
}
/**
* Create an instance of {@link MyUserResponse }
*
*/
public MyUserResponse createMyUserResponse() {
return new MyUserResponse();
}
/**
* Create an instance of {@link MyUserRequest }
*
*/
public MyUserRequest createMyUserRequest() {
return new MyUserRequest();
}
}
package-info.java文件:
@javax.xml.bind.annotation.XmlSchema(namespace = "http://tempuri.org/", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.myuser.echannel;
我正在使用下面的请求主体处理SOAP请求到我的spring集成层(下面是web.xml和spring上下文文件):
的web.xml:
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring-ws-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
spring-ws-config.xml文件:
<context:component-scan base-package="com.nbad.eChannel"/>
<import resource="classpath:/WEB-INF/inbound-gateway-config.xml"/>
<!-- Ensures that all incoming requests will be routed to the ws:inbound-gateway -->
<!-- <bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
<property name="defaultEndpoint" ref="ws-inbound-gateway"/>
</bean> -->
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop key="{http://tempuri.org/}MyUserRequest">ws-myuser-gateway</prop>
</props>
</property>
</bean>
</beans>
<context:component-scan base-package="com.mypackage"/>
<import resource="classpath:/com/mypackage/si/jdbc/config/spring-integration-context.xml"/>
<int:channel id="FFUserRequestChannel"/>
<int-ws:inbound-gateway id="ws-ffuser-gateway" request-channel="FFUserRequestChannel" marshaller="marshaller" unmarshaller="marshaller"/>
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="com.mypackage.model" />
</bean>
<int:service-activator input-channel="MyUserRequestChannel">
<bean class="com.mypackage.serviceImpl.MyUserImpl">
<constructor-arg ref = "MyUserRequest"></constructor-arg>
</bean>
</int:service-activator>
<bean id="MyUserRequest" class="com.mypackage.model.MyUserRequest"></bean>
<bean id="MyUserResponse" class="com.mypackage.model.MyUserResponse"></bean>
</beans>
如上所述,我使用Jaxb2Marshaller进行编组和解组。现在serviceImpl文件如下:
package com.mypackage.serviceImpl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import com.mypackage.model.*;
import com.mypackage.service.MyUser;
import com.mypackage.si.jdbc.service.MyUserJdbc;
/**
* @author Vinay Agrawal
*/
public class MyUserImpl implements MyUser{
@Autowired
MyUserRequest request;
@Autowired
MyUserJdbc MyUserJdbc;
public MyUserImpl() {
}
public MyUserImpl(MyUserRequest request) {
super();
this.request = request;
}
@Override
@PayloadRoot(localPart = "issueResponseFor" , namespace = "http://tempuri.org/")
@ResponsePayload
public List<MyUserResponse>issueResponseFor(@RequestPayload MyUserRequest request) {
List<MyUserResponse> MyUserResponse = new ArrayList<MyUserResponse>();
MyUserResponse = (List<MyUserResponse>)MyUserJdbc.getMyUserResponse(request);
return MyUserResponse;
}
}
这里我调用DB层并从DB获取MyUserResponse(多个记录)的List并使用spring integration marshaller Jaxb2Marshaller,我希望这会将java对象编组为soap响应,并且应该在SOAPUI中为MyUserResponse显示此列表名单。但我在SOAP UI和Junit上得到以下错误:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring xml:lang="en">Unknown JAXB exception; nested exception is javax.xml.bind.JAXBException: class java.util.ArrayList nor any of its super class is known to this context.</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Junit生成错误:
org.springframework.ws.soap.client.SoapFaultClientException:未知的JAXB异常;嵌套异常是javax.xml.bind.JAXBException:类java.util.ArrayList,它的任何超类都不为此上下文所知。 在org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:37) 在org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:776) 在org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:602) 在org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:539) 在org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:494) 在org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:438) 在org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:423) 在com.nbad.eChannel.Common.InContainerTests.testWebServiceRequestAndResponse(InContainerTests.java:44) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) 在org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:47) 在org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 在org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 在org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 在org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 在org.junit.runners.ParentRunner $ 3.run(ParentRunner.java:238) 在org.junit.runners.ParentRunner $ 1.schedule(ParentRunner.java:63) 在org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 在org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:53) 在org.junit.runners.ParentRunner $ 2.evaluate(ParentRunner.java:229) 在org.junit.runners.ParentRunner.run(ParentRunner.java:309) 在org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 在org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
我的SOAP请求如下:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<sch:MyUserRequest>
<sch:SomeNumber>8009618916</sch:SomeNumber>
<sch:ReferenceID>ReferenceIDReferenceID</sch:ReferenceID>
</sch:MyUserRequest>
</soapenv:Body>
</soapenv:Envelope>
如果我在xsd文件中进行了更改以获取单个记录以及创建的java对象文件中的相应更改,但是在尝试获取多个记录响应时面临问题,我再次收到正确的响应(一条记录)。
请帮助我找到我在做错误或遗失的地方。
答案 0 :(得分:3)
从我得到的链接中引用:
发生上述异常是因为JAXB总是期望实体上有@XmlRootElement注释,它会被编组。这是强制性的,不能跳过。需要此@XmlRootElement注释才能从XML对象编组的XML的根元素获取元数据。 ArrayList类或任何java集合类都没有任何JAXB注释。由于这个原因,JAXB无法解析任何此类java对象并引发此错误。
似乎您的MyUserResponse
没有@XMLRootElement
注释。
答案 1 :(得分:1)
这对我有用:
javax.xml.bind.JAXBException: Class *** nor any of its super class is known to this context
只需在响应类中添加XmlSeeAlso
注释:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"myUserResponse"})
@XmlRootElement(name = "MyUserResponses")
@XmlSeeAlso(ArrayList.class)
public class MyUserResponses {
@XmlElement(name = "MyUserResponse")
protected List<MyUserResponse> myUserResponse;
...
答案 2 :(得分:1)
我遇到了同样的问题,你可以检查这样的代码行:
jaxbMarshaller.marshal(obj,sw);
- 确保obj不是收藏品
- obj是反映XML root的父类
希望这有帮助!
答案 3 :(得分:0)
我有类似的问题,我使用CXF生成了存根。我得到了类似的错误,在分析中我发现我创建的列表有一些null
值导致它。我用空字符串替换了空值。我的代码如下所示使用Java 8.如果我启用了注释的代码行,我得到 java.util.ArrayList,它的任何超类都不知道这个上下文异常。
希望这会对某人有所帮助。
model.keySet().forEach( val ->{
TestRequest.Param param = new Param();
param.setKey(val);
param.setValue(model.get(val) != null ?model.get(val).toString():""); //works fine
//below line has caused the issue
//param.setValue(model.get(val));
request.getParam().add(param);// this is the list on my request
});