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

2025 年 1 月 22 日
 ZeroDu
[
    "com.test.UserInfo",
    {
        "userName": "`13123",
        "email": "",
        "roleIds": [
            "java.util.ArrayList",
            [
                "109"
            ]
        ]
    }
]

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

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

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

这样你只需要简单配置下自己这边的反序列化器忽略`@type`字段(很多时候也不需要配置,json 库默认忽略不认识的字段)。
guyeu
2025 年 1 月 22 日
我说的这个修改需要上游改一下这个类上`@JsonTypeInfo`注解的属性,或者修改下自己的`ObjectMapper`。
guyeu
2025 年 1 月 22 日
u1s1 ,Jackson 把多态对象的类型信息当作数组的元素序列化的方式略微少见,正经的 API 还是尽可能避免使用多态数据,或者专门定义一个描述类型信息的枚举,然后根据这个枚举来序列化/反序列化,使用 Jackson 也可以较简单地实现这样的机制。
zhuisui
2025 年 1 月 22 日
```
// nodejs Buffer
> Buffer.from([1]).toJSON()
{ type: 'Buffer', data: [ 1 ] }
```
特定类型的对象 json 序列化结果本来就依赖于类型,默认行为只会考虑本平台的反序列化。
要想跨平台识别,必须自定义序列化结果。
json 本身只是信息携带标准格式,没什么非法不非法一说。
body007
2025 年 1 月 22 日
我这边是用 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
2025 年 1 月 22 日
json 不是都一样的吗?怎么还跟语言有关系
git00ll
2025 年 1 月 22 日
让上游不要吧类型搞出来,这不是标准的 json
Erroad
2025 年 1 月 22 日
说明没做好序列化,变成了一堆 Object 或者说 interface 的数组
afutureus
2025 年 1 月 22 日
我盲猜是 redis 内的数据...
000sitereg
2025 年 1 月 22 日
这个都不算 json 字符串,一眼看着像而已
jhdxr
2025 年 1 月 22 日
@000sitereg @git00ll @jov1

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

这 json 字符串哪不标准了?

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

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

或者你能控制上游,直接改上游.
ZeroDu
2025 年 1 月 22 日
@body007 #6 这个适合单独的处理一些
kingcanfish
2025 年 1 月 23 日
@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
2025 年 1 月 23 日
@kingcanfish 没问题啊,OP 贴的这个哪儿不符合了?
a132811
2025 年 1 月 23 日
递归移除一下就可以了:
```
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
2025 年 1 月 25 日
@a132811 #18 不错,代码可用。就是耗时是原来的二倍,有没有优化思路
layxy
2025 年 2 月 6 日
严格来说这不是 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