【问题标题】:How to serialize single-valued @Data object using Jackson without nesting (e.g. {"id":123}, not {"id":{"value":123}})?如何使用没有嵌套的 Jackson 序列化单值 @Data 对象(例如 {"id":123},而不是 {"id":{"value":123}})?
【发布时间】:2016-07-26 05:51:44
【问题描述】:

我打算使用 Lombok 创建数百个基于“值对象”模式的类,如下所示:

@Data
public final class SomeId implements Serializable {
    private final long value;
}

我想将这些类用于由 Jackson 提供支持的 JSON 序列化。例如,考虑如下 DTO 类:

public class SomeDTO {
    SomeId id;
    public SomeId getId() {
        return id;
    }
}

我希望将该 DTO 类序列化为 {"id":123} 之类的东西,但 Jackson 会生成类似 {"id":{"value":123}} 的东西,它带有一个名为 value 的字段的不必要的嵌套对象。即一个测试用例表达了我的要求:

public class SomeDTOTest {
    @Test
    public void serializationTest() throws Exception {
        SomeDTO dto = new SomeDTO();
        dto.id = new SomeId(123);

        String serialized = new ObjectMapper().writeValueAsString(dto);

        System.out.println(serialized);             // {"id":{"value":123}}
        assertThat(serialized, is("{\"id\":123}")); // I want {"id":123} instead!
    }
}

我知道将@JsonValue 注释添加到SomeId 类中的每个getValue() 方法将是一个解决方案,但我不能这样做,因为没有@Data 类的实际定义,因为Lombok 会自动创建它。

为每个类手动创建实际的getValue() 方法注释为@JsonValue 可能是另一种解决方案,但这意味着创建大量样板代码。

如何在没有样板代码的情况下实现此要求?

【问题讨论】:

  • 还有1种方法,不知道对你有没有帮助:public class SomeDTO { @JsonUnwrapped SomeId id;}public class SomeId { @JsonProperty(value = "id") private long value;}
  • 您可以简单地使用@JsonValue 对 SomeId 类中的 value 字段进行注释。您不需要对 getter 进行注释

标签: java json jackson lombok


【解决方案1】:

您可以为此类编写自定义序列化程序。

例如:

class CustomSerializer extends StdSerializer<SomeId>{

    protected CustomSerializer(Class<SomeId> t) {
        super(t);
    }

    @Override
    public void serialize(SomeId someId, JsonGenerator gen, SerializerProvider serializers)
            throws IOException, JsonProcessingException {
        gen.writeNumber(someId.getValue()); 
    }   
}

现在使用这个序列化器来序列化SomeId类:

 ObjectMapper mapper = new ObjectMapper();

 SimpleModule module = new SimpleModule();
 module.addSerializer(new CustomSerializer(SomeId.class));       
 mapper.registerModule(module);

 SomeDTO dto = new SomeDTO();
 dto.id = new SomeId(123);     
 String serialized = mapper.writeValueAsString(dto);
 System.out.println(serialized);             // output : {"id":123}

【讨论】:

  • 很好,但是使用您的解决方案,我似乎需要为所有“值对象”类创建数百个CustomSerializers - 这将是我想要消除的另一个样板代码。为“值对象”类创建父类可能是一种选择,但我宁愿避免使用它,因为它会降低使用 Lombok 的好处。
【解决方案2】:

我创建了一个带有getValue() 的接口,注释为@JsonValue

public interface LongValue {
    @JsonValue
    long getValue();
}

然后在每个@Data 类中实现它。请注意,getValue() 的实际实现将由 Lombok 自动生成:

@Data
public final class SomeId implements LongValue, Serializable {
    private final long value;
}

我已经通过了测试SomeDTOTest - 正如我所料,SomeDTO 被序列化为{"id":123}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多