Jackson Custom Serializer 在 Json 序列化期间显示 2 个不同字段的相同上下文
Jackson Custom Serializer shows the same context for 2 different field during the Json Serialization
我正在尝试基于我的对象 class POJO 创建一个 JSON。对于某些字段,我想使用 CustomSerializer,因为我想根据我的要求创建字段。因此,我创建了 CustomSerializer.class
.
CustomSerializer
将由我的 POJO
中的 2 个不同字段调用,我想根据调用的字段不同来处理这些事情。对于其中一个字段 (extensions
) 我想要 fieldName
而对于其他字段 (withoutExtensions
) 我不希望在我的 JSON.
我面临的问题是,当调用 CustomSerializer
时,我得到的两个调用都是相同的 fieldname
,因此我无法区分当前调用的是哪个字段CustomSerializer
.
以下代码示例将更清楚地说明我面临的问题:
Customer
POJO class 用于序列化 JSON:
@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
class 它将创建一个 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
。
任何帮助将不胜感激。谢谢
一个。创建两个 Map
序列化程序,其中一个创建外部对象,另一个不创建
优点:
- 易于实施
- 易于测试
- 一个class只做一件事
Map
不创建外部对象的序列化器可以替换为自定义 Map
序列化器(如果可能)
缺点:
- 如果他们需要共享状态可能会有问题。
- 可能是重复代码
乙。实现 ContextualSerializer 接口
优点:
- 可以为每个字段单独配置
- 如果需要可以共享状态。用户控制创建多少个实例。
缺点:
- 做不止一件事
- 很容易过于复杂
示例:
- Need Jackson serializer for Double and need to specify precision at runtime
根据@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();
}
我正在尝试基于我的对象 class POJO 创建一个 JSON。对于某些字段,我想使用 CustomSerializer,因为我想根据我的要求创建字段。因此,我创建了 CustomSerializer.class
.
CustomSerializer
将由我的 POJO
中的 2 个不同字段调用,我想根据调用的字段不同来处理这些事情。对于其中一个字段 (extensions
) 我想要 fieldName
而对于其他字段 (withoutExtensions
) 我不希望在我的 JSON.
我面临的问题是,当调用 CustomSerializer
时,我得到的两个调用都是相同的 fieldname
,因此我无法区分当前调用的是哪个字段CustomSerializer
.
以下代码示例将更清楚地说明我面临的问题:
Customer
POJO class 用于序列化 JSON:
@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
class 它将创建一个 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
。
任何帮助将不胜感激。谢谢
一个。创建两个 Map
序列化程序,其中一个创建外部对象,另一个不创建
优点:
- 易于实施
- 易于测试
- 一个class只做一件事
Map
不创建外部对象的序列化器可以替换为自定义Map
序列化器(如果可能)
缺点:
- 如果他们需要共享状态可能会有问题。
- 可能是重复代码
乙。实现 ContextualSerializer 接口
优点:
- 可以为每个字段单独配置
- 如果需要可以共享状态。用户控制创建多少个实例。
缺点:
- 做不止一件事
- 很容易过于复杂
示例:
- Need Jackson serializer for Double and need to specify precision at runtime
根据@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();
}