2014-04-19 67 views
5

我在尋找可能只在某些情況下,序列化瞬時信息:傑克遜:忽略吸氣,但不能與@JsonView

@JsonInclude(Include.NON_NULL) 
@Entity 
public class User { 

    public static interface AdminView {} 

    ... id, email and others ... 

    @Transient 
    private transient Details details; 

    @JsonIgnore     // Goal: ignore all the time, except next line 
    @JsonView(AdminView.class) // Goal: don't ignore in AdminView 
    public Details getDetails() { 
     if (details == null) { 
      details = ... compute Details ... 
     } 
     return details; 
    } 
} 

public class UserDetailsAction { 
    private static final ObjectWriter writer = new ObjectMapper(); 
    private static final ObjectWriter writerAdmin = writer 
     .writerWithView(User.AdminView.class); 

    public String getUserAsJson(User user) { 
     return writer.writeValueAsString(user); 
    } 

    public String getUserAsJsonForAdmin(User user) { 
     return writerAdmin.writeValueAsString(user); 
    } 
} 

如果我打電話getUserAsJson我期望看到ID,電子郵件等領域,但不是細節。這工作正常。但是我看到getUserAsJsonForAdmin也是一樣,也沒有細節。如果我刪除@JsonIgnore註釋 - 我確實在兩個調用中看到細節。

我錯了什麼,有沒有好的方法?謝謝!

回答

4

相反,你可能會發現使用the dynamic Jackson filtering稍微更加優雅爲您的用例。這裏是POJO領域的基於自定義註釋共享一個對象映射器實例中的濾波的實例:

public class JacksonFilter { 
    static private boolean shouldIncludeAllFields; 

    @Retention(RetentionPolicy.RUNTIME) 
    public static @interface Admin {} 

    @JsonFilter("admin-filter") 
    public static class User { 
     public final String email; 
     @Admin 
     public final String details; 

     public User(String email, String details) { 
      this.email = email; 
      this.details = details; 
     } 
    } 

    public static class AdminPropertyFilter extends SimpleBeanPropertyFilter { 

     @Override 
     protected boolean include(BeanPropertyWriter writer) { 
      // deprecated since 2.3 
      return true; 
     } 

     @Override 
     protected boolean include(PropertyWriter writer) { 
      if (writer instanceof BeanPropertyWriter) { 
       return shouldIncludeAllFields || ((BeanPropertyWriter) writer).getAnnotation(Admin.class) == null; 
      } 
      return true; 
     } 
    } 

    public static void main(String[] args) throws JsonProcessingException { 
     User user = new User("email", "secret"); 
     ObjectMapper mapper = new ObjectMapper(); 
     mapper.setFilters(new SimpleFilterProvider().addFilter("admin-filter", new AdminPropertyFilter())); 
     System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user)); 
     shouldIncludeAllFields = true; 
     System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user)); 
    } 

} 

輸出:

{ 
    "email" : "email" 
} 
{ 
    "email" : "email", 
    "details" : "secret" 
} 
+0

感謝您一個很好的例子! –

+0

好的,在測試了不同的解決方案之後,自定義過濾器和FilterIntrospector似乎是我想要的方式。 –

+0

對於任何在線程中使用此代碼的人,使用shouldIncludeAllFields可能會產生併發問題。但只需創建2個ObjectMapper即可輕鬆修復,1個使用過濾器,1個不使用。 ObjectMapper是Threadsafe – muttonUp

0

這看起來像傑克遜非常酷的功能像@JsonView可怕的概念。我發現解決我的問題的唯一方法是:

@JsonInclude(Include.NON_NULL) 
@Entity 
public class User { 

    public static interface BasicView {} 
    public static interface AdminView {} 

    ... id and others ... 

    @JsonView({BasicView.class, AdminView.class}) // And this for EVERY field 
    @Column 
    private String email; 

    @Transient 
    private transient Details details; 

    @JsonView(AdminView.class) 
    public Details getDetails() { 
     if (details == null) { 
      details = ... compute Details ... 
     } 
     return details; 
    } 
} 

public class UserDetailsAction { 
    private static final ObjectWriter writer = new ObjectMapper() 
     .disable(MapperFeature.DEFAULT_VIEW_INCLUSION) 
     .writerWithView(User.BasicView.class); 
    private static final ObjectWriter writerAdmin = new ObjectMapper() 
     .disable(MapperFeature.DEFAULT_VIEW_INCLUSION) 
     .writerWithView(User.AdminView.class); 

    public String getUserAsJson(User user) { 
     return writer.writeValueAsString(user); 
    } 

    public String getUserAsJsonForAdmin(User user) { 
     return writerAdmin.writeValueAsString(user); 
    } 
} 

也許是有些幫助的。但我希望找到更好的解決方案,因爲不接受我自己的答案。

編輯:因爲接口可以擴展(多)接口,我可以使用:

public static interface AdminView extends BasicView {} 

,只是

@JsonView(BasicView.class) 

@JsonView({BasicView.class, AdminView.class})