杰克逊序列化:包裹字段

时间:2015-09-30 19:28:57

标签: java json jackson

当我们打开嵌套对象并将其字段写入主对象时,有一个众所周知的情况,我需要做一个反向任务。

我有一个POJO:

class A {
    private String id = "id1";

    @JsonWrap("properties")
    private String property1 = "...";

    @JsonWrap("properties")
    private String property2 = "...";

    // getters and setters
}

默认序列化程序将按预期生成

{
    "id": "id1",
    "property1": "...",    
    "property2": "..."    
}

但是,我的JSON应该符合某些规范,为此,我需要在property1包装器中包装property2properties。所以结果应该是这样的:

{
    "id": "id1",
    "properties": 
    {
        "property1": "...",
        "property2": "..."
    }
}

我不想改变POJO的结构,所以我看到了3种可能的方式:

  1. 编写自定义序列化程序。但是在我看来,编写这样的序列化器需要花费更多的精力然后手工序列化对象。
  2. 创建代理Java对象,它将反映JSON的正确结构,并序列化此类代理。
  3. 生成后修改JSON。 (我担心重读和重写JSON会有很大的开销)。
  4. 有没有人制作这样的Serializer或者知道其他选项来生成具有我需要的结构的JSON?

    对于custom serializer我想重用标准BeanSerializer,我不想手动写出所有字段:

    1. 隐藏带注释的字段。
    2. 写出bean,没有带注释的字段,但不要关闭对象。 (别打电话给jgen.writeEndObject();
    3. 写出包装好的字段。
    4. 关闭对象。

3 个答案:

答案 0 :(得分:0)

您需要更改模型。

    function convertStringToArrayBufferView(str) {
      var bytes = new Uint8Array(str.length);
      for (var iii = 0; iii < str.length; iii++) {
        bytes[iii] = str.charCodeAt(iii);
      }

      return bytes;
    }

    
    var crypto = window.crypto || window.msCrypto;
    var config = {
      name: 'RSAES-PKCS1-v1_5',
      modulusLength: 2048,
      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
      hash: {
        name: 'SHA-256'
      }
    };

    var keyOp = crypto.subtle.generateKey(config, false, ['encrypt', 'decrypt']);
    keyOp.onerror = function(e) {
      console.error(e);
    };
    keyOp.oncomplete = function(e) {
      encrypt(e.target.result);
    };

    function encrypt(keypair) {
      var data = "abc1234444"

      var encOp = crypto.subtle.encrypt({
        name: config.name,
        iv: config.iv || crypto.getRandomValues(new Uint8Array(16)),
        key: keypair.publicKey
      }, keypair.publicKey, convertStringToArrayBufferView(data));

      encOp.onerror = function(e) {
        console.error(e);
      };
      encOp.oncomplete = function(e) {
        console.log({
          data: new Uint8Array(e.target.result)
        });
      };
    }

在主屏幕中运行:

@JsonSerialize(using = ASerializer.class)
class A {
    private String id;
    private String property1;
    private String property2;

    // getters and setters

    public static class ASerializer extends JsonSerializer<A> {
        @Override
        public void serialize(A value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            jgen.writeStartObject();
            jgen.writeStringField("id", value.getId());
            jgen.writeObjectFieldStart("properties");
            jgen.writeStringField("property1", value.getProperty1());
            jgen.writeStringField("property2", value.getProperty2());
            jgen.writeEndObject();
            jgen.writeEndObject();
        }
    }
}

<强>输出:

A a = new A();
a.setId("id1");
a.setProperty1("...");
a.setProperty2("...");
ObjectMapper mapper = new ObjectMapper();
ObjectWriter writer = mapper.writer();
String json = writer.writeValueAsString(a);
System.out.println(json);

答案 1 :(得分:0)

听起来你需要创建一个Custom Serializer:http://wiki.fasterxml.com/JacksonHowToCustomSerializers

当然,如果您使用类似的JSON结构创建Java对象,您可能也需要创建自定义反序列化器。

请记住,您始终可以使用反射创建一个通用的&#39;如果您发现许多对象共享相似的结构,则为序列化器。

答案 2 :(得分:0)

要在不改变模型的情况下获得该功能,请查看编写自定义序列化程序以完成杰克逊无法解决的问题。我们使用特定的方向注释模型类A以使用已定义的序列化程序,然后使用JsonGenerator来专门定义我们所遵循的结构。

@JsonSerialize(using = ASerializer.class)
class A {
    private String field1;
    private String innerField1;
    private String innerField2;
    // getters and setters


    public static class ASerializer extends JsonSerializer<A> {
        @Override
        public void serialize(A value, JsonGenerator jgen, SerializerProvider provider) 
          throws IOException, JsonProcessingException {
            jgen.writeStartObject();
                jgen.writeStringField("field1", value.getField1());
                jgen.writeObjectFieldStart("wrapper");
                    jgen.writeStringField("innerField1", value.getInnerField1());
                    jgen.writeStringField("innerField2", value.getInnerField2());
                jgen.writeEndObject();
            jgen.writeEndObject();
        }
    }
}

在这种情况下我使用了静态内部类,但可行的是,您可以根据可见性将Serializer放置在最适合您的项目结构的位置。对于一次性特殊情况序列化器,这是我倾向于做的。