Spring Boot中将JSON对象反序列化为抽象类

发布于 2025-01-20 02:31:21 字数 1072 浏览 1 评论 0原文

我有一个 JSON 对象,它有一个具有以下结构的键 (key1)

"key1": {
      "key2": "some value1",
      "key3": {
          "key4": "some value2",
          "key5": "some value3"
      }
}

键 3 是动态的,因为它也可以具有以下数据

"key1": {
      "key2": "some value1",
      "key3": {
          "key4": "some value2",
          "key5": "some value3"
          "key6": "some value4"
      }
}

"key1": {
      "key2": "some value1",
      "key3": {
          "key4": "some value2",
      }
}

只有这 3 个组合是可能的(键 3 有 2 个属性、3 个属性或只有 1 个属性)。

考虑到所有这些,我在 Java 中为 key3 声明了一个抽象类(假设为 Key3 类),认为 key3 可以有多个实现(每个具体类都有自己的字段)。

现在有一个由类 Key3 的变量组成的 POJO(具有 Key3 的引用变量)

public Class MYPOJO class{
 String variable1;
 String variable2;
 .
 .
 .
 
 Key3 variable;
 .
 .
 .
 int variable3;

}

现在,当 MYPOJO 发生反序列化时,它会失败,因为 Key3 是抽象的,因此无法使用所需的具体类实例化(具体类将是三个类中的一个 - 具有 1、2 或 3 个字段)。具体的类可以根据 JSON 中 key2 的值​​或 key3 中的值来决定。

谁能建议我一些可以解决这个问题的方法,实例化一个具体类并将其传递给抽象类的引用变量?

或者有更好的解决方法来处理它?

I have a JSON object which has a key (key1) with the following structure

"key1": {
      "key2": "some value1",
      "key3": {
          "key4": "some value2",
          "key5": "some value3"
      }
}

Key 3 is dynamic in that it can have the following data as well

"key1": {
      "key2": "some value1",
      "key3": {
          "key4": "some value2",
          "key5": "some value3"
          "key6": "some value4"
      }
}

or

"key1": {
      "key2": "some value1",
      "key3": {
          "key4": "some value2",
      }
}

Only these 3 combinations are possible (key 3 having 2 attributes, 3 attributes or just 1 attribute).

With all that in mind, I declared an abstract class (let's say Class Key3) for key3 in Java thinking that key3 can have multiple implementations (each concrete class will have their own fields).

Now there is a POJO composed of class Key3's variable (having a reference variable of Key3)

public Class MYPOJO class{
 String variable1;
 String variable2;
 .
 .
 .
 
 Key3 variable;
 .
 .
 .
 int variable3;

}

Now as the deserialization happens for MYPOJO, it fails as Key3 is abstract and hence can't be instantiated with a desired concrete class (concrete class will be either of the three classes - having 1, 2 or 3 fields). The concrete class can be decided on the basis of the value of key2 or whatever is present in key3 in JSON.

Can anyone suggest me something that can take care of this, instantiate a concrete class and pass it on to the reference variable of abstract class?

Or some better workaround to deal with it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

秋叶绚丽 2025-01-27 02:31:21

我不知道您在哪种环境中要使用这种挑选方法,所以让我告诉您如何在Springboot中进行操作。
如果确定是key1,key2,key3,我可以使用以下方法接收。

@PostMapping("/test")
public String test(@RequestBody Test userName){
    System.out.println(userName);
    return null;
}

@Data
@ToString
@Accessors(chain = true)public class Test {
    
    private String key;
    
    private String key2;
    
    private Map<String, Object> key3;
    }

控制台将结果打印为测试(key = aaa,key2 = some value1,key3 = {key4 = 16,key5 = jsf})。

证明可以通过使用MAP接收多个参数来完成避难所化,但是,此方法需要key1,key2和key3才能固定名称。

I don't know in what environment you want to use this deserialization method, so let me tell you how to do it in springboot.
If it is key1, key2, key3 is determined, I can use the following methods to receive.

@PostMapping("/test")
public String test(@RequestBody Test userName){
    System.out.println(userName);
    return null;
}

@Data
@ToString
@Accessors(chain = true)public class Test {
    
    private String key;
    
    private String key2;
    
    private Map<String, Object> key3;
    }

The console prints the result as Test(key=aaa, key2=some value1, key3={key4=16, key5=jsf}).

It is proved that the deserialization can be completed by using map to receive multiple parameters, however, this method requires key1, key2, and key3 to be fixed names.

粉红×色少女 2025-01-27 02:31:21

所以基本上你有两个选择。如果您知道总会有相同的结构,您可以创建用于响应的类并使用例如 GSON 进行反序列化。对象中总是有三个字段,JSON 响应中没有的字段为 null。第二个选项是在 Key3 类中创建字符串列表来存储这些值,但必须手动完成。

情况 1:

public class Response {

@SerializedName("key1")
private Key1 key1;

// getters, setters
}

Key1 类

public class Key1{

@SerializedName("key2")
private String key2;

@SerializedName("key3")
private Key3 key3;

// getters, setters
}

Key3 类

public class Key3{

@SerializedName("key5")
private String key5;

@SerializedName("key6")
private String key6;

@SerializedName("key4")
private String key4;

// getters, setters
}

然后您可以使用以下代码反序列化 JSON 响应

    GsonBuilder gsonBuilder = new GsonBuilder();
    Response response = gsonBuilder.create().fromJson(jsonResponse, Response.class);
    System.out.println(response);

请记住,如果 JSON 响应不包含(例如 key6),则该值将为 null。

案例2:

public class Key3{

List<String> keys = new ArrayList<>();

// geters, setters
}

反序列化

    Gson gson = new Gson();
    Object o = gson.fromJson(jsonResponse, Object.class);
    if (o instanceof Map) {
        Map map = (Map) o;
        Collection firstLevelBranchMapValues = map.values();
        Key1 key1 = new Key1();
        for (var val : firstLevelBranchMapValues) {
            if (val instanceof LinkedTreeMap){
                Map secondLevelBranchMap = ((LinkedTreeMap) val);
                for (var secondLevelBranchMapValues : secondLevelBranchMap.values()) {
                    if (secondLevelBranchMapValues instanceof LinkedTreeMap){
                        // map of some value2, some value3, some value4
                        Map thirdLevelBranchMap = ((LinkedTreeMap) secondLevelBranchMapValues);
                        Key3 key3 = new Key3();
                        for (var thirdLevelBranchMapValues : thirdLevelBranchMap.values()){
                            // returns some value2, some value3, some value4 in following iterations
                            key3.getKeys().add(thirdLevelBranchMapValues.toString());
                        }
                        key1.setKey3(key3);
                    } else {
                        // returns some value1
                        key1.setKey2(secondLevelBranchMapValues.toString());
                    }
                }
            }
        }
    }

So basically you have two options. If you know there'll always be the same structure you can create classes for response and deserialize with for example GSON. There are always three fields in object and the ones that are not in JSON response are null. The second option is to create list of strings in Key3 class to store those values but it has to be done manually.

Case 1:

public class Response {

@SerializedName("key1")
private Key1 key1;

// getters, setters
}

Key1 class

public class Key1{

@SerializedName("key2")
private String key2;

@SerializedName("key3")
private Key3 key3;

// getters, setters
}

Key3 class

public class Key3{

@SerializedName("key5")
private String key5;

@SerializedName("key6")
private String key6;

@SerializedName("key4")
private String key4;

// getters, setters
}

Then you can deserialize JSON response with following code

    GsonBuilder gsonBuilder = new GsonBuilder();
    Response response = gsonBuilder.create().fromJson(jsonResponse, Response.class);
    System.out.println(response);

Keep in mind if JSON response doesnt contain, for example key6, this value will be null.

Case 2:

public class Key3{

List<String> keys = new ArrayList<>();

// geters, setters
}

Deserialization

    Gson gson = new Gson();
    Object o = gson.fromJson(jsonResponse, Object.class);
    if (o instanceof Map) {
        Map map = (Map) o;
        Collection firstLevelBranchMapValues = map.values();
        Key1 key1 = new Key1();
        for (var val : firstLevelBranchMapValues) {
            if (val instanceof LinkedTreeMap){
                Map secondLevelBranchMap = ((LinkedTreeMap) val);
                for (var secondLevelBranchMapValues : secondLevelBranchMap.values()) {
                    if (secondLevelBranchMapValues instanceof LinkedTreeMap){
                        // map of some value2, some value3, some value4
                        Map thirdLevelBranchMap = ((LinkedTreeMap) secondLevelBranchMapValues);
                        Key3 key3 = new Key3();
                        for (var thirdLevelBranchMapValues : thirdLevelBranchMap.values()){
                            // returns some value2, some value3, some value4 in following iterations
                            key3.getKeys().add(thirdLevelBranchMapValues.toString());
                        }
                        key1.setKey3(key3);
                    } else {
                        // returns some value1
                        key1.setKey2(secondLevelBranchMapValues.toString());
                    }
                }
            }
        }
    }
愁以何悠 2025-01-27 02:31:21

您不需要带有3个可能实现的抽象类。只需创建1个类,其中key3属性是类型map&lt; string,string&gt;的类型。您总是可以将其归为班级,并且地图中的班级可能会容纳1、2或3个键值对。您的班级可能如下:

public class MyProps {
  private Key1 key1;
  //... seter and getter for key1 here
}

public class Key1 {
  private String key2;
  private Map<String, String> key3;
  // ... setters and getters here
}

You don't need an abstract class with 3 possible implementations. Just create 1 class where key3 property is of type Map<String, String>. You can always de-serialize it into your class and your class in your map may hold 1, 2 or 3 key-value pairs. Your class may look as follows:

public class MyProps {
  private Key1 key1;
  //... seter and getter for key1 here
}

public class Key1 {
  private String key2;
  private Map<String, String> key3;
  // ... setters and getters here
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文