【问题标题】:Polymorphism with JaxRS and JacksonJaxRS 和 Jackson 的多态性
【发布时间】:2017-11-03 14:23:25
【问题描述】:

我有class Admin extends User {}AdminUser 都扩展了 @XmlRootElement

@XmlRootElement
public class User {
   ....
}

@XmlRootElement
public class Admin extends User {

    String statement;
}

我将此 Json 发送到正确的 JaxRS 服务:

{
    "id": "84",
    "content": "blablah",
    "user": {
        "id": 1,
        "email": "nicolas@robusta.io",
        "name": "Nicolas",
        "male": true,
        "admin": true,
        "statement":"hello world"
    }
}

这里是 Web 服务。评论应该有一个User,但我们这里有一个管理员,它有一个statement 不知道User 的字段。

@POST
@Path("{id}/comments")
public Response createComment(@PathParam("id") long topicId, Comment comment) { ... }

Comment 不被杰克逊接受为Comment,因为它的UserAdmin

@XmlRootElement
public class Comment {
    String id;  
    String content;
    User user = null;
}

我应该如何告诉杰克逊接受任何类型的用户?如何做到与 Java EE 最兼容(即与具有另一个 Json 处理程序的服务器)?

【问题讨论】:

  • 你在评论类中尝试过@XmlElement(name = "user", type = Admin.class)
  • 它并不总是管理员。用户或管理员可以创建评论

标签: java jakarta-ee jackson jax-rs


【解决方案1】:

多态对象的杰克逊方法是在你的 json 中添加一些额外的字段并使用 @JsonTypeInfo 如果你可以将你的 json 更改为类似的东西

"user": {
     "type": "Admin",
     ...
 }

那么你可以简单地使用

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(name = "User", value = User.class),
        @JsonSubTypes.Type(name = "Admin", value = Admin.class)
})
static class User {
    public String id;
}

如果你不能改变你的 json,那么事情就会变得复杂,因为没有默认的方法来处理这种情况,你将不得不编写自定义的反序列化器。基本的简单案例看起来像这样:

public static class PolymorphicDeserializer extends JsonDeserializer<User> {
    ObjectMapper mapper = new ObjectMapper();

    @Override
    public User deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        JsonNode tree = p.readValueAsTree();

        if (tree.has("statement")) // <= hardcoded field name that Admin has
            return mapper.convertValue(tree, Admin.class);

        return mapper.convertValue(tree, User.class);

    }
}

你可以在 ObjectMapper 上注册它

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(User.class, new PolymorphicDeserializer());
mapper.registerModule(module);

或带注释:

@JsonDeserialize(using = PolymorphicDeserializer.class)
class User {
    public String id;
}

【讨论】:

    猜你喜欢
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    • 2017-10-05
    • 2020-05-20
    • 2022-11-25
    • 2016-05-19
    • 2016-01-09
    相关资源
    最近更新 更多