我如何告诉杰克逊忽略我无法控制源代码的属性?

Posted

技术标签:

【中文标题】我如何告诉杰克逊忽略我无法控制源代码的属性?【英文标题】:How can I tell jackson to ignore a property for which I don't have control over the source code? 【发布时间】:2011-11-17 07:12:05 【问题描述】:

长话短说,我的一个实体有一个GeometryCollection,当您调用“getBoundary”时会引发异常(为什么这是另一本书,现在让我们说这是它的工作方式)。

有没有办法告诉杰克逊不要包含那个特定的吸气剂?我知道当我拥有/控制代码时可以使用@JacksonIgnore。但情况并非如此,jackson 通过对父对象的不断序列化来结束这一点。我在杰克逊文档中看到了一个过滤选项。这是一个合理的解决方案吗?

谢谢!

【问题讨论】:

【参考方案1】:

您可以使用Jackson Mixins。例如:

class YourClass 
  public int ignoreThis()  return 0;     

有了这个 Mixin

abstract class MixIn 
  @JsonIgnore abstract int ignoreThis(); // we don't need it!  

有了这个:

objectMapper.getSerializationConfig().addMixInAnnotations(YourClass.class, MixIn.class);

编辑:

感谢 cmets,在 Jackson 2.5+ 中,API 发生了变化,应该使用 objectMapper.addMixIn(Class<?> target, Class<?> mixinSource) 调用

【讨论】:

如果属性是机器生成的并且名称中包含不受支持的字符?喜欢 '@'? JVM 允许,但 Java 编译器不允许。杰克逊对此有解决方案吗? 在杰克逊 2.2 中是objectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource); 如何通过指定属性名称而不是 getter 来忽略? 也适用于 mixin 类中定义的属性:@JsonIgnore private HttpClient httpClient;【参考方案2】:

如果您想始终排除任何类的某些属性,您可以使用setMixInResolver 方法:

    @JsonIgnoreProperties("id", "index", "version")
    abstract class MixIn 
    

    mapper.setMixInResolver(new ClassIntrospector.MixInResolver()
        @Override
        public Class<?> findMixInClassFor(Class<?> cls) 
            return MixIn.class;  
        

        @Override
        public ClassIntrospector.MixInResolver copy() 
            return this;
        
    );

【讨论】:

唯一对我有用的东西,谢谢!【参考方案3】:

使用 Java 类

new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

使用注解

@JsonIgnoreProperties(ignoreUnknown=true)

【讨论】:

【参考方案4】:

基于注释的方法更好。但有时需要手动操作。为此,您可以使用 ObjectWriterwithout 方法。

ObjectMapper mapper   = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
ObjectWriter writer   = mapper.writer().withoutAttribute("property1").withoutAttribute("property2");
String       jsonText = writer.writeValueAsString(sourceObject);

【讨论】:

这种方法对我不起作用,但 mixin 可以。序列化后我仍然得到忽略的属性。当我们有 withoutAttribute() 时为什么我们有 mixins? "当我们有 withoutAttribute() 时,为什么我们有 mixins?" - Mixins 不能动态设置。 ***.com/a/11849523/3105386,而我们可以使用“withoutAttributes”来做到这一点。这可能是原因之一。 其次,当您想忽略具有特定名称的字段并且不关心类时,使用“withoutAttribute”。 Mixin 可以帮助您更精细地定义那些需要忽略这些字段的特定类。 @ErranMorad 你有没有弄清楚为什么 withoutAttribute() 不起作用? ObjectWriter.withoutAttribute 无法按照答案中的建议工作。 attribute 不引用输入数据的属性名称,并且从未在这样的上下文中引用,例如this comment 中所指出的。这种方法似乎是面向内部使用的,可以看到here。【参考方案5】:

这里还有一个好处是使用@JsonFilter。 这里有一些细节http://wiki.fasterxml.com/JacksonFeatureJsonFilter

【讨论】:

【参考方案6】:

我有一个类似的问题,但它与 Hibernate 的双向关系有关。我想展示关系的一侧并以编程方式忽略另一侧,这取决于我正在处理的视图。如果你不能这样做,你最终会得到讨厌的***Exceptions。例如,如果我有这些对象

public class A
  Long id;
  String name;
  List<B> children;


public class B
  Long id;
  A parent;

如果我正在查看 A,我希望以编程方式忽略 B 中的 parent 字段,如果我正在查看 B,则忽略 A 中的 children 字段。

我开始使用 mixins 来做这件事,但很快就变得很糟糕;你有这么多无用的类,它们只是为了格式化数据而存在。我最终编写了自己的序列化程序以更简洁的方式处理这个问题:https://github.com/monitorjbl/json-view。

它允许您以编程方式指定要忽略的字段:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JsonView.class, new JsonViewSerializer());
mapper.registerModule(module);

List<A> list = getListOfA();
String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(B.class, match()
        .exclude("parent")));

它还允许您通过通配符匹配器轻松指定非常简化的视图:

String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(A.class, match()
        .exclude("*")
         .include("id", "name")));

在我原来的例子中,需要像这样的简单视图是为了显示关于父/子的最低限度,但它也对我们基于角色的安全性很有用。对象的权限较低的视图需要返回较少的对象信息。

所有这些都来自序列化程序,但我在我的应用程序中使用了 Spring MVC。为了让它正确处理这些情况,我编写了一个集成,您可以将其放入现有的 Spring 控制器类中:

@Controller
public class JsonController 
  private JsonResult json = JsonResult.instance();
  @Autowired
  private TestObjectService service;

  @RequestMapping(method = RequestMethod.GET, value = "/bean")
  @ResponseBody
  public List<TestObject> getTestObject() 
    List<TestObject> list = service.list();

    return json.use(JsonView.with(list)
        .onClass(TestObject.class, Match.match()
            .exclude("int1")
            .include("ignoredDirect")))
        .returnValue();
  

两者都可以在 Maven Central 上找到。我希望它可以帮助其他人,这是杰克逊的一个特别丑陋的问题,对我的情况没有很好的解决方案。

【讨论】:

Match.match() 的导入是什么?【参考方案7】:

另一种可能性是,如果您想忽略所有未知属性,您可以按如下方式配置映射器:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

【讨论】:

如果我们可以将 objectMapper 配置为仅忽略特定属性,那就太好了。即报告所有新/未知字段的异常,除了让我们说“myfield”。类似mapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] "myField")); 请注意,这也可以在阅读器上使用without() 进行配置,如:mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) 我强烈建议不要使用这种机制。 Jackson 的“严格”心态,导致在未知/未处理的字段上引发错误是它的优势之一,并且与 Java 的静态类型/编译时分析性质很好地匹配。最好选择不处理一组给定的忽略字段。【参考方案8】:

如前所述,混合注释在这里工作得很好。除了每个属性 @JsonIgnore 之外的另一种可能性是使用 @JsonIgnoreType 如果您有一个永远不应包含的类型(即,如果应该忽略 GeometryCollection 属性的所有实例)。然后,您可以直接添加它(如果您控制类型),也可以使用混入,例如:

@JsonIgnoreType abstract class MixIn  
// and then register mix-in, either via SerializationConfig, or by using SimpleModule

如果您有很多类都有一个“IgnoredType getContext()”访问器左右(许多框架都是这种情况),这会更方便

【讨论】:

以上是关于我如何告诉杰克逊忽略我无法控制源代码的属性?的主要内容,如果未能解决你的问题,请参考以下文章

如果值为空,如何告诉杰克逊在序列化期间忽略一个字段?

杰克逊在序列化时忽略@Size

如何强制杰克逊在控制器中调用对象(dto)中所有属性的 Set 方法?

如何告诉 gcov 忽略不可命中的 C++ 代码行?

如何告诉 git 忽略个别行,即特定代码行的 gitignore [重复]

android 杰克逊 @JsonIgnore 属性