序列化 Java Map<String, Object> 以创建动态 GraphQL 负载字符串

问题描述 投票:0回答:1

我正在使用 Java 构建一个 REST 应用程序,该应用程序需要动态构建 GraphQL 有效负载以发送到 GraphQL API。

我们将收到一个

String entityType = "MyEntity"
和一个
Map<String, Object> myMap
,可能如下所示:

{
    "blobUrl": "myurl.com",
    "accountId": 12345,
    "user": {
        "id": 4,
        "name": "username"
    }
}

它可能有许多其他具有不同类型值的键,因此我无法事先创建一个模板来指示需要绑定哪些变量。

我们提前了解 GraphQL 有效负载的所有信息是,它将采用以下格式:

mutation {
    Create%s(%s)
}

有了这些信息,我想生成以下 GraphQL 负载:

mutation {
    CreateMyEntity(
        blobUrl: "myurl.com"
        accountId: 12345
        user: {
            id: 4
            name: "username"
        }
    )
}

我可以通过手动循环

myMap
并使用
StringBuilder
构建有效负载来做到这一点,但我想知道是否有更好的或预先存在的方法可以做到这一点。

我已经查遍了,没有发现任何不涉及明确定义变量及其类型的模板的内容。

java serialization graphql
1个回答
0
投票

我相信您专注于自己构建查询字符串。

这是自定义序列化的示例:

入口点

这包含了 main 方法。

package org.example.graphql;

public class Runner {
    public static void main(String[] args) throws Exception {
        GraphQLSerializer entitySerializer = new GraphQLMutationSerializer("CreateMyEntity");
        String payload = entitySerializer.serialize(jsonInput);

        System.out.printf("Formatted properly? %b%n", payload.equals(expectedGraphQL));
    }

    private static final String jsonInput = """
            {
                "blobUrl": "myurl.com",
                "accountId": 12345,
                "user": {
                    "id": 4,
                    "name": "username"
                }
            }
            """;

    private static final String expectedGraphQL = """
            mutation {
                CreateMyEntity(
                    blobUrl: "myurl.com"
                    accountId: 12345
                    user: {
                        id: 4
                        name: "username"
                    }
                )
            }
            """.trim();
}

界面

这是一个用于序列化的接口。

package org.example.graphql;

import com.fasterxml.jackson.core.JsonProcessingException;

public interface GraphQLSerializer {
    String serialize(String jsonInput) throws JsonProcessingException;
}

实施

这里是我们解析 JSON 并格式化它的地方。

package org.example.graphql;

import java.util.Map;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class GraphQLMutationSerializer implements GraphQLSerializer {
    private final ObjectMapper objectMapper = new ObjectMapper();

    private final String mutationName;
    private final int indentSize;

    public GraphQLMutationSerializer(String mutationName, int indentSize) {
        this.mutationName = mutationName;
        this.indentSize = indentSize;
    }

    public GraphQLMutationSerializer(String mutationName) {
        this(mutationName, 4);
    }

    @Override
    @SuppressWarnings({ "unchecked" })
    public String serialize(String jsonInput) throws JsonProcessingException {
        // Parse the input JSON string into a Map using Jackson
        Map<String, Object> inputMap = objectMapper.readValue(jsonInput, Map.class);

        // Format the body and indentation
        String body = buildArguments(inputMap, indentSize, indentSize);
        String indentation = indent(indentSize);

        return String.format("mutation {\n%s%s(\n%s\n%s)\n}", indentation, mutationName, body, indentation);
    }

    private static String buildArguments(Map<String, Object> map, int indentSize, int currentIndent) {
        return map.entrySet().stream()
                .map(entry -> String.format(
                        "%s%s: %s",
                        indent(currentIndent + indentSize),
                        entry.getKey(),
                        formatValue(entry.getValue(), indentSize, currentIndent + indentSize)))
                .collect(Collectors.joining("\n"));
    }

    private static String formatValue(Object value, int indentSize, int currentIndent) {
        if (value instanceof String) {
            return "\"" + value + "\"";
        } else if (value instanceof Number || value instanceof Boolean) {
            return value.toString();
        } else if (value instanceof Map) {
            return String.format(
                    "{\n%s\n%s}",
                    buildArguments((Map<String, Object>) value, indentSize, currentIndent),
                    indent(currentIndent));
        } else {
            throw new IllegalArgumentException("Unsupported value type: " + value.getClass());
        }
    }

    private static String indent(int level) {
        return " ".repeat(level);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.