gpt4 book ai didi

java - 自定义 jackson bean 序列化器,可以根据同级属性的值动态忽略一些带注释的属性

转载 作者:行者123 更新时间:2023-12-01 16:45:12 25 4
gpt4 key购买 nike

所以我有一个名为 MyClass 的 java 类型,它有一些要序列化的属性。它还有另一个属性来决定其他属性是否应该序列化。是否可以编写一个自定义序列化器来实现此规则,即仅当 java 类型的属性匹配条件时,它才会序列化它们?例如我还有另一个兄弟属性,其中包含 id 列表。如果要序列化的当前属性分配了一个 id(通过注释),该 id 是该列表的一部分,那么我不想序列化它。

我的java类...

public class MyClass implements WithFieldsToHide {

// serializable fields

@FieldId(id = "one")
private String name;

@FieldId(id = "two")
private String company;

public String getName() { return name; }

public String getCompany() { return company; }


// internal fields, non-serializable

@JsonIgnore
private Set<String> fieldsToHide;

public Set<String> getFieldsToHide() { return fieldsToHide; }

}

一个简单的界面,支持隐藏字段...

public interface WithFieldsToHide {
Set<String> getFieldsToHide();
}

简单的注释...

@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
public @interface FieldId {
String id();
}

用法...

public static void main(String args...) {
ObjectMapper objectMapper = new ObjectMapper();

MyClass testObject = new MyClass();

// assume the setters are available
testObject.setName("Jackson");
testObject.setCompany("NoBitMedia");
testObject.setFieldsToHide(new HashSet<String>() {{ add("two"); }});

String serialized = objectMapper.writeValueAsString(testObject);
// serialized should equal `{"name":"Jackson"}`
}

我尝试过的一些事情:

  • 我可以延长BeanSerializerModifier并覆盖modifySerializer() ,但我没有可用的实际对象来读取 fieldsToHide属性(根据它我将决定是否序列化)。

  • 我可以编写一个自定义转换器(扩展 StdConverter<MyClass, MyClass> ,但我没有 convert() 方法中注释的属性列表。

  • 我可以编写一个自定义序列化程序( MyClassSerializer<T extends WithFieldsToHide> extends JsonSerializer<T> ),但在这里,我也不确定是否可以在 serialize() 中提供属性列表及其注释。方法。

在我尝试深入研究 jackson 代码之前,想问一下这种动态序列化是否可能。或者有什么建议可以得到类似的结果吗?

最佳答案

虽然我确实尝试覆盖 BeanPropertyWriter早些时候但无法真正弄清楚如何做我想做的事情。

这就是我最终所做的。

如果 bean 类需要动态隐藏其字段则要实现的接口(interface)..

public interface WithFieldsToHide {
boolean hide(String fieldId);
}

在需要隐藏的字段上添加注释..

@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
public @interface HideFieldId {
String id();
}
public class CustomFieldHideModule extends Module {
@Override
public void setupModule(SetupContext context) {
context.addBeanSerializerModifier(new CustomFieldHideSerializerModifier());
}

private static class CustomFieldHideSerializerModifier extends BeanSerializerModifier {

@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
// only try to hide fields for class of a particular interface type
if (WithFieldsToHide.class.isAssignableFrom(beanDesc.getBeanClass())) {
for (int i = 0; i < beanProperties.size(); i++) {
BeanPropertyWriter writer = beanProperties.get(i);
// to be able to run the logic to hide, we need to know if the property has a field id assigned
HideFieldId annotation = writer.getAnnotation(HideFieldId.class);
if (null != annotation) {
beanProperties.set(i, new ConditionalPropertyWriter<>(writer, annotation.id()));
}
}
}
return beanProperties;
}

private static class ConditionalPropertyWriter<T extends WithFieldsToHide> extends BeanPropertyWriter{

private final fieldId;
protected ConditionalPropertyWriter(BeanPropertyWriter writer, String fieldId) {
super(writer);
this.fieldId = fieldId;
}

@Override
public void serializeAsField(Object bean, JsonGenerator jgen, SerializerProvider prov) throws Exception {
T withFieldsToHide = (T) bean; // don't need type check as we're checking when registering this writer for the property
if (!withFieldsToHide.isInternal(fieldId)) {
super.serializeAsField(bean, jgen, prov);
}
}
}
}
}

然后你只需使用你的对象映射器注册这个模块,瞧!

对于 map 属性类型,我还想要多一层隐藏,我只需要隐藏 map 属性中的某些元素,而不是整个属性本身,并且可以编写一些东西来实现它。如果有人想要这个,请告诉我,为了简洁起见,不包括它。

谢谢!!

关于java - 自定义 jackson bean 序列化器,可以根据同级属性的值动态忽略一些带注释的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61793478/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com