Java Jersey/Jackson: return 动态 JSON 属性

Java Jersey/Jackson: return dynamic JSON properties

我们使用 jackson 将 java 对象 (DTO) 反序列化为 JSON 我们的端点。这很好用。但是,我有一个奇怪的问题。

假设我们有一个对象用户,并且我们有附加到该用户的元数据。元数据真的可以是客户能想到的任何东西,所以这是非常动态的。

客户端可以发出请求,以检索特定用户的特定元数据属性。假设客户想要拥有以下元数据属性:age 和 favouriteTree(因为有些人拥有一个,对吧?重点是,元数据可以是任何东西,而我们事先并不知道)。

我想return以下JSON:

{
    "userId" : 1,
    "age" : 22,
    "favouriteTree" : "Maple Tree"
}

我可以简单地拥有一个 Java POJO,其中包含一个 int userId、int age 和一个 String favouriteTree。这样,我们可以让 Jackson 将其反序列化为 JSON,一切都很好。

但是,下次客户端使用相同的端点时,它可能会请求不同的属性,例如:colorEyes 和 favouriteFood,在这种情况下我想 return:

{
    "userId" : 1,
    "colorEyes" : "blue",
    "favouriteFood" : "Pizza"
}

现在我需要另一个 Java POJO 来处理那些类型的元数据,并按照我们通常的方式对其进行反序列化。但是由于元数据可以是任何东西,我们不能那样做,因为我们不想继续向我们的代码中添加 POJO,因为不同的客户会有不同的需求。

在 Java 中是否有一种通用的方法可以做到这一点?

编辑:

我知道我可以做类似的事情:

{
    "userId": 1,
    "metadata": [{
            "key": "colorEyes",
            "value": "blue"
        },
        {
            "key": "favouriteFood",
            "value": "Pizza"
        }
    ]
}

但我想尽可能避免这种情况。

您可以让端点 return 成为 JsonNode,这样您就可以 return 任何类型的 json。如果您有一些基本 DTO,您可以将其映射到 JsonNode,然后在其中包含任何动态参数。

代码片段示例:

JsonNode jn = // map some BaseDTO to JsonNode
ObjectNode on = (ObjectNode)jn; // We need to cast to ObjectNode for mutation
on.put("attribute", whateverValue);

return on;

GraphQL 非常适合您的用例。

我知道你问的不是技术栈,但它正是你想要的。客户端将定义他们希望从服务中获得的数据,并且只会返回请求的数据。

而且您的服务将 maintain/extend 比您自己通过操纵 json 更简单、更容易。

检查此 link 以获得介绍:https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/

对于你说的情况,完全可以把你上面给的例子包起来,就像用map接受请求数据,然后把map转成json格式,就可以用

<dependency here. >
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-databind</artifactId>
       <version>2.9.9</version>
       <scope>compile</scope>
     </dependency>

这个jar里面的ObjectMapper工具class把地图转成json,像这样

public static String object2Json(Object o){
        try{
            return mapper.writeValueAsString(o);
        }catch (Exception e){
            log.warn("json serialize fail:", e);
            return null;
        }
    }