REST Webサービスを介してオブジェクトを渡そうとしています。以下は、いくつかのサンプルコードを使用して必要な機能を説明するクラスです。
Rest Web Service Classメソッド
@POST
@Path("/find")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces({MediaType.APPLICATION_JSON})
public Response getDepartments(){
Response response = new Response();
try {
response.setCode(MessageCode.SUCCESS);
response.setMessage("Department Names");
Department dept = new Department("12", "Financial");
response.setPayload(dept);
} catch (Exception e) {
response.setCode(MessageCode.ERROR);
response.setMessage(e.getMessage());
e.printStackTrace();
}
return response;
}
応答クラス
import Java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Response implements Serializable{
private static final long serialVersionUID = 1L;
public enum MessageCode {
SUCCESS, ERROR, UNKNOWN
}
private MessageCode code;
private String message;
private Object payload;
public MessageCode getCode() {
return code;
}
public void setCode(MessageCode code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getPayload() {
return payload;
}
public void setPayload(Object payload) {
this.payload = payload;
}
}
部門クラス
@XmlRootElement
public class Department implements Java.io.Serializable {
private String deptNo;
private String deptName;
public Department() {
}
public Department(String deptNo, String deptName) {
this.deptNo = deptNo;
this.deptName = deptName;
}
public String getDeptNo() {
return this.deptNo;
}
public void setDeptNo(String deptNo) {
this.deptNo = deptNo;
}
public String getDeptName() {
return this.deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}
残りのWebサービスクラスでgetDepartmentsメソッドを呼び出すと、次の例外が返されます。ただし、ResponseクラスでpayloadのObjectをDepartmentに変更すると、json応答が正しく返されます。しかし、さまざまなタイプのクラスにこのResponseクラスを使用する必要があるため、ペイロードを1つのクラスタイプに再ストリング化することはできません。誰でもこの問題で私を助けてくれますか?
スタックトレース
Dec 27, 2012 9:34:18 PM com.Sun.jersey.spi.container.ContainerResponse logException
SEVERE: Mapped exception to response: 500 (Internal Server Error)
javax.ws.rs.WebApplicationException: javax.xml.bind.MarshalException
- with linked exception:
[javax.xml.bind.JAXBException: class Department nor any of its super class is known to this context.]
at com.Sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.Java:159)
at com.Sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.Java:306)
at com.Sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.Java:1437)
at com.Sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.Java:1349)
at com.Sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.Java:1339)
at com.Sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.Java:416)
at com.Sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.Java:537)
at com.Sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.Java:699)
at javax.servlet.http.HttpServlet.service(HttpServlet.Java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.Java:511)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.Java:401)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.Java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.Java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.Java:766)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.Java:450)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.Java:152)
at org.mortbay.jetty.Server.handle(Server.Java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.Java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.Java:945)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.Java:756)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.Java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.Java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.Java:410)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.Java:582)
Caused by: javax.xml.bind.MarshalException
- with linked exception:
[javax.xml.bind.JAXBException: class Department nor any of its super class is known to this context.]
at com.Sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.Java:323)
at com.Sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.Java:177)
at com.Sun.jersey.json.impl.BaseJSONMarshaller.marshallToJSON(BaseJSONMarshaller.Java:103)
at com.Sun.jersey.json.impl.provider.entity.JSONRootElementProvider.writeTo(JSONRootElementProvider.Java:136)
at com.Sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.Java:157)
... 23 more
Caused by: javax.xml.bind.JAXBException: class Department nor any of its super class is known to this context.
at com.Sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.Java:250)
at com.Sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.Java:265)
at com.Sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.Java:657)
at com.Sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.Java:156)
at com.Sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.Java:344)
at com.Sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.Java:597)
at com.Sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.Java:328)
at com.Sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.Java:498)
at com.Sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.Java:320)
... 27 more
Caused by: javax.xml.bind.JAXBException: class Department nor any of its super class is known to this context.
at com.Sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.Java:611)
at com.Sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.Java:652)
... 33 more
JAX-RS実装は、検出可能なJAXBアノテーションに基づいてクラスのマーシャリング/アンマーシャリングを自動的にサポートしますが、ペイロードがObject
として宣言されているため、作成されたJAXBContext
がDepartment
クラスを失い、マーシャリングする時期がわからないと思います。
迅速で汚い修正は、応答クラスに XmlSeeAlso
注釈を追加することです。
@XmlRootElement
@XmlSeeAlso({Department.class})
public class Response implements Serializable {
....
または、もう少し複雑なことは、Response
を使用してContextResolver
クラスのJAXBコンテキストを「豊かにする」ことです。
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
@Provider
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class ResponseResolver implements ContextResolver<JAXBContext> {
private JAXBContext ctx;
public ResponseResolver() {
try {
this.ctx = JAXBContext.newInstance(
Response.class,
Department.class
);
} catch (JAXBException ex) {
throw new RuntimeException(ex);
}
}
public JAXBContext getContext(Class<?> type) {
return (type.equals(Response.class) ? ctx : null);
}
}
私は同じ問題を抱えており、Jaxb2marshallerに探索するパッケージを追加することで解決しました。春には、次のようなBeanを定義します。
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
String[] packagesToScan= {"<packcge which contain the department class>"};
marshaller.setPackagesToScan(packagesToScan);
return marshaller;
}
この方法により、すべての要求クラスと応答クラスが同じパッケージにある場合、JAXBcontextでクラスを具体的に示す必要はありません
この例外は、完全なクラスパスを指定することで解決できます。
例:
ExceptionDetails
という名前のクラスを使用している場合
引数を渡す間違った方法
JAXBContext jaxbContext = JAXBContext.newInstance(ExceptionDetails.class);
引数を渡す正しい方法
JAXBContext jaxbContext = JAXBContext.newInstance(com.tibco.schemas.exception.ExceptionDetails.class);
JAXBリファレンス実装とJBoss AS 7.1を使用して同様の問題が発生しました。 JAXBがJBoss環境の外で機能することを確認する統合テストを作成できました(問題はJBossのクラスローダーである可能性があることを示唆しています)。
これはエラーを与えていたコードです(つまり、動作していません):
private static final JAXBContext JC;
static {
try {
JC = JAXBContext.newInstance("org.foo.bar");
} catch (Exception exp) {
throw new RuntimeException(exp);
}
}
これが機能したコードです(ValueSetは、私のXMLからマーシャリングされたクラスの1つです)。
private static final JAXBContext JC;
static {
try {
ClassLoader classLoader = ValueSet.class.getClassLoader();
JC = JAXBContext.newInstance("org.foo.bar", classLoader);
} catch (Exception exp) {
throw new RuntimeException(exp);
}
}
場合によっては、クラスを取得しましたが、このコンテキストではそのスーパークラスは認識されていません。他の場合には、org.foo.bar.ValueSetをorg.foo.bar.ValueSetにキャストできないという例外もあります(ここで説明する問題と同様: 同じクラスにキャストするときのClassCastException ) 。
1つのアプリケーションをサポートするときに、同様のエラーに直面していました。 SOAP Webサービス用に生成されたクラスに関するものでした。
この問題は、クラスが欠落しているために発生しました。 javax.xml.bind.Marshallerがjaxbオブジェクトをマーシャリングしようとしたときに、wsdlおよびxsdによって生成された後のすべての依存クラスが見つかりませんでした。クラスパス内のすべてのクラスを含むjarを追加すると、問題は解決しました。
私はそれが古い質問であることを知っていますが、パラメーター(P)を使用して応答を変更できます:
public class Response<P> implements Serializable{
private static final long serialVersionUID = 1L;
public enum MessageCode {
SUCCESS, ERROR, UNKNOWN
}
private MessageCode code;
private String message;
private P payload;
...
public P getPayload() {
return payload;
}
public void setPayload(P payload) {
this.payload = payload;
}
}
メソッドは
public Response<Departments> getDepartments(){...}
今は試すことができませんが、うまくいくはずです。
それ以外の場合は、Responseを拡張することができます
@XmlRootElement
public class DepResponse extends Response<Department> {<no content>}
Ftrujilloの答え はうまく機能しますが、スキャンするパッケージが1つしかない場合は、これが最も短い形式です::
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("your.package.to.scan");
return marshaller;
}
たとえば、Jaxb2Marshallerに同じメソッド名を使用すると、このエラーが発生します。
@Bean
public Jaxb2Marshaller marshallerClient() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
// this package must match the package in the <generatePackage> specified in
// pom.xml
marshaller.setContextPath("library.io.github.walterwhites.loans");
return marshaller;
}
そして他のファイル
@Bean
public Jaxb2Marshaller marshallerClient() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
// this package must match the package in the <generatePackage> specified in
// pom.xml
marshaller.setContextPath("library.io.github.walterwhites.client");
return marshaller;
}
たとえ異なるクラスであっても、異なる名前を付ける必要があります