2013-08-29 52 views
0

目前我有一個使用Spring-Hibernate和Jackson處理JSON的項目。當我第一次嘗試使用傑克遜時,我總是得到LazyInitializationException,有時對於相互引用的多個實體有無限循環。然後我發現@JsonIgnore@JsonIdentityInfo處理Jackson序列化的常用方法是什麼?

現在問題是有時需要忽略屬性,但有時我只需要這些屬性是可序列化的。有沒有辦法有時忽略幾個字段,有時序列化運行時的字段?

我發現「Serialization and Deserialization with Jackson: how to programmatically ignore fields?

但是,如果我總是要使用註釋的搭配,它會很麻煩,如果一個對象的數十項屬性檢索。例如。在第1頁我需要propertyA,propertyB,propertyC;在第2頁我需要propertyApropertyC;在第3頁我只需要propertyB。僅在這些情況下,我將不得不爲每個頁面創建1個類,從而產生3個類。

因此,在這種情況下,有沒有辦法來定義是這樣的:

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

回答

0

我覺得這是一個更靈活的方式來做到這一點。您可以用這樣的方式配置Jackson,它會默默地忽略延遲加載的屬性,而不是停止序列化過程。所以你可以重複使用同一個類。只需加載所有必要的屬性/關係並將其傳遞給Jackson。您可以嘗試聲明自定義ObjectMapper並關閉SerializationFeature.FAIL_ON_EMPTY_BEANS功能。希望能幫助到你。

1

您可能正在尋找的是Module。該文件說,Modules

爲可與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方法並進行相應的更改。

現在,您需要將您自己的module與您的ObjectMapper一起註冊。您可以從您的應用程序上下文中獲取Jackson HTTP消息轉換器,並獲取其對象映射器。我假設你已經知道如何做到這一點,因爲你一直在處理懶惰初始化問題。

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

然後你就完成了。如果要爲特定類型的對象自定義序列化,請爲其創建一個PropertyFilter,並將其放在List中,並將其作爲當前請求中的一個屬性提供。這只是一個簡單的例子。您可能需要稍微調整以適應您的需求。

在你的問題中,你似乎正在尋找一種方法來指定序列化對象本身的屬性 - 過濾器。在我看來,這應該避免,因爲要過濾的屬性列表不屬於您的實體。但是,如果您確實想要這樣做,請創建一個interface,其中提供settersgetters作爲屬性列表。假設接口的名稱是CustomSerialized然後,您可以修改MyModule類以查找此接口的實例並相應地過濾掉這些屬性。

注意:您可能需要根據所使用庫的版本來調整/調整一些內容。

0

您可以通過爲mixin註釋創建靜態接口來過濾掉屬性而無需修改類。接下來,用@JsonFilter註解來註釋該接口。創建一個SimpleBeanPropertyFilter和一個SimpleFilterProvider。然後通過調用objectMapper.writer(filterProvider)

與您的過濾器提供程序創建一個ObjectWriter
相關問題