假设我有以下 POJO:
class Pojo {
String s;
Object o;
Map<String, String> m;
}
并且在运行时,我希望对除一个属性之外的所有属性进行默认序列化/反序列化。通常,我想在序列化时用数据库中的 ID 替换字段,类似于 this other question 。
例如,我想用从外部映射中获得的字符串替换o
(例如:object1
<=> "123"and object2
<=> "456"):
- 序列化:读取
o
并替换(所以如果o
是object1
,序列化为字符串“123”) - 反序列化:读取“123”,查询一些表以获取
o
的原始值(即object1
),重新创建一个Pojo
带有o = object1
的对象。
我知道模块是一种方法,但我不确定如何使用它们同时为不需要更改的属性保留自动 BeanSerializer/Deserializer。
有人可以举个例子(甚至是人为的)或替代方法吗?
注意事项:
- 我不能使用注释或 Mixins,因为这些更改在编译时是未知的(即,任何属性都可能以无法确定的方式更改)。
- This other question 指出使用 CustomSerializerFactory,它似乎可以完成这项工作。不幸的是,官方网站指出应该改用 it is not the recommended approach any more 和那个模块。
编辑
为了更清楚一点,我可以用 Mixins 做如下例子:
ObjectMapper mapper = new ObjectMapper(MongoBsonFactory.createFactory());
mapper.addMixInAnnotations(Pojo.class, PojoMixIn.class);
ObjectReader reader = mapper.reader(Pojo.class);
DBEncoder dbEncoder = DefaultDBEncoder.FACTORY.create();
OutputBuffer buffer = new BasicOutputBuffer();
dbEncoder.writeObject(buffer, o);
使用以下 Mixin:
abstract class PojoMixIn {
@JsonIgnore Object o;
}
然后将所需的字符串添加到 JSON 内容中。但是我需要在编译时知道需要替换的是 o
字段,而我不知道。
最佳答案
我认为 @JsonSerialize
和 @JsonDeserialize
是您所需要的。这些注释使您可以控制特定字段的序列化/反序列化。 This question展示了将它们组合成一个注释的优雅方式。
UPD。对于这种复杂的情况,您可以查看 BeanSerializerModifier/BeanDeserializerModifier
类。这个想法是用您针对特定字段的自定义逻辑修改一般的 BeanSerializer/BeanDeserializer
并让基本实现来做其他事情。稍后将发布示例。
UPD2. 正如我所见,其中一种方法是使用 changeProperties
方法并分配您自己的序列化程序。
UPD3. 更新了自定义序列化程序的工作示例。反序列化可以用类似的方式完成。
UPD4. 使用完整的自定义序列化/反序列化更新示例。 (我用过jakson-mapper-asl-1.9.8)
public class TestBeanSerializationModifiers {
static final String PropertyName = "customProperty";
static final String CustomValue = "customValue";
static final String BaseValue = "baseValue";
// Custom serialization
static class CustomSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
String customValue = CustomValue; // someService.getCustomValue(value);
jgen.writeString(customValue);
}
}
static class MyBeanSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BasicBeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
for (int i = 0; i < beanProperties.size(); i++) {
BeanPropertyWriter beanPropertyWriter = beanProperties.get(i);
if (PropertyName.equals(beanPropertyWriter.getName())) {
beanProperties.set(i, beanPropertyWriter.withSerializer(new CustomSerializer()));
}
}
return beanProperties;
}
}
// Custom deserialization
static class CustomDeserializer extends JsonDeserializer<Object> {
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// serialized value, 'customValue'
String serializedValue = jp.getText();
String baseValue = BaseValue; // someService.restoreOldValue(serializedValue);
return baseValue;
}
}
static class MyBeanDeserializerModifier extends BeanDeserializerModifier {
@Override
public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BasicBeanDescription beanDesc, BeanDeserializerBuilder builder) {
Iterator<SettableBeanProperty> beanPropertyIterator = builder.getProperties();
while (beanPropertyIterator.hasNext()) {
SettableBeanProperty settableBeanProperty = beanPropertyIterator.next();
if (PropertyName.equals(settableBeanProperty.getName())) {
SettableBeanProperty newSettableBeanProperty = settableBeanProperty.withValueDeserializer(new CustomDeserializer());
builder.addOrReplaceProperty(newSettableBeanProperty, true);
break;
}
}
return builder;
}
}
static class Model {
private String customProperty = BaseValue;
private String[] someArray = new String[]{"one", "two"};
public String getCustomProperty() {
return customProperty;
}
public void setCustomProperty(String customProperty) {
this.customProperty = customProperty;
}
public String[] getSomeArray() {
return someArray;
}
public void setSomeArray(String[] someArray) {
this.someArray = someArray;
}
}
public static void main(String[] args) {
SerializerFactory serializerFactory = BeanSerializerFactory
.instance
.withSerializerModifier(new MyBeanSerializerModifier());
DeserializerFactory deserializerFactory = BeanDeserializerFactory
.instance
.withDeserializerModifier(new MyBeanDeserializerModifier());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializerFactory(serializerFactory);
objectMapper.setDeserializerProvider(new StdDeserializerProvider(deserializerFactory));
try {
final String fileName = "test-serialization.json";
// Store, "customValue" -> json
objectMapper.writeValue(new File(fileName), new Model());
// Restore, "baseValue" -> model
Model model = objectMapper.readValue(new File(fileName), Model.class);
} catch (IOException e) {
e.printStackTrace();
}
}
}
关于java - 在运行时以自定义方式(反)序列化 Bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15022617/