22

我有以下课程:

public class Message {
    private String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }    
}

默认情况下,使用 Jackson 将实例转换为 JSON 时,我得到:

{"text":"Text"}

我想得到:

{"message":{"text":"Text"}}

我可以使用任何 JAXB / Jackson 注释来实现我的目标吗?

作为一种解决方法,我可以用另一个类包装我的类:

public class MessageWrapper {
    private Message message;

    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }
}

或更通用的解决方案:

public class JsonObjectWrapper<T> {
    /**
     * Using a real map to allow wrapping multiple objects
     */
    private Map<String, T> wrappedObjects = new HashMap<String, T>();

    public JsonObjectWrapper() {
    }

    public JsonObjectWrapper(String name, T wrappedObject) {
        this.wrappedObjects.put(name, wrappedObject);
    }

    @JsonAnyGetter
    public Map<String, T> any() {
        return wrappedObjects;
    }

    @JsonAnySetter
    public void set(String name, T value) {
        wrappedObjects.put(name, value);
    }
}

可以这样使用:

Message message = new Message();
message.setText("Text");
JsonObjectWrapper<Message> wrapper = new JsonObjectWrapper<Message>("message", message);

我可以使用任何 JAXB / Jackson 注释来实现我的目标吗?

谢谢。

4

7 回答 7

24

使用 Jackson 2.x 可以使用以下内容来启用包装器,而无需在 ObjectMapper 中添加其他属性

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;

@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
@JsonTypeName(value = "student")
public class Student {
  private String name;
  private String id;
}
于 2019-03-03T09:04:19.113 回答
15

关于解决方法:您并不绝对需要那些 getter/setter,所以可以:

public class MessageWrapper {
  public Message message;
}

或者添加便利构造函数:

public class MessageWrapper {
  public Message message;
  @JsonCreator
  public MessageWrapper(@JsonProperty("message") Message m) { 
       message = m; 
  }
}

还有一种方法可以添加包装;在 1.9 中,您可以使用SerializationConfig.Feature.WRAP_ROOT_ELEMENTDeserializationConfig.Feature.UNWRAP_ROOT_ELEMENT。如果要更改包装器名称(默认情况下它只是不合格的类名),可以使用@JsonRootName注解

Jackson 2.0 通过ObjectReaderObjectWriter以及 JAX-RS 注释添加了更多动态选项。

于 2012-05-30T01:54:28.340 回答
4

得知您必须为使用标记对象包装类的简单目标而编写自定义序列化,这令人难过。在尝试编写自定义序列化程序后,我得出结论,最简单的解决方案是通用包装器。这可能是您上面示例的更简单的实现:

public final class JsonObjectWrapper {
    private JsonObjectWrapper() {}

    public static <E> Map<String, E> withLabel(String label, E wrappedObject) {
        HashMap<String, E> map = new HashMap<String, E>();
        map.put(label, wrappedObject);
        return map;
    }
}
于 2014-01-22T16:42:48.860 回答
3

如果您不介意 json 大写min message,那么最简单的方法是使用@JsonTypeInfo.

你会添加:

@JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME)
public class Message {
  // ...
}

要得到{"Message":{"text":"Text"}}

于 2017-01-06T13:59:54.750 回答
1

如果使用弹簧,则在application.properties文件中添加以下内容:-

spring.jackson.serialization.WRAP_ROOT_VALUE=true

然后@JsonRootName在您希望序列化的任何类上使用注释。例如

@JsonRootName("user")
public class User {
    private String name;
    private Integer age;
}
于 2018-02-03T15:36:02.150 回答
1

一种更简单/更好的方法:

@JsonRootName(value = "message")
public class Message { ...}

然后使用
new ObjectMapper().configure(SerializationFeature.WRAP_ROOT_VALUE, true).writeValueAs...

于 2016-08-17T20:52:06.703 回答
0

我创建了一个包含 @JsonWrapped 注释的小型杰克逊模块,可以解决问题。代码见这里:https ://github.com/mwerlitz/jackson-wrapped

您的课程将如下所示:

public class Message {
    @JsonWrapped("message")
    private String text;
}
于 2020-06-21T12:29:59.160 回答