杰克逊:忽略getter,但不使用@JsonView
Posted
技术标签:
【中文标题】杰克逊:忽略getter,但不使用@JsonView【英文标题】:jackson: ignore getter, but not with @JsonView 【发布时间】:2014-06-04 00:47:37 【问题描述】:我正在寻找仅在某些情况下序列化瞬态信息的可能性:
@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、email 和其他字段,但看不到详细信息。这工作正常。但我对 getUserAsJsonForAdmin 也看到了同样的情况,也没有详细说明。如果我删除 @JsonIgnore 注释 - 我确实会在两个调用中看到详细信息。
我做错了什么,有什么好的方法吗?谢谢!
【问题讨论】:
【参考方案1】:看起来杰克逊对@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)
【讨论】:
如何为作为 REST 响应发送的 POJO 执行此操作?注意:我没有使用 ObjectWriter 使用 null 而不是某些特定视图会有所帮助吗? @JsonView(null) // 目标:一直忽略,除了下一行【参考方案2】:对于您的用例,您可能会发现使用 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"
【讨论】:
好吧,在测试了不同的解决方案之后,自定义过滤器和FilterIntrospector似乎是我想走的一条路。 对于跨线程使用此代码的任何人,使用 shouldIncludeAllFields 存在潜在的并发问题。但只需创建 2 个 ObjectMapper 即可轻松修复,1 个带过滤器,1 个不带。 ObjectMappers 是线程安全的以上是关于杰克逊:忽略getter,但不使用@JsonView的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有jackson注释的情况下忽略反序列化的某些字段?
强制杰克逊在没有 JsonIgnore 的情况下忽略 isEmpty