目前我有一个项目使用Spring-Hibernate和Jackson来处理JSON。我第一次尝试使用Jackson时,我总是得到LazyInitializationException
,有时会为多个相互引用的实体进行无限循环。然后我找到了@JsonIgnore
和@JsonIdentityInfo
。
现在问题是有时需要忽略属性,但有时我只需要这些属性可序列化。有没有办法有时会忽略几个字段,有时会在运行时序列化字段?
我找到了“Serialization and Deserialization with Jackson: how to programmatically ignore fields?”
但是如果我总是必须在注释中使用mix,那么如果一个对象需要检索几十个属性,那将会非常麻烦。例如。在第1页中,我需要propertyA
,propertyB
,propertyC
;在第2页中,我需要propertyA
和propertyC
;在第3页我只需要propertyB
。仅在这些情况下,我必须为每个页面创建1个类,从而产生3个类。
所以在这种情况下有一种方法来定义类似的东西:
objectA.ignoreAllExcept('propertyA');
String[] properties = {'propertyA', 'propertyC'};
objectB.ignoreAllExcept(properties); // Retrieve propertyA and propertyC
objectC.ignore(properties);
答案 0 :(得分:1)
可以使用ObjectMappers注册的扩展的简单界面,为默认功能提供明确定义的扩展集。
以下是您如何使用它们来实现您想要的效果的示例。注意,还有其他方法可以实现这一点;这只是其中之一。
一个简单的DTO,可用于指定要过滤的属性:
public class PropertyFilter {
public Class<?> classToFilter;
public Set<String> propertiesToIgnore = Collections.emptySet();
public PropertyFilter(Class<?> classToFilter, Set<String> propertiesToIgnore) {
this.classToFilter = classToFilter;
this.propertiesToIgnore = propertiesToIgnore;
}
}
自定义模块,可根据您存储在当前attribute
中的某些request
过滤掉属性。
public class MyModule extends Module {
@Override
public String getModuleName() {
return "Test Module";
}
@Override
public void setupModule(SetupContext context) {
context.addBeanSerializerModifier(new MySerializerModifier());
}
@Override
public Version version() {
// Modify if you need to.
return Version.unknownVersion();
}
public static class MySerializerModifier extends BeanSerializerModifier {
public BeanSerializerBuilder updateBuilder(SerializationConfig config,
BeanDescription beanDesc,
BeanSerializerBuilder builder) {
List<PropertyFilter> filters = (List<PropertyFilter>) RequestContextHolder.getRequestAttributes().getAttribute("filters", RequestAttributes.SCOPE_REQUEST);
PropertyFilter filter = getPropertyFilterForClass(filters, beanDesc.getBeanClass());
if(filter == null) {
return builder;
}
List<BeanPropertyWriter> propsToWrite = new ArrayList<BeanPropertyWriter>();
for(BeanPropertyWriter writer : builder.getProperties()) {
if(!filter.propertiesToIgnore.contains(writer.getName())) {
propsToWrite.add(writer);
}
}
builder.setProperties(propsToWrite);
return builder;
}
private PropertyFilter getPropertyFilterForClass(List<PropertyFilter> filters, Class<?> classToCheck) {
for(PropertyFilter f : filters) {
if(f.classToFilter.equals(classToCheck)) {
return f;
}
}
return null;
}
}
}
注意:BeanSerializerModifier类中有一个changeProperties
方法更适合更改属性列表(根据文档)。因此,您可以通过适当的更改将updateBuilder
中编写的代码移动到changeProperties
方法。
现在,您需要使用ObjectMapper注册此自定义module
。您可以从应用程序上下文中获取Jackson HTTP消息转换器,并获取其对象映射器。我假设你已经知道如何做到这一点,因为你一直在处理延迟初始化问题。
// Figure out a way to get the ObjectMapper.
MappingJackson2HttpMessageConverter converter = ... // get the jackson-mapper;
converter.getObjectMapper().registerModule(new MyModule())
你完成了。如果要为特定类型的对象自定义序列化,请为其创建PropertyFilter
,将其放在List
中,并使其可用作当前请求中的属性。这只是一个简单的例子。您可能需要稍微调整一下以满足您的需求。
在您的问题中,您似乎正在寻找一种方法来指定序列化对象本身的属性 - 过滤掉。在我看来,应该避免这种情况,因为过滤掉的属性列表不属于您的实体。但是,如果您确实要这样做,请为属性列表创建一个interface
,其中包含setters
和getters
。假设接口的名称为CustomSerialized
然后,您可以修改MyModule
类以查找此CustomSerialized
接口的实例,并相应地过滤掉属性。
注意:您可能需要根据所使用的库的版本调整/调整一些内容。
答案 1 :(得分:0)
我认为有一种更灵活的方式。您可以以这样的方式配置Jackson,即它将静默忽略延迟加载的属性,而不是停止序列化过程。所以你可以重用同一个类。只需加载所有必要的属性/关系并将其传递给杰克逊。您可以尝试通过声明自定义ObjectMapper
并关闭SerializationFeature.FAIL_ON_EMPTY_BEANS
功能来执行此操作。希望它有所帮助。
答案 2 :(得分:0)
您可以通过为mixin注释创建静态接口来过滤掉属性而无需修改类。接下来,使用@JsonFilter注释注释该接口。创建SimpleBeanPropertyFilter和SimpleFilterProvider。然后通过调用objectMapper.writer(filterProvider)与过滤器提供程序一起创建一个ObjectWriter