提问人:kennarddh 提问时间:10/27/2023 更新时间:10/27/2023 访问量:74
如何使用java gson解析动态json对象值
How to parse dynamic json object value with java gson
问:
我有2个班级
class X {
public String name;
public int age;
}
class Y {
public float score;
}
json是这样的
{
"type": "X",
"data": {
"name": "myname",
"age": 20
}
}
或
{
"type": "Y",
"data": {
"score": 10
}
}
如何使用 gson 解析 json,但如果类型字段是,则数据将是类实例X
X
答:
1赞
Abra
10/27/2023
#1
您希望根据 type 元素的值反序列化 JSON。因此,您可以解析 JSON 并提取 type 元素的值。然后提取数据元素并使用 Gson 将其反序列化为 Java 对象。
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class GsonTest {
public static void main(String[] args) {
String json = """
{
"type": "X",
"data": {
"name": "myname",
"age": 20
}
}
""";
JsonElement root = JsonParser.parseString(json);
JsonObject obj = root.getAsJsonObject();
JsonElement typeElem = obj.get("type");
String type = typeElem.getAsString();
JsonElement dataElem = obj.get("data");
Gson gson = new Gson();
Class<?> theClass;
if ("X".equals(type)) {
theClass = X.class;
}
else if ("Y".equals(type)) {
theClass = Y.class;
}
else {
theClass = null;
}
if (theClass != null) {
Object result = gson.fromJson(dataElem, theClass);
System.out.println(result);
}
}
}
上面的代码使用了 Java 15 中添加的文本块。
我在类中添加了一个 toString 方法:X
public String toString() {
return String.format("%s:%d", name, age);
}
当我运行上面的代码时,我得到以下内容:
myname:20
请注意,通常会创建类和类 JavaBeans,即您需要添加“getters”和“setter”。X
Y
下面是一个完整的代码:
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class GsonTest {
public static void main(String[] args) {
String json = """
{
"type": "Y",
"data": {
"score": 10
}
}
""";
JsonElement root = JsonParser.parseString(json);
JsonObject obj = root.getAsJsonObject();
JsonElement typeElem = obj.get("type");
String type = typeElem.getAsString();
JsonElement dataElem = obj.get("data");
Gson gson = new Gson();
Class<?> theClass;
if ("X".equals(type)) {
theClass = X.class;
}
else if ("Y".equals(type)) {
theClass = Y.class;
}
else {
theClass = null;
}
if (theClass != null) {
Object result = gson.fromJson(dataElem, theClass);
System.out.println(result);
}
}
}
class X {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return String.format("%s:%d", name, age);
}
}
class Y {
private float score;
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
public String toString() {
return Float.toString(score);
}
}
请参阅 Gson 用户指南
评论
0赞
Marcono1234
10/28/2023
为了避免任何混淆:Gson 不需要 getter 和 setter 方法,实际上它只是忽略它们并直接访问字段。因此,它只取决于您的代码风格,或者您如何使用类,以及是否要添加 getter 和 setter。X
Y
0赞
kennarddh
10/27/2023
#2
我发现在谷歌吟游诗人的一些问题之后......
public static class CustomTypeAdapter extends TypeAdapter<Object> {
@Override
public void write(JsonWriter out, Object value) {
}
@Override
public Object read(JsonReader reader) {
JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject();
String type = jsonObject.get("type").getAsString();
System.out.println(type);
return switch (type) {
case "X" -> new Gson().fromJson(jsonObject.get("data"), X.class);
case "Y" -> new Gson().fromJson(jsonObject.get("data"), Y.class);
default -> throw new JsonParseException("Unknown type: " + type);
};
}
}
然后我像这样使用它
JsonReader reader = new Gson().newJsonReader(new StringReader("{\"type\":\"X\",\"data\":{\"name\":\"Name\",\"age\":10}}"));
Object output = new CustomTypeAdapter().read(reader);
System.out.println(((X) output).name);
但是有了这个,我不知道为什么我扩展了..我不认为我需要它。TypeAdapter<Object>
评论
1赞
Marcono1234
10/28/2023
虽然这可能会解决您的问题(目前),但它存在几个问题:创建效率低下且不继承原始实例设置的新实例,为空(至少它应该始终抛出异常以避免将来出现错误),首先有一个(使用您当前的代码,您可能可以直接使用里面的代码CustomTypeAdapter
Gson
Gson
CustomTypeAdapter.write
TypeAdapter
CustomTypeAdapter.read
)
0赞
kennarddh
10/28/2023
@Marcono1234是的,我现在添加了 write 方法的代码,我不再扩展,并且每次读/写都要创建新实例,我可以通过在构造函数中缓存 Gson 实例来解决它吗?TypeAdapter<Object>
0赞
Marcono1234
10/28/2023
您可能可以应用@Abra的 anwser;在功能方面,它似乎完全相同
2赞
cloudchamb3r
10/27/2023
#3
var m = new TreeMap();
m.put("type", X.class.getSimpleName());
m.put("data", new X("myname", 20));
var gson = new Gson();
var json = gson.toJson(m);
如果您不想创建自定义适配器,请尝试使用 Map!
这可能是最简单的解决方案之一
评论
1赞
kennarddh
10/27/2023
这是为了写?我认为如此。我还需要写anw..泰
评论
Reflection
Object