我如何告诉杰克逊忽略我无法控制源代码的属性?
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】:基于注释的方法更好。但有时需要手动操作。为此,您可以使用 ObjectWriter 的 without 方法。
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 的双向关系有关。我想展示关系的一侧并以编程方式忽略另一侧,这取决于我正在处理的视图。如果你不能这样做,你最终会得到讨厌的***Exception
s。例如,如果我有这些对象
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()”访问器左右(许多框架都是这种情况),这会更方便
【讨论】:
以上是关于我如何告诉杰克逊忽略我无法控制源代码的属性?的主要内容,如果未能解决你的问题,请参考以下文章
如何强制杰克逊在控制器中调用对象(dto)中所有属性的 Set 方法?