0

目前我有一个使用 Spring-Hibernate 和 Jackson 来处理 JSON 的项目。我第一次尝试使用 Jackson 时,总是会遇到LazyInitializationException多个相互引用的实体的无限循环,有时甚至是无限循环。然后我发现@JsonIgnore@JsonIdentityInfo

现在的问题是有时需要忽略属性,但有时我只需要这些属性是可序列化的。有没有办法有时忽略几个字段,有时在运行时序列化这些字段?

我发现“杰克逊的序列化和反序列化:如何以编程方式忽略字段?

但是如果我总是要在注解中使用混合,如果一个对象要检索几十个属性会很麻烦。例如。在 page1 我需要propertyA, propertyB, propertyC; 在第 2 页我需要propertyApropertyC; 在 page3 我只需要propertyB. 仅在这些情况下,我就必须为每个页面创建 1 个类,从而产生 3 个类。

因此,在这种情况下,有一种方法可以定义如下内容:

objectA.ignoreAllExcept('propertyA');
String[] properties = {'propertyA', 'propertyC'};
objectB.ignoreAllExcept(properties); // Retrieve propertyA and propertyC
objectC.ignore(properties);
4

3 回答 3

1

您可能正在寻找的是一个Module。文档说模块

可以使用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;
        }
    }

}

注意:BeanSerializerModifierchangeProperties类中有一个方法更适合更改属性列表(根据文档)。因此,您可以通过适当的更改移动在to方法中编写的代码。updateBuilderchangeProperties

现在,您需要module使用您的ObjectMapper注册此自定义。您可以从应用程序上下文中获取 Jackson HTTP 消息转换器,并获取其对象映射器。我假设您已经知道如何做到这一点,因为您也一直在处理延迟初始化问题。

// Figure out a way to get the ObjectMapper.
MappingJackson2HttpMessageConverter converter = ... // get the jackson-mapper;
converter.getObjectMapper().registerModule(new MyModule())

你完成了。当您想为特定类型的对象自定义序列化时,请为此创建一个PropertyFilter,将其放入 aList并使其作为当前请求中的属性可用。这只是一个简单的例子。您可能需要对其进行一些调整以满足您的需求。

在您的问题中,您似乎正在寻找一种方法来指定序列化对象本身的过滤属性。在我看来,应该避免这种情况,因为要过滤掉的属性列表不属于您的实体。但是,如果您确实想这样做,请创建一个interface提供settersgetters的属性列表。假设接口的名称是CustomSerializedThen,您可以修改MyModule类以查找该CustomSerialized接口的实例并相应地过滤掉属性。

注意:您可能需要根据您使用的库的版本来调整/调整一些东西。

于 2013-08-30T09:16:48.900 回答
0

我认为有一种更灵活的方法可以做到这一点。您可以配置 Jackson,使其静默忽略延迟加载的属性,而不是停止序列化过程。所以你可以重用同一个类。只需加载所有必要的属性/关系并将其传递给杰克逊。您可以尝试通过声明您的自定义ObjectMapper和关闭SerializationFeature.FAIL_ON_EMPTY_BEANS功能来做到这一点。希望能帮助到你。

于 2013-08-29T10:31:53.970 回答
0

您可以通过为 mixin 注释创建静态接口来过滤掉属性而无需修改类。接下来,使用 @JsonFilter 注解对该接口进行注解。创建一个 SimpleBeanPropertyFilter 和一个 SimpleFilterProvider。然后通过调用 objectMapper.writer(filterProvider) 使用您的过滤器提供程序创建一个 ObjectWriter

于 2016-03-30T20:03:38.703 回答