杰克逊 – 基于多个属性的自定义TypeId解析器

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

Jackson - Custom TypeId Resolver based on more than one property

问题

我想使用Jackson根据多个属性对JSON对象进行反序列化;更具体地说,对于那些根据其ID字段可以推断出TYPE的对象。

这在REST API实现中是必需的,其中可以观察到两种简化情况:

  1. 对象即将被创建,在这种情况下它尚未具有ID,但需要TYPE。
  2. 对象即将被更新,在这种情况下提供了ID,可以推断出TYPE。

第一种情况下的对象如下:

{
    "type": "dog",
    "name": "rex"
}

第二种情况下的对象如下:

{
    "id": "D10000",
    "name": "lady"
}

我正在寻找一种将这两种对象都反序列化为Dog对象的方法。

目前,第二种情况被序列化如下:

{
    "type": "dog",
    "id": "D10000",
    "name": "lady"
}

... 这样也能正常工作,但有点冗余,我正在寻找一种在第二种情况下去除"type"属性的方法。

因此,首先,是否可以使用当前版本的Jackson库来实现,如果可能的话,如何实现?

提前感谢。

英文:

I would like to deserialize JSON objects based on more than one property using Jackson; more specfically, I have objects for which, based on their ID field, the TYPE can be inferred.

This is needed for a REST API implementation, where two simplified situations can be observed :

  1. the object is about to be created, in which case it doesn't have an ID yet, but the TYPE is required
  2. the object is about to be updated, in which case the ID is provided, and the TYPE can be inferred

The object in the first case is like this :

{
    "type" : "dog",
    "name" : "rex"
}

The second case is like this :

{
    "id" : "D10000",
    "name" : "lady"
}

I'm looking for a way to deserialize both object to a Dog object.

Currently, the second case is serialized like his :

{
    "type" : "dog"
    "id" : "D10000",
    "name" : "lady"
}

... and it works just fine, but it's kind of redundant and I'm looking for a way to remove the "type" property in the second case.

So, first of all, is it possible using the current implementation of the Jackson library, and, obviously, if possible, how ?

Thanks in advance.

答案1

得分: 1

最终,已实施解决方案;将其发布在这里,供日后有人需要时参考。

解决方案是在需要时注入所需数据(当“TYPE”缺失且可以从“ID”推断出时),但是在库解析每个根节点之前进行。

// ObjectMapper om2;
// ...

final JsonNode jsonROOTNode = om.readTree(inputJSON);
Iterator<Entry<String, JsonNode>> iterator = jsonROOTNode.fields();

while (iterator.hasNext()) {
    Entry<String, JsonNode> e = iterator.next();
    if (e.getValue().isObject() && e.getValue().isContainerNode()) {
        injectData(e.getValue());
    }
    // 其余处理...
}

数据注入如下所示:

void injectData(JsonNode _value) {
    if (_value.has("TYPE")) {
        // 一切正常
    } else if (_value.has("ID")) {
        // 推断并注入'prefix'
        String _TYPE = ... // 从ID中推断出
        ((ObjectNode) _value).put("TYPE", _prefix);
    }

    // 递归
    Iterator<Entry<String, JsonNode>> iterator = _value.fields();
    while (iterator.hasNext()) {
        Entry<String, JsonNode> e = iterator.next();
        if (e.getValue().isArray()) {
            Iterator<JsonNode> arrayIterator = ((ArrayNode) e.getValue()).iterator();
            while (arrayIterator.hasNext()) {
                injectPrefixes(arrayIterator.next());
            }
        } else if (e.getValue().isContainerNode()) {
            injectPrefixes(e.getValue());
        }
    }
}
英文:

Finally, implemented a workaround; posting it here for reference in case someone needs it someday.

The solution is to inject the required data when needed (the TYPE when can it's missing and can be inferred from the ID), but before each root node is parsed by the library.

// ObjectMapper om2;
// ...

final JsonNode jsonROOTNode = om.readTree(inputJSON);
Iterator&lt;Entry&lt;String, JsonNode&gt;&gt; iterator = jsonROOTNode.fields();

while (iterator.hasNext()) {
    Entry&lt;String, JsonNode&gt; e = iterator.next();
    if (e.getValue().isObject() &amp;&amp; e.getValue().isContainerNode()) {
        injectData(e.getValue());
    }
    // rest of processing ...
}

and the data injection is performed like this :

void injectData(JsonNode _value)	{
	if (_value.has(&quot;TYPE&quot;)) {
		// we&#39;re good
	}
	else if (_value.has(&quot;ID&quot;)) {
		// infer and inject &#39;prefix&#39;
		String _TYPE = ... // infer it from ID
		((ObjectNode)_value).put(&quot;TYPE&quot;, _prefix);
	}
	
	// recurse
	Iterator&lt;Entry&lt;String, JsonNode&gt;&gt; iterator = _value.fields();
	while (iterator.hasNext()) {
		Entry&lt;String, JsonNode&gt; e = iterator.next();
		if (e.getValue().isArray()) {
			Iterator&lt;JsonNode&gt; arrayIterator = ((ArrayNode)e.getValue()).iterator();
			while (arrayIterator.hasNext()) {
				injectPrefixes(arrayIterator.next());
			}
		}
		else if (e.getValue().isContainerNode()) {
			injectPrefixes(e.getValue());
		}
	}
}

huangapple
  • 本文由 发表于 2020年9月23日 19:10:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/64026654.html
匿名

发表评论

匿名网友

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

确定