【问题标题】:@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) not working when Response is returned@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 在返回响应时不起作用
【发布时间】:2012-11-28 08:49:32
【问题描述】:

我正在使用 Jersey 编写一个 REST 服务。我有一个带有注释的抽象类 Promotion:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)

多亏了这一点,当我返回一个对象列表时:

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("promotions/")
public List<Promotion> getClosestPromotions() {
List<Promotion> promotions = getPromotions(); //here I get some objects

return promotions;
}

我为该列表中的每个对象获得了一个带有“@class”字段的 Json 字符串。但问题是,如果我返回一个响应:

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("promotions/")
public Response getClosestPromotions() {
List<Promotion> promotions = getPromotions(); //here I get some objects

return Response.ok().entity(promotions).build();
}

我得到了几乎相同的列表,但没有额外的“@class”字段。 为什么会这样,我该怎么做才能得到一个带有“@class”字段的列表,在响应中返回一个列表? 顺便说一句,令人惊讶的是,当我返回一个仅作为实体给出的 Promotion 对象的 Response 并且我得到那个“@class”字段时,它就起作用了。

【问题讨论】:

  • 我还没有足够的答案,但是。实体方法接受一个对象。底层代码可能会在运行时检查类型以恢复类型信息。不幸的是,这将得到它,而不是 List。它把它写成一个没有泛型类型信息的列表,因此你会丢失类字段。编写一个将列表作为成员变量的对象可能会起作用,但我正试图想出一些更干净的东西。

标签: java json rest jersey jackson


【解决方案1】:

如果您使用 JAXB 生成类,您当然可以使用不同类型的 @XmlElements 之类的东西来解析列表。

现在,如果您还使用与 Jersey/Jackson 相同的 JAXB 类,您可以通过添加 @JsonTypeInfo 和 @JsonSubTypes 来描述如何格式化对象列表/数组的名称来增强类的元数据。

@JsonTypeInfo 描述了要添加的类型,@JsonSubTypes 提供了封闭集合的选项。例如,As.PROPERTY 定义输出的属性,如下例所示,其中可以具有不同类型元素的实体列表,包括类型本身(“Form”)以及 2 种其他类型“字段”和“表”。

public class Form {

  @XmlElements({
    @XmlElement(name = "field", type = Field.class),
    @XmlElement(name = "form", type = Form.class),
    @XmlElement(name = "table", type = Table.class)
  })
  @JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "obj")
  @JsonSubTypes({
    @JsonSubTypes.Type(value = Field.class),
    @JsonSubTypes.Type(value = Form.class),
    @JsonSubTypes.Type(value = Table.class)
  })
  @Generated(value = "com.sun.tools.internal.xjc.Driver", date = "2013-11-11T02:08:36-08:00", comments = "JAXB RI v2.2.4-2")
  @JsonProperty("entities")
  protected List<Object> fieldOrFormOrTable;

使用带有添加元数据的 Jersey 的 Jackson 默认序列化程序对对象进行序列化将如下...

     "entities": [
                  {
                    "obj": "Table",
                    "row": {
                        "id": 1,
                        "fields": [
                            {
                                "id": "DEBUGARY",
                                "type": "Text",
                                "kind": "user"
                            }
                        ]
                    },
                    "id": "DBGARRAY"
                },
                {
                    "obj": "field",
                    "id": "IDBG",
                    "type": "Text",
                    "kind": "user"
                },
        ..., ..., ...]

【讨论】:

    【解决方案2】:

    尝试添加子类型注释,这是我正在使用的示例。这可以通过指定所有可操作的子类型来解决您的问题。抱歉没有测试你的确切例子。

    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
    @JsonSubTypes({
        @JsonSubTypes.Type(value=MetricCollection.class),
        @JsonSubTypes.Type(value=Column.class),
        @JsonSubTypes.Type(value=IntegerColumn.class),
        @JsonSubTypes.Type(value=DoubleColumn.class),
        @JsonSubTypes.Type(value=StringColumn.class)
    })
    public interface IMetricCollection<T extends IMetric> {
    ...
    }
    

    【讨论】:

    • 你知道为什么它可以解决问题吗?
    【解决方案3】:

    也许你想试试:

    GenericEntity<Collection<Promotion>> genericEntity = 
               new GenericEntity<Collection<Promotion>>(promotions){};
    return Response.ok().entity(genericEntity).build();
    

    【讨论】:

    • 这是一个简单的解决方案,效果很好,谢谢分享!唯一的缺点是我们必须记住始终以这种方式包装我们的集合。
    猜你喜欢
    • 2016-03-08
    • 2019-01-04
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 2019-10-11
    • 1970-01-01
    • 2010-11-27
    • 1970-01-01
    相关资源
    最近更新 更多