【问题标题】:JAX-RS: returning concrete class instance from method with declared abstract return typeJAX-RS:从声明抽象返回类型的方法返回具体类实例
【发布时间】:2014-01-11 22:33:31
【问题描述】:

我有一些使用 JAX-RS 和 Jackson 的 REST 服务。我的客户希望将抽象类作为服务的返回类型,但我不知道如何让 JAX-RS 客户端返回具体子类的实例。这对 XML 和 JSON 表示都可能吗?如果是这样,将感谢示例和/或链接。

【问题讨论】:

  • 也许@XmlSeeAlso 也在使用jaxb?
  • 我写了一个测试程序。 @XmlSee也有效。 JSON 怎么样?
  • 如果你在教程中使用 jersey 说 jaxb 适用于 json 和 xml..
  • 不。我正在使用 CXF。还有杰克逊。
  • 试着把你的测试例子(例如junit),如果我有一个清晰的例子,我可以看看。

标签: java xml rest jackson jax-rs


【解决方案1】:

可以尝试添加 JsonTypeInfo 和 JsonSubTypes 注解

@JsonTypeInfo(use = Id.CLASS,
              include = JsonTypeInfo.As.PROPERTY,
              property = "type")
@JsonSubTypes({
    @Type(value = MySubClass.class)
    })
public abstract class MyAbsClass {
....
}
public class MySubClass extends MyAbsClass {
....
}

它应该将类型信息添加到 json 输出。

【讨论】:

    【解决方案2】:

    如果您只想返回一个任意的具体实例,那么在使用基于 Jackson 的提供程序时,这“可以正常工作”。这是带有 DropWizard 的 JSON 的默认设置。唯一可能出现的问题是如果使用普通 Jersey 和基于 JAXB 的提供程序,这可能会将序列化限制为抽象类型公开的 API。

    如果您还需要能够将(在客户端)端反序列化为具体类型,则需要使用 @JsonTypeInfo

    【讨论】:

      【解决方案3】:

      有几种方法可以实现这一点。最简单的方法是使用@JsonTypeInfoas Garry mentioned。您所要做的就是用@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY) 注释您的抽象基类,然后就可以开始了。

      另一种方法是确保服务器端和客户端上的所有映射器都启用了(可能是 NON_FINAL)default typing,以便类型信息在未注释的类上(反)序列化。如果您对开箱即用的序列化功能不满意,可以通过提供您自己的TypeResolverBuilder 来增强这两种方式。可以在in this articleJackson's Polymorphic Type Handling wiki page 上找到这些方法的更详细说明。

      虽然@JsonTypeInfo 方法很简单,但让CXF 服务器/客户端真正工作可能是一件苦差事。所以这里有一个完整的例子:

      import com.fasterxml.jackson.annotation.JsonTypeInfo;
      import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
      import com.fasterxml.jackson.jaxrs.xml.JacksonJaxbXMLProvider;
      import org.apache.cxf.endpoint.Server;
      import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
      import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
      
      import javax.ws.rs.GET;
      import javax.ws.rs.Path;
      import javax.ws.rs.Produces;
      import java.util.Arrays;
      import java.util.Collections;
      import java.util.Random;
      
      import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
      import static javax.ws.rs.core.MediaType.APPLICATION_XML;
      
      public class FullCxfJaxrsJacksonExample {
          public static void main(String[] args) {
              String serverAddress = "http://localhost:9000/";
              Server server = null;
      
              try {
                  // make server that supports JSON and XML
                  JAXRSServerFactoryBean serverFactory = new JAXRSServerFactoryBean();
                  serverFactory.setResourceClasses(ShapeServiceRandom.class);
                  serverFactory.setAddress(serverAddress);
                  serverFactory.setProviders(Arrays.asList(new JacksonJaxbJsonProvider(), new JacksonJaxbXMLProvider()));
                  server = serverFactory.create();
      
                  // make and use a client
                  JAXRSClientFactoryBean clientFactory = new JAXRSClientFactoryBean();
                  clientFactory.setAddress(serverAddress);
                  clientFactory.setServiceClass(ShapeService.class);
                  clientFactory.setProvider(new JacksonJaxbJsonProvider());
                  clientFactory.setHeaders(Collections.singletonMap("Accept", "application/json"));
                  // for an XML client instead of a JSON client, use the following provider/headers instead:
                  //clientFactory.setProvider(new JacksonJaxbXMLProvider());
                  //clientFactory.setHeaders(Collections.singletonMap("Accept", "application/xml"));
      
                  ShapeService shapeServiceClient = clientFactory.create(ShapeService.class);
                  for (int i = 0; i < 10; i++) {
                      System.out.format("created shape: %s\n", shapeServiceClient.create());
                  }
      
              } finally {
                  if (server != null) {
                      server.destroy();
                  }
              }
              System.exit(0);
          }
      
          // Put JsonTypeInfo on the abstract base class so class info gets marshalled.
          // You'll want CLASS instead of MINIMAL_CLASS if your base class and subclasses are in different packages.
          @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY)
          public abstract static class Shape {
          }
      
          public static class Circle extends Shape {
              public double radius;
      
              @Override
              public String toString() {
                  return "Circle{radius=" + radius + '}';
              }
          }
      
          public static class Polygon extends Shape {
              public int numSides;
      
              @Override
              public String toString() {
                  return "Polygon{numSides=" + numSides + '}';
              }
          }
      
          // service definition with abstract return type
          @Path("/shape")
          public interface ShapeService {
              @GET
              @Path("/create")
              @Produces({APPLICATION_JSON, APPLICATION_XML})
              Shape create();
          }
      
          // service implementation that returns different concrete subclasses
          public static class ShapeServiceRandom implements ShapeService {
              Random random = new Random();
      
              public Shape create() {
                  int num = random.nextInt(8);
                  if (num > 3) {
                      Polygon polygon = new Polygon();
                      polygon.numSides = num;
                      return polygon;
                  } else {
                      Circle circle = new Circle();
                      circle.radius = num + 0.5;
                      return circle;
                  }
              }
          }
      }
      

      本示例已使用 JDK 1.8.0_45 和以下依赖项成功测试:

          <dependency>
              <groupId>com.fasterxml.jackson.jaxrs</groupId>
              <artifactId>jackson-jaxrs-json-provider</artifactId>
              <version>2.5.4</version>
          </dependency>
          <dependency>
              <groupId>com.fasterxml.jackson.jaxrs</groupId>
              <artifactId>jackson-jaxrs-xml-provider</artifactId>
              <version>2.5.4</version>
          </dependency>
          <dependency>
              <groupId>org.apache.cxf</groupId>
              <artifactId>cxf-rt-transports-http-jetty</artifactId>
              <version>3.1.1</version>
          </dependency>
          <dependency>
              <groupId>org.apache.cxf</groupId>
              <artifactId>cxf-rt-rs-client</artifactId>
              <version>3.1.1</version>
          </dependency>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多