当前位置: 首页 > 知识库问答 >
问题:

Jersey解析JSON/Jackson子类型反序列化的规则

闾丘书
2023-03-14

臣接孙氏道:

@POST
@Path("log")
public Map<String, List<OperationResult>> log(Stats stats) {
  ..
}
{
  "eventType": 1
  "params": {
    "field1" : 10
  }
}

{
  "eventType": 2
  "params": {
    "field2" : "ten"
  }
}
interface Params;
class Params1 implements Params{ public int field1; }
class Params2 implements Params{ public String field2; }

class Stats {
  public int eventType;
  public Params params;
}

我如何使Jersey解析JSONs,以便如果eventType=1,那么stats.params变成Params1的实例,而else变成params2的实例?

共有1个答案

司寇羽
2023-03-14

今天早上我花了点时间来解决这个问题。一个有趣的用途。我想出了如何做到这一点,但我必须稍微更改您的json。这并不是绝对必要的,但是类型转换不是您问题的一部分,因此如果需要,我们可以执行后续操作:)

您的JSON:

artur@pandaadb:~/tmp/test$ cat 1.json 
{
  "eventType": "1",
  "params": {
    "field1" : 10
  }
}
artur@pandaadb:~/tmp/test$ cat 2.json 
{
  "eventType": "2",
  "params": {
    "field2" : "10"
  }
}

我正在使用这两个文件来执行请求。注意,我将eventType t改为字符串而不是数字。我稍后会指出这点。

public class Stats {

    @JsonProperty
    int eventType;


    public Params params;

    @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.EXTERNAL_PROPERTY, property="eventType")
    @JsonSubTypes({ @Type(value = Param1.class, name = "1"), @Type(value = Param2.class, name = "2") })
    public void setParams(Params params) {
        this.params = params;
    }
}
JsonTypeInfo.Id.NAME 
JsonTypeInfo.As.EXTERNAL_PROPERTY 
property="eventType" 

只是告诉jackson要使用什么属性名称

然后在JsonSubTypes中注释可能的选项,在您的示例中为2:

@Type(value = Param1.class, name = "1") 

这告诉jackson在eventType属性为“1”的情况下使用param1.class。

注这就是我稍微更改json的原因。子类型批注不能将整数作为属性。现在,您可以使用不同的选项,例如TypeConverters,它在运行时将您的integer属性转换为string,这样您就可以保持json不变。我跳过了这一步,一个快速的谷歌会给你如何做到这一点的指导。

现在您的参数模型如下所示:

public interface Params {

    public static class Param1 implements Params {
        @JsonProperty
        int field1;
    }

    public static class Param2 implements Params {

        @JsonProperty
        String field2;
    }

}

我正在注释这些属性以便杰克逊知道去序列化那些。

JsonTypeInfo.As.EXTERNAL_PROPERTY
JsonTypeInfo.As.EXISTING_PROPERTY

最后是测试:

artur@pandaadb:~/tmp/test$ curl -XPOST  "localhost:8085/api/v2/test" -d @1.json -H "Accept: application/json" -H "Content-Type: application/json"
io.gomedia.resource.Params$Param1
artur@pandaadb:~/tmp/test$ 
artur@pandaadb:~/tmp/test$ curl -XPOST  "localhost:8085/api/v2/test" -d @2.json -H "Accept: application/json" -H "Content-Type: application/json"
io.gomedia.resource.Params$Param2

请注意,资源正在打印实例化类的名称。正如您所看到的,这两个json都被反序列化到了正确的实例类中。

我希望这会有所帮助:)

但是,为了完整起见,如果您需要一个转换器(因为您可能需要它将字符串模型转换回一个整数以进行序列化),这将是一个整数到字符串转换器:

public class EventTypeConverter implements Converter<Integer, String>{

    @Override
    public String convert(Integer value) {
        return String.valueOf(value);
    }

    @Override
    public JavaType getInputType(TypeFactory typeFactory) {
        return SimpleType.construct(Integer.class);
    }

    @Override
    public JavaType getOutputType(TypeFactory typeFactory) {
        return SimpleType.construct(String.class);
    }

}

您可以通过执行以下操作来使用它:

@JsonProperty
@JsonDeserialize(converter=EventTypeConverter.class)
String eventType;
 类似资料:
  • 好的,我知道有一堆类似的问题,但似乎都行不通。 我为我的实体设置了以下结构。 在我的控制器中,我尝试将一个请求映射到下面的方法。 请尝试%1 我认为它是这样做的--添加了一个元数据属性,该属性将存储子类类。 结果是什么。 结果是什么。 即使将和添加到这两个子类中,也会得到相同的结果。 其他尝试 我试了很多。什么都不起作用。不会包含这里的所有内容。 我觉得应该有一个简单的方法来做到这一点,但我只是不

  • 问题内容: 我正在尝试制作一个使用Jackson来反序列化POJO的类。 看起来像这样… 我对此实施有2个问题。 首先是我将类类型传递给方法,以便对象映射器知道应反序列化的类型。有使用泛型的更好方法吗? 同样在get方法中,我将一个从objectMapper返回的对象强制转换为T。这看起来特别讨厌,因为我必须在此处强制转换T,然后还必须从调用它的方法中强制转换对象类型。 我在该项目中使用了Robo

  • 我看过jackson反序列化@JsonTypeInfo的一个例子,那就是: 我试过了,效果很好。现在的问题是,在示例类中,Cat和Dog是从Animal中引用的,我想避免这种情况。有没有一种方法可以将类型绑定从类动物中移除,并且仍然进行反序列化工作?谢谢

  • 假设我有以下格式的JSON: 我试图避免自定义反序列化程序,并试图将上述JSON(称为Wrapper.java)反序列化为JavaPOJO。“type”字段指示“object”反序列化,即type=foo表示使用foo.java反序列化“object”字段。(如果type=Bar,则使用Bar.java反序列化对象字段)。Metadata/owner将始终以相同的方式对每个元数据使用简单的带Jac

  • 在下面的示例中,我有一个主类-A和它的子类-B。两者都可以用作一般类X中的属性。 如何使用Jackson多态特性将以下给定的json正确反序列化为各自的类: JSON A: JSON B: 预期结果:将keys对象映射到JSON A的类A和JSON B的类B。 请提出其他建议。