我如何从一个Java类中提取Jackson属性名称,当序列化已经被注解修改?

huangapple go评论90阅读模式
英文:

How do I extract the Jackson property names from a java class when the serialization has been altered by annotation?

问题

我有一个相当奇怪的问题。我有一个数据对象系统,规模相当大,并且具有各种各样的属性。它们正在使用JSON进行序列化和反序列化,在许多情况下,字段名称已经被注解修改过。我有与该JSON交互并且几乎不关心底层代码做了什么的用户,只要他们知道在JSON中放什么来使其正常工作。我想为他们提供一个端点,他们可以访问,可以在那里识别一个类,并让它返回字段名称(就像在序列化的JSON中显示的那样)。我有类对象,并且在使用反射方面有一些能力。

我考虑了一些选项。我的初始计划是只使用反射来处理所有事情,但我意识到这将要求我自己追踪所有可能影响Jackson的注解,以尝试获得正确的逻辑。听起来这是一项巨大而不必要的工作,几乎肯定会在我试图弄清楚逻辑的时候产生一些丑陋而又隐蔽的错误。毕竟,Jackson已经有了这个逻辑。看起来我应该能以某种方式利用它。

我考虑过创建类的虚拟版本,对其进行序列化,然后从结果JSON中读取字段名称,但这里有大量的类,其中许多是复杂的,并且其中许多属性指向彼此。在这种情况下,创建正确工作的字段自动填充似乎需要大量的工作,这也可能会产生许多不必要的错误。

在Jackson中,确实有某个逻辑知道如何识别这些字段名称(特别是实际被序列化的字段的序列化字段名称)。看起来应该可以仅通过ObjectMapper和我想要信息的类来确定。这可能吗?我应该如何做呢?我在网上找不到指示(因为所有的文章都关于如何首先更改名称),而且仅仅阅读Jackson中的类文件也不起作用。(注释相对简洁,我要找的内容非常具体。即使我找到了,我也不知道如何确保它实际上给我需要的东西,而不是其他非常相似的东西。)

作为一个额外的内容,如果有一种方式可以知道字段的Java类作为其值,那将更好,但是我至少有一些解决方法,我认为我可能能够让它们可行。获取精确的字段名称更重要。

英文:

I have a somewhat odd problem. I have a system of data objects fo significant size, with a wide variety of properties. They're being serialized and deserialized with JSON, and in many cases, the field names have been altered by annotation. I have users who interact with that JSON and could not care less what the underlying code does, as long as they know what to put int eh JSON to make it work right. I'd like to provide them with an endpoint they can go to, where they can identify a class, and have it spit back the field name (as it would appear in the serialized JSON). I have the class object and have some ability in working with reflection.

I have considered a few options. My initial plan was that I was just going to handle everything with reflection, but I realized that that would require me to chase around all of the Jackson-affecting annotations myself to try to get the logic right. That sounds like a huge amount of unnecessary effort that would almost certainly generate a few ugly and well-hidden bugs as I wound up getting the logic not-quite-right. Jackson already has this logic, after all. It seems like I should be able to harness it in some way.

I have considered making a dummy version of the class, serializing it, and reading the field names off of the JSON that results, but there are a large number of classes here, many of them are complicated, and many of them have properties that point at one another. Under those conditions, making the sort of field auto-populate that would make that work right... well, that also sounds like a great deal of hopefully-unnecessary, bug-generating work.

There is the logic in Jackson somewhere that knows how to identify these field names (specifically the serialized field names for the fields that actually are being serialized). It seems like it should be possible to determine just with the ObjectMapper and the class that I want the information on. Is it possible? How should I do it? I haven't been able to find instructions online (fuzzed-out by all the articles on how to change the name in the first place) and just reading the class files in Jackson isn't doing the trick either. (The comments are relatively terse, and what I'm looking for is very specific. Even if I did find it, I don't know how I would make sure that it was actually giving me the thing I need, rather than some other, very similar thing.)

As a bonus, if there were some way to know which java class the field had as its value, that would be even better, but I have at least a few workarounds for that that I think I might be able to make workable. Getting a precise field names is more important.

答案1

得分: 1

好的,以下是翻译好的内容:

// 我们使用jacksObjectMapper来获取序列化器,从而可以从该序列化器中获取逻辑属性列表。
// 这个过程的目的是要为用户提供与用户所查看内容相对应的数据。
// 这意味着我们特别想要 jackson 将要序列化和反序列化的字段,以及 jackson 将使用的名称。
// 这是获得这些内容的方法。这并不像你想象的那么容易。

SerializerProvider serProv = jacksonObjectMapper.getSerializerProviderInstance();
JsonSerializer serializer = serProv.findValueSerializer(inputClass);

Iterator<PropertyWriter> logicalProperties = serializer.properties();

// 一旦我们获得了逻辑属性,我们从中获取字段名称和值类,并用这些来填充其他所有内容。
while (logicalProperties.hasNext()) {

    PropertyWriter propw = logicalProperties.next();
    String jsonFieldName = propw.getName();
    ...
}

现在过了这一点,将这些与Java反射字段对齐仍然是有趣的,因为属性是从那里生成的,这样我实际上可以获取那些值类。不过这是另一个问题,其解决方案更加依赖于个别的代码库。

英文:

Well, I managed to find my answer.

// We&#39;re using the jacksObjectMapper to grab the serializer, so that
// we can get the list of logical properties from said serializer.
// The point of this process is that we want to give the user the
// data that corresponds with what said user is looking at.  That
// means we specifically want the fields that jackson will serialize
// and deserialize, with the names that jackson will use.  This is
// the way to get that.  It was not as easy to find as you might think.

SerializerProvider serProv = jacksonObjectMapper.getSerializerProviderInstance();
JsonSerializer serializer = serProv.findValueSerializer(inputClass);

Iterator&lt;PropertyWriter&gt; logicalProperties = serializer.properties();

// Once we have the logical properties, we grab the field names and 
// value classes from that, and use that to populate everything else.
while (logicalProperties.hasNext()) {

    PropertyWriter propw = logicalProperties.next();
    String jsonFieldName = propw.getName();
    ...
}

Now past that point, it was still somewhat interesting to line it up with the java reflection fields that the properties were spawned from, so that I could actually get those value classes, but that was a different issue, and one with a solution far more dependent on the individual codebase.

huangapple
  • 本文由 发表于 2020年9月21日 12:29:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/63986218.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定