使用泽西岛的 JAX WS RS - 返回集合、地图等



我正在使用泽西岛 2.3

我的 WS 端点类:

@Path("/employees")
public class EmployeeWSEndpoint {
    @Context
    Request request;
    @GET
    @Path("/allEmployees")
    @Produces(MediaType.APPLICATION_JSON)
    public List<Employee> getAllEmployees() {
        System.out.println("In EmployeeWSEndpoint.getAllEmployees()");
        EmployeeService employeeService = new EmployeeServiceImpl();
        return employeeService.getAllEmployees();
    }
    @GET
    @Path("/allDept")
    @Produces(MediaType.APPLICATION_JSON)
    public List<String> getAllDept() {
        System.out.println("In EmployeeWSEndpoint.getAllDept()");
        List<String> deptNames = new ArrayList<>();
        deptNames.add("CoE");
        deptNames.add("iLabs");
        return deptNames;
    }
    @GET
    @Path("/allDeptPOJO")
    @Produces(MediaType.APPLICATION_JSON)
    public TempPOJO getAllDeptPOJO() {
        System.out.println("In EmployeeWSEndpoint.getAllDeptPOJO");
        TempPOJO tempPOJO = new TempPOJO();
        return tempPOJO;
    }
}

员工职位 :

public class Employee {
    private int id;
    private String firstName;
    private String middleName;
    private String lastName;
    private Date dob;
    private int deptId;
    public Employee() {
    }
    public Employee(String firstName, String middleName, String lastName,
            Date dob, int deptId) {
        this.firstName = firstName;
        this.middleName = middleName;
        this.lastName = lastName;
        this.dob = dob;
        this.deptId = deptId;
    }
    public Employee(int id, String firstName, String middleName,
            String lastName, Date dob, int deptId) {
        this.id = id;
        this.firstName = firstName;
        this.middleName = middleName;
        this.lastName = lastName;
        this.dob = dob;
        this.deptId = deptId;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public Date getDob() {
        return dob;
    }
    public void setDob(Date dob) {
        this.dob = dob;
    }
    public int getDeptId() {
        return deptId;
    }
    public void setDeptId(int deptId) {
        this.deptId = deptId;
    }
    @Override
    public String toString() {
        return firstName + " " + middleName + " " + " " + lastName;
    }
}

临时POJO :

public class TempPOJO {
    private List<String> deptNames;
    public List<String> getDeptNames() {
        deptNames = new ArrayList<>();
        deptNames.add("CoE");
        deptNames.add("iLabs");
        return deptNames;
    }
    public void setDeptNames(List<String> deptNames) {
        this.deptNames = deptNames;
    }
}

列出不同方法的输出:

所有员工

[{"deptId":1,"dob":"1978-06-19","firstName":"Garfield","id":0,"lastName":"Arbuckle","middleName":"John"},{"deptId":1,"dob":"1946-07-07","firstName":"John","id":0,"lastName":"Rambo","middleName":"R"}]

/全部部门

In EmployeeWSEndpoint.getAllDept()
Oct 01, 2013 3:31:08 PM org.glassfish.jersey.server.ServerRuntime$Responder mapException
WARNING: WebApplicationException cause:
javax.xml.bind.MarshalException
 - with linked exception:
[Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred marshalling the object
Internal Exception: Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class java.lang.String was not found in the project.  For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.]
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:403)
    at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.writeTo(MOXyJsonProvider.java:808)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:243)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:230)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:149)
    at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:103)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:149)
    at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:88)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:149)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1139)
    at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:562)
    at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:357)
    at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:347)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:258)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:235)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:983)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:359)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred marshalling the object
Internal Exception: Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class java.lang.String was not found in the project.  For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.
    at org.eclipse.persistence.exceptions.XMLMarshalException.marshalException(XMLMarshalException.java:97)
    at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:911)
    at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:848)
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:401)
    ... 41 more
Caused by: Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class java.lang.String was not found in the project.  For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.
    at org.eclipse.persistence.exceptions.XMLMarshalException.descriptorNotFoundInProject(XMLMarshalException.java:139)
    at org.eclipse.persistence.internal.oxm.Context$ContextState.getSession(Context.java:143)
    at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:787)
    at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:1)
    at org.eclipse.persistence.internal.oxm.Context.getSession(Context.java:451)
    at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:356)
    at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:1)
    at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:568)
    at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:1096)
    at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:869)
    ... 43 more

/全部部门

{"deptNames":["CoE","iLabs"]}

我有一些疑问

  1. 我想从泽西岛 2.3 开始,注释"XmlRootElement"对于 POJO 不是必需的 - 我还没有这样做,但调用有效。请确认
  2. 如果 pojo(员工(的列表或具有列表的 pojo,响应是正确的,但对于列表、映射等,它失败了(基本上,对于 Java 类型( - 为什么会这样?如果它适用于员工,为什么它不适用于 Java 类型?是否需要编写 XmlAdapter?

注意:在大多数情况下,我希望以JSON格式响应。

修改网页.xml使用杰克逊:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>Jersey</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
    <servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.ws.jaxrs.jersey</param-value>
        </init-param>
        <init-param>
            <param-name>jersey.config.disableMoxyJson.server</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.ws.jaxrs.jersey;org.codehaus.jackson.jaxrs</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

</web-app>

我得到了以下异常:

In EmployeeWSEndpoint.getAllDept()
Nov 07, 2013 10:04:12 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [Jersey REST Service] in context with path [/Jersey] threw exception [org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/json, type=class java.util.ArrayList, genericType=java.util.List<java.lang.String>.] with root cause
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/json, type=class java.util.ArrayList, genericType=java.util.List<java.lang.String>.
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:227)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:149)
    at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:103)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:149)
    at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:88)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:149)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1139)
    at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:562)
    at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:357)
    at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:347)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:258)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:235)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:983)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:359)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:964)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

杰克逊是目前对我来说最好的解决方案。

要使用 Jackson 作为 JSON 提供程序,您需要将jersey-media-json-jackson模块添加到pom.xml文件中:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.7</version>
</dependency>

注意:自动发现功能不起作用。

启用杰克逊 JSON 功能的构建客户端:

final Client client = ClientBuilder.newBuilder()
                    .register(JacksonFeature.class)
                    .build();

创建启用了 Jackson JSON 功能的 JAX-RS 服务器应用程序:

final Application application = new ResourceConfig()
                              .packages("my.rest.package")
                              .register(JacksonFeature.class);

另请查看官方泽西岛 json-jackson 示例。

使用不同的 JSON 提供程序

我不知道为什么 jersey startet 采用 MOXy 作为他们的默认 JSON 提供程序,但这显然是一个坏主意。

您(和我 - 以及其他人(遇到的问题是 MOXy beeing 无法映射简单 Java 类型(如字符串(的集合的结果 - 恕我直言,这简直是荒谬的。其他提供商(如杰克逊(没有这个问题,因此切换肯定会有所帮助。

这是我所做的:

  1. 告诉泽西岛不要使用MOXy。将此添加到您的网络.xml:

    <init-param>
        <param-name>jersey.config.disableMoxyJson.server</param-name>
        <param-value>true</param-value>
    </init-param>
    
  2. 将杰克逊添加到您的pom中。像这样的事情可以:

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-jaxrs</artifactId>
        <version>1.9.12</version>
    </dependency>
    
  3. 告诉球衣扫描杰克逊杰克逊包裹。它将查找(并使用(杰克逊提供的 json 提供程序:

    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>com.example.your.package;org.codehaus.jackson.jaxrs</param-value>
    </init-param>
    

注意:我是 EclipseLink JAXB (MOXy( 的负责人,也是 JAXB (JSR-222( 专家组的成员。

您遇到的异常是由于MOXy MOXyJsonProvider中的错误。 MOXyJsonProvider是 JAX-RS 接口MessageBodyReader/MessageBodyWriter 的实现。 我已将isWriteable方法更改为返回 false,以便List<String>返回 false,以便另一个提供程序可以处理它。

我还打开了以下增强请求,以将此支持添加到 MOXy:

  • http://bugs.eclipse.org/417725

您可以使用 RestEasy 作为 JAX-RS 实现

GlassFish4使用Jersey/MOXy作为JAX-RS的实现。他们在将简单 Java 类型(如字符串(的集合映射到 JSON 时遇到问题 - https://bugs.eclipse.org/bugs/show_bug.cgi?id=417723

WildFly 和 JBoss 使用 RestEasy/Jackson 作为 JAX-RS 的实现,映射没有问题。

你可以在任何Java应用程序服务器中使用RestEasy而不是Jersey,例如WildFly(JBoss(,GlassFish或Tomcat。

只需替换:

    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>

跟:

    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-servlet-initializer</artifactId>
        <version>3.0.7.Final</version>
        <scope>compile</scope>
    </dependency>        
    <dependency>
       <groupId>org.jboss.resteasy</groupId>
       <artifactId>resteasy-jaxrs</artifactId>
       <version>3.0.7.Final</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson-provider</artifactId>
        <version>3.0.7.Final</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxb-provider</artifactId>
        <version>3.0.7.Final</version>
        <scope>compile</scope>
    </dependency>

它对我有用。

最好的问候从卢布林在波兰:)

我在返回List<String>对象时遇到了同样的问题。我把它包装在一个RestStringList类中,这很有效。如果我们有更多的事情要做,我可能会转向杰克逊。

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class RestStringList implements Serializable {
    private static final long serialVersionUID = 1L;
    private List<String> stringList = null;
    public RestStringList() {
        this.stringList = new ArrayList<String>();
    }
    public void setStringList(List<String> stringList) {
        this.stringList = new ArrayList<String>(stringList);
    }
    public List<String> getStringList() {
        return stringList;
    }
    public String toString() {
        return "{ strings=" + stringList + " }";
    }
}

最新更新