【发布时间】:2012-01-01 01:45:36
【问题描述】:
我有一个类,里面也有变量。有时我想忽略一些字段,有时在反序列化时不想忽略(也许也在序列化时)。我如何在杰克逊做到这一点?
【问题讨论】:
标签: java json deserialization jackson
我有一个类,里面也有变量。有时我想忽略一些字段,有时在反序列化时不想忽略(也许也在序列化时)。我如何在杰克逊做到这一点?
【问题讨论】:
标签: java json deserialization jackson
对于序列化,“filtering properties”博客条目应该会有所帮助。反序列化方面的支持较少,因为更常见的是要过滤掉写入的内容。
一种可能的方法是对JacksonAnnotationIntrospector 进行子类化,覆盖自省方法(和/或字段)的可忽略性以使用您想要的任何逻辑的方法。
如果您提供一个实际应用示例,也可能会有所帮助,即您试图防止反序列化的内容和原因。
【讨论】:
@JsonFilter 非常适合我的用例,我希望在获取(序列化)方面进行更多控制,但不能超出某个级别,因为它最终会被递归获取。 ORM 往往是这样的。
您可能想要使用 JsonViews(最初来自 http://wiki.fasterxml.com/JacksonJsonViews - 现在已损坏 - 网络存档链接:https://web.archive.org/web/20170831135842/http://wiki.fasterxml.com/JacksonJsonViews)
首先,定义视图意味着声明类;您可以重用现有的,或者只是创建虚假类——它们只是带有关系信息的视图标识符(子继承父视图成员身份):
// View definitions:
class Views {
static class Public { }
static class ExtendedPublic extends PublicView { }
static class Internal extends ExtendedPublicView { }
}
public class Bean {
// Name is public
@JsonView(Views.Public.class) String name;
// Address semi-public
@JsonView(Views.ExtendPublic.class) Address address;
// SSN only for internal usage
@JsonView(Views.Internal.class) SocialSecNumber ssn;
}
有了这样的视图定义,序列化可以这样完成:
// short-cut:
objectMapper.writeValueUsingView(out, beanInstance, ViewsPublic.class);
// or fully exploded:
objectMapper.getSerializationConfig().setSerializationView(Views.Public.class);
// (note: can also pre-construct config object with 'mapper.copySerializationConfig'; reuse)
objectMapper.writeValue(out, beanInstance); // will use active view set via Config
// or, starting with 1.5, more convenient (ObjectWriter is reusable too)
objectMapper.viewWriter(ViewsPublic.class).writeValue(out, beanInstance);
and result would only contain 'name', not 'address' or 'ssn'.
【讨论】:
你应该看看最近 Jackson 版本的modules feature。
一种可能的机制是使用BeanDeserializerModifier。
我一直在寻找有用的在线教程或示例,但没有立即出现。如果对您的上下文有更多了解,则可能会有所作为。您是手动管理ObjectMappers,还是在 JAX-RS 设置中使用它们,在 Spring 中注入,还是什么?
【讨论】:
我搜索了整个网络(是的,我这样做了)以找到答案。然后我自己写了一些东西。
我正在使用 Jackson 离子反序列化。我编写了一个自定义阅读器,它会动态忽略这些字段。
你可以对 json 反序列化做同样的事情。
让我们假设一个这样的实体。
User {
id
name
address {
city
}
}
创建一个树结构来表示字段选择。
public class IonField {
private final String name;
private final IonField parent;
private final Set<IonField> fields = new HashSet<>();
// add constructs and stuff
}
从 amazon ion-java https://github.com/amzn/ion-java 扩展的自定义离子读取器
public class IonReaderBinaryUserXSelective extends IonReaderBinaryUserX {
private IonField _current;
private int hierarchy = 0;
public IonReaderBinaryUserXSelective(byte[] data, int offset, int length,
IonSystem system, IonField _current) {
super(system, system.getCatalog(), UnifiedInputStreamX.makeStream(data, offset, length));
this._current = _current;
}
@Override
public IonType next() {
IonType type = super.next();
if (type == null) {
return null;
}
String file_name = getFieldName();
if (file_name == null || SystemSymbols.SYMBOLS.equals(file_name)) {
return type;
}
if (type == IonType.STRUCT || type == IonType.LIST) {
IonField field = _current.getField(getFieldName());
if (field != null) {
this._current = field;
return type;
} else {
super.stepIn();
super.stepOut();
}
return next();
} else {
if (this._current.contains(file_name)) {
return type;
} else {
return next();
}
}
}
@Override
public void stepIn() {
hierarchy = (hierarchy << 1);
if (getFieldName() != null && !SystemSymbols.SYMBOLS.equals(getFieldName())) {
hierarchy = hierarchy + 1;
}
super.stepIn();
}
@Override
public void stepOut() {
if ((hierarchy & 1) == 1) {
this._current = this._current.getParent();
}
hierarchy = hierarchy >> 1;
super.stepOut();
}
构建动态视图。这棵树动态创建并传递给阅读器进行反序列化。
假设我们只需要地址中的城市。
IonField root = new IonField("user", null);
IonField address = new IonField("address", root);
IonField city = new IonField("city", address);
address.addChild(city);
root.addChild(id);
//now usual stuff.
IonFactory ionFactory = new IonFactory();
IonObjectMapper mapper = new IonObjectMapper(ionFactory);
File file = new File("file.bin"); // ion bytes
byte[] ionData = Files.readAllBytes(file.toPath());
IonSystem ionSystem = IonSystemBuilder.standard().build();
IonReader ionReader = new IonReaderBinaryUserXSelective(ionData, 0, ionData.length, ionSystem, root);
User user = mapper.readValue(ionReader, User.class);
【讨论】: