Jackson序列化的动态属性名称

时间:2014-09-16 20:20:30

标签: java json jackson

我有很多课程,我试图序列化为JSON。它们非常相似,所以我想知道是否有更好的方法来执行此操作,而不是每次出现此模式时创建3个非常接近相同的类:

public class SomethingFoo {
  @JsonProperty("foo")
  Identifier foo

  // other properties
}

public class SomethingBar {
  @JsonProperty("bar")
  Identifier bar

  // other properties
}

public class SomethingBaz {
  @JsonProperty("baz")
  Identifier baz

  // other properties
}

标识符是一个只包含一个字段的类:

public class Identifier {
  @JsonProperty("name")
  String name = "";
}

我想做的是将标识符更改为:

public class Identifier {
  @JsonProperty("name")
  String name = "";

  @JsonIgnore
  IdentifierType type;
}

public Enum IdentifierType {
  FOO, BAR, BAZ;
}

然后我想使用'类型'标识符中的字段,用于更改包含这些标识符的对象中标识符字段的名称。

我想用这个替换SomethingFoo,SomethingBar和SomethingBaz:

public class Something {
  @JsonProperty(??????)
  Identifier name

  // other properties
}

我希望Something.identifier的属性名称为" foo"," bar"或" baz",具体取决于Identifier的值。类型。

或者,我也可以使用标识符进行子类化,而不是使用枚举。

问题在于我试图在对象中使用值(或对象的类型,如果使用子类)来通知包含类的标识符中的属性名称。所以我不知道在不改变包含标识符的每个类的情况下,我想做什么是可能的。

修改

问题是我想要什么' Something'被序列化为其中之一(基于标识符的枚举类型(或子类,如果这是实现此目的的更好方法)):

{
  "foo" : { 
     "name" : "blahblahblah"
  }
}

{
  "bar" : { 
     "name" : "blahblahblah"
  }
}

{
  "baz" : { 
     "name" : "blahblahblah"
  }
}

2 个答案:

答案 0 :(得分:4)

这可以使用JsonSerializer和您的自定义实现来完成。请参考以下代码。

 @JsonSerialize(using = Term.TermSerializer.class)
 public class Term {

//@JsonProperty("field")
private String field;

public Term() {

}

public Term(String field){
    this.field = field;
}

public String getField() {
    return field;
}

public void setField(String field) {
    this.field = field;
}

public static class TermSerializer extends JsonSerializer<Term> {
    @Override public void serialize(Term value, JsonGenerator jsonGenerator, SerializerProvider provider)
        throws IOException {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("price", value.getField());// dynamic field name
        jsonGenerator.writeEndObject();
    }
}

public static void main(String[] args){
    Term term = new Term("color");
    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
    String jsonString = null;
    try {
        jsonString = mapper.writeValueAsString(term);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    System.out.println(jsonString);
}

}

答案 1 :(得分:2)

注释的属性值必须是常量,因此您无法更改它。我不确定我在这里看到了什么问题。为什么下面的解决方案不起作用? @JsonProperty只是告诉ObjectMapper Json字段的名称应该是什么。

public class Something {
  @JsonProperty(value = "id")
  Identifier identifier

  // other properties
}

如果您序列化了其中一个对象,那就会出现这样的情况:

{
  "id": FOO,
  ...
}

如果value - "id"没有@JsonProperty,则只使用字段名称:

{
  "identifier": FOO,
  ...
}

杰克逊有很多方法可以自定义序列化和反序列化对象。如果您希望序列化有更多信息(例如,如果您向Enum添加任何字段)或想要更改它的序列化方式,那么有办法做到这一点。例如,如果您希望将Enum序列化为对象在 Jackson 2.1.2 @JsonFormat你可以做到:

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Identifier {...}

修改 我不认为将数据序列化为上述格式必然是有意义的,因为您不再将对象表示为JSON,因为您将其表示为不同的对象。您已经在对象上有一个字段,用于区分该对象的Identifier是什么,您可以在其他任何地方使用该字段。如果您真的想按照上面描述的方式将数据序列化,我相信您必须为此类型实现自己的JsonSerializer(至少对于Jackson 2.1):

public SomethingSerializer extends JsonSerializer<Something> {
  // Define serialization methods
  ...
}

然后扩展SimpleModule,添加序列化程序,并使用ObjectMapper注册模块:

ObjectMapper mapper = new ObjectMapper();
SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null));
testModule.addSerializer(new SomethingSerializer());
mapper.registerModule(testModule);

改编自JacksonHowToCustomSerializers

的示例