jackson自定义序列化程序在json序列化期间为2个不同字段显示相同的上下文

4c8rllxm  于 2021-08-20  发布在  Java
关注(0)|答案(2)|浏览(452)

我正在尝试基于我的对象类pojo创建json。对于某些字段,我希望使用customserializer,因为我希望根据需要创建字段。因此,我创建了 CustomSerializer.class .
这个 CustomSerializer 将由我的中的两个不同字段调用 POJO 我想根据打电话的领域来处理不同的事情。为其中一个领域( extensions )我想要一个 fieldName 以及其他领域( withoutExtensions )我不希望有这样的机会 fieldname 在我的json中。
我面临的问题是 CustomSerializer 被称为然后我得到同样的 fieldname 对于我无法区分的两个调用,哪个字段当前正在调用 CustomSerializer .
以下代码示例将更清楚地说明我面临的问题: Customer 用于序列化json的pojo类:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
@NoArgsConstructor
public class Customer {
    private String isA;
    private String name;

    @JsonSerialize(using = CustomSerializer.class)
    private Map<String, Object> extensions = new HashMap<>();

    private Map<String, Object> withoutExtensions = new HashMap<>();

    @JsonAnyGetter
    @JsonSerialize(using = CustomSerializer.class)
    public Map<String, Object> getWithoutExtensions() {
        return withoutExtensions;
    }

}

下面是我的 CustomSerializer 在创建json期间,将由2个字段(扩展和withoutextensions)调用:

public class CustomSerializer extends JsonSerializer<Map<String, Object>> {

    @Override
    public void serialize(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) {
        //I would like to create the outer object for "Extensions" but do not want to create outer object for "WithoutExtensions"

         System.out.println(gen.getOutputContext().getCurrentName());

        //In my case for both "Extensions" and "WithoutExtensions" i get the "currentName" as "Extensions" how can I ensure which field is calling this sealizer at
        // present
    }
}

下面是我的 Main 类,该类将创建json:

public class Main {
    public static void main(String[] args) throws JsonProcessingException {
        final ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
        final Customer customer = new Customer();

        customer.setName("Jackson");

        Map<String, Object> extensions = new HashMap<>();
        extensions.put("WithObject", "With");
        customer.setExtensions(extensions);

        Map<String, Object> withoutExtensions = new HashMap<>();
        extensions.put("WithoutObject", "Without");
        customer.setWithoutExtensions(withoutExtensions);

        final String eventAsJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(customer);
        System.out.println(eventAsJson);
    }
}

正如我运行应用程序时所看到的 CustomSerializer 将打印 extensions 在这两种情况下。我认为应该打印出来 extensions 只有一次,在下一种情况下,它应该提供 withoutExtensions 或空字符串。
我只是想知道这是否是Jackson方面的一个错误,或者是否有任何解决办法,我可以尝试区分哪个领域正在给我的客户打电话 CustomSerializer .
任何帮助都将不胜感激。谢谢

wfypjpf4

wfypjpf41#

a。创建两个Map序列化器,其中一个创建外部对象,另一个不创建

赞成的意见:
易于实现
易于测试
一个类只做一件事 Map 不创建外部对象的serialiser可以由custom替换 Map serialiser(如果可能)
欺骗:
如果他们需要共享状态,可能会有问题。
可能是重复的代码

b。实现contextualserializer接口

赞成的意见:
可以为每个字段单独配置
如果需要,可以共享状态。用户控制创建了多少示例。
欺骗:
做不止一件事
很容易过于复杂
示例:
需要双精度的jackson序列化程序,并且需要在运行时指定精度
用于自定义值序列化的jackson自定义注解
使用jackson反序列化为字符串或对象
jackson-将对象的内部列表反序列化为更高级别的列表

5ssjco0h

5ssjco0h2#

基于@michal的响应,我修改了代码,它对两种场景都有效。发布完整的代码示例,因为它可能对将来的人有所帮助: Customer.class 补充道 @Extensions 在必填字段上:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
@NoArgsConstructor
public class Customer {
    private String isA;
    private String name;

    @JsonSerialize(using = CustomSerializer.class)
    @Extensions(extension = "extensions")
    private Map<String, Object> extensions = new HashMap<>();

    private Map<String, Object> withoutExtensions = new HashMap<>();

    @JsonAnyGetter
    @JsonSerialize(using = CustomSerializer.class)
    @Extensions(extension = "withoutExtensions")
    public Map<String, Object> getWithoutExtensions() {
        return withoutExtensions;
    }

}
``` `CustomSerializer` :

@NoArgsConstructor
public class CustomSerializer extends JsonSerializer<Map<String, Object>> implements ContextualSerializer {

private String context = "";

public CustomSerializer(String context) {
    this.context = context;
}

@Override
public void serialize(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) {
    if (this.context.equals("extensions")) {
        System.out.println("Extensions : " + this.context);
    } else if (this.context.equals("withoutExtensions")) {
        System.out.println("Without Extensions : " + this.context);
    }
}

@Override
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
    Extensions extensions = beanProperty.getAnnotation(Extensions.class);
    if (extensions != null) {
        return new CustomSerializer(extensions.extension());
    }
    return this;
}

}

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Extensions {
String extension();
}

相关问题