如何在不嵌套的情况下使用 Jackson 序列化单值 @Data 对象(例如 {"id":123},而不是 {"id":{"value":123}})?

Koh*_*aki 7 java json jackson lombok

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

@Data
public final class SomeId implements Serializable {
    private final long value;
}
Run Code Online (Sandbox Code Playgroud)

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

public class SomeDTO {
    SomeId id;
    public SomeId getId() {
        return id;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想这DTO类序列化为类似{"id":123},但杰克逊会产生类似{"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!
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Koh*_*aki 5

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

public interface LongValue {
    @JsonValue
    long getValue();
}
Run Code Online (Sandbox Code Playgroud)

然后在每个班级中实施@DatagetValue()请注意, Lombok 将自动生成实际的实现:

@Data
public final class SomeId implements LongValue, Serializable {
    private final long value;
}
Run Code Online (Sandbox Code Playgroud)

这样我就SomeDTOTest通过了测试 -按我的预期SomeDTO序列化{"id":123}


Sac*_*141 2

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

例如:

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()); 
    }   
}
Run Code Online (Sandbox Code Playgroud)

现在使用这个序列化器来序列化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}
Run Code Online (Sandbox Code Playgroud)