golang 如何正确解析 Java 中 jackson 序列化的 json 数据?

29 天前
ZeroDu  ZeroDu
[
    "com.test.UserInfo",
    {
        "userName": "`13123",
        "email": "",
        "roleIds": [
            "java.util.ArrayList",
            [
                "109"
            ]
        ]
    }
]

如上,因为 jackson 在序列化时写入了类型信息,所以在 golang 中如何正确解析数据(忽略其中的类型信息)?

1893 次点击
所在节点   Go 编程语言  Go 编程语言
22 条回复
jov1
jov1
29 天前
这个数据看起来更像是对序列化后的对象做了 toString()操作返回的字符串,肯定不是标准的 json ,即便带有类信息比如存到 redis ,使用 jackson 序列化完也应该是这样的结构,不会出现 "java.util.ArrayList"这种的
{
"@type": "com.xxx.xxx.XXX",
"ids": [
111,22
],
"name": "你好"
}
guyeu
guyeu
29 天前
最好让上游改一下序列化方式,把类型信息当作字段放进 json ,如

```json
{
"@type": "com.test.UserInfo",
"userName": "`13123",
"email": "",
"roleIds": [
"java.util.ArrayList",
[
"109"
]
]
}
```

这样你只需要简单配置下自己这边的反序列化器忽略`@type`字段(很多时候也不需要配置,json 库默认忽略不认识的字段)。
guyeu
guyeu
29 天前
我说的这个修改需要上游改一下这个类上`@JsonTypeInfo`注解的属性,或者修改下自己的`ObjectMapper`。
guyeu
guyeu
29 天前
u1s1 ,Jackson 把多态对象的类型信息当作数组的元素序列化的方式略微少见,正经的 API 还是尽可能避免使用多态数据,或者专门定义一个描述类型信息的枚举,然后根据这个枚举来序列化/反序列化,使用 Jackson 也可以较简单地实现这样的机制。
zhuisui
zhuisui
29 天前
```
// nodejs Buffer
> Buffer.from([1]).toJSON()
{ type: 'Buffer', data: [ 1 ] }
```
特定类型的对象 json 序列化结果本来就依赖于类型,默认行为只会考虑本平台的反序列化。
要想跨平台识别,必须自定义序列化结果。
json 本身只是信息携带标准格式,没什么非法不非法一说。
body007
body007
29 天前
我这边是用 github.com/json-iterator/go 这个库的 jsoniter.Get 方法,示例如下,我是默认 "com.test.UserInfo" 和 "java.util.ArrayList" 这类数据都在第 0 项里面,所以用 data.Get(1) 取第 1 项。

```go
package main

import (
"fmt"

jsoniter "github.com/json-iterator/go"
)

func main() {
s := `
[
"com.test.UserInfo",
{
"userName": "13123",
"email": "a@qq.com",
"roleIds": [
"java.util.ArrayList",
[
"109","209","309"
]
]
}
]`
data := jsoniter.Get([]byte(s), 1)
var (
userName = data.Get("userName").ToString()
email = data.Get("email").ToString()

roleIds []string
)
data.Get("roleIds", 1).ToVal(&roleIds)
fmt.Printf("userName: %s, email: %s, roleIds: %#v\n", userName, email, roleIds)
}
```
fengjianche
29 天前
json 不是都一样的吗?怎么还跟语言有关系
git00ll
29 天前
让上游不要吧类型搞出来,这不是标准的 json
Erroad
29 天前
说明没做好序列化,变成了一堆 Object 或者说 interface 的数组
afutureus
29 天前
我盲猜是 redis 内的数据...
000sitereg
29 天前
这个都不算 json 字符串,一眼看着像而已
jhdxr
29 天前
@000sitereg @git00ll @jov1

一堆说这不是 json/不是标准的 json 的。。。

这 json 字符串哪不标准了?

有规定说 json 里一个数组内的所有元素必须是同一个类型吗?虽然我也觉得这种用法很奇葩,但并不代表这种用法是非法的。
siweipancc
29 天前
一眼 redis json ,设置 @type ,jackson 给前端就没问题了,gson 忽略未知 field 试试
shyangs
29 天前
通過了 JSON 驗證器, JSON 驗證器說是標準的 json.

你若不能控制上游,則叫上游拿 API 文件出來, 看文件上是不是說這個 API 的 json 陣列第一個元素固定是類型.

或者你能控制上游,直接改上游.
ZeroDu
29 天前
@body007 #6 这个适合单独的处理一些
kingcanfish
28 天前
@jhdxr JSON is built on two structures:

A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
https://www.json.org/json-en.html
jhdxr
28 天前
@kingcanfish 没问题啊,OP 贴的这个哪儿不符合了?
a132811
28 天前
递归移除一下就可以了:
```
package main

import (
"encoding/json"
"fmt"
)

func removeJavaTypes(input string) (string, error) {
var data interface{}
if err := json.Unmarshal([]byte(input), &data); err != nil {
return "", fmt.Errorf("failed to unmarshal json: %w", err)
}

cleanedData, err := recursivelyRemoveTypes(data)
if err != nil {
return "", err
}

outputBytes, err := json.Marshal(cleanedData)
if err != nil {
return "", fmt.Errorf("failed to marshal json: %w", err)
}
return string(outputBytes), nil
}

func recursivelyRemoveTypes(data interface{}) (interface{}, error) {
switch v := data.(type) {
case []interface{}:
if len(v) == 2 {
_, isString := v[0].(string)
if isString {
return recursivelyRemoveTypes(v[1])
}
}
for i := range v {
var err error
v[i], err = recursivelyRemoveTypes(v[i])
if err != nil {
return nil, err
}

}
return v, nil

case map[string]interface{}:
for key := range v {
var err error
v[key], err = recursivelyRemoveTypes(v[key])
if err != nil {
return nil, err
}
}
return v, nil
default:
return data, nil
}
}

func main() {
input := `
[
"com.test.UserInfo",
{
"userName": "13123",
"email": "a@a.com",
"roleIds": [
"java.util.ArrayList",
[
"109"
]
]
}
]
`
output, err := removeJavaTypes(input)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Output:", output)
}

}
```
ZeroDu
26 天前
@a132811 #18 不错,代码可用。就是耗时是原来的二倍,有没有优化思路
layxy
14 天前
严格来说这不是 json 数据吧, jackson 序列化有配置可以决定是否带类型类型信息,但是类型信息也不是这样的结构,整体还是标准 json 结构

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1107120

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX