java - 从 Java 类生成 JSON 示例

标签 java json jackson

如何使用 Java 类定义中的虚拟数据生成 JSON 样本? (注意:我不是在问从 POJO 生成 JSON。这是之前在 stackoverflow 上问过的问题)。

我想要的是直接从 Java 类生成一些示例虚拟数据。例如你有这样一个类:

public class Reservation  {

  @ApiModelProperty(value = "")
  private Traveller leadTraveller = null;

  @ApiModelProperty(example = "2", value = "")
  private Integer sourceSystemID = null;

  @ApiModelProperty(value = "")
  private String recordLocation = null;

  @ApiModelProperty(example = "2010", value = "")
  private Integer recordLocatorYear = null;

}

然后你有一个函数,它在不创建 POJO 的情况下生成一个具有虚拟值的 JSON 字符串,例如:

{
    "leadTraveller": {
        "firstNames": "firstNames",
        "lastName": "lastName",
        "email": "email",
        "travellerGUID": "travellerGUID",
        "travellerRefs": [{
            "customerReportingRank": 37,
            "value": "value",
            "description": "description"
        }]
    },
    "sourceSystemID": 38,
    "recordLocation": "recordLocation",
    "recordLocatorYear": 9
}

是否有默认情况下可以执行此操作的库?

我尝试使用具有这些 Maven 依赖项的 Java 代码来解决这个问题:

<dependency>
    <groupId>fctg-ngrp</groupId>
    <artifactId>model-core</artifactId>
    <version>1.0.4-SNAPSHOT-MODEL-CORE</version>
</dependency>
<dependency>
    <groupId>io.vavr</groupId>
    <artifactId>vavr</artifactId>
    <version>0.9.2</version>
    <scope>test</scope>
</dependency>

Jackson主要用于校验和格式化输出的JSON。

下面是我使用的 Java 代码:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.Files;
import io.vavr.API;
import io.vavr.collection.Array;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Sample utility for generating dummy JSON sample code from a JAva class directly.
 */
public class GenerateJSONFromClasses {

    private static final Random R = new Random();

    /**
     * Used to avoid infinite loops.
     */
    private static final Map<Class<?>, Integer> visited = new HashMap<>();

    private static final ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) throws IOException {
        Class<Reservation> clazz = Reservation.class;
        generateDummyJSON(clazz, args);
    }

    public static void generateDummyJSON(Class<Reservation> clazz, String... paths) throws IOException {
        StringWriter out = new StringWriter();
        try (PrintWriter writer = new PrintWriter(out)) {
            writer.println(printObj(clazz));
            JsonNode jsonNode = mapper.readTree(out.toString());
            String prettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode);
            if (paths == null || paths.length == 0) {
                System.out.println(prettyJson);
            } else {
                Array.of(paths).map(sPath -> Paths.get(sPath))
                        .map(Path::toFile)
                        .map(API.unchecked(file -> {
                            Files.write(prettyJson, file, StandardCharsets.UTF_8);
                            return file;
                        }));
            }
        }
    }

    private static String printObj(Class<?> clazz) {
        if (!visited.containsKey(clazz) || visited.get(clazz) <= 1) {
            visited.merge(clazz, 1, (integer, integer2) -> integer + integer2);
            Field[] declaredFields = clazz.getDeclaredFields();
            return "{" +
                    Array.of(declaredFields).map(field -> String.format("  \"%s\" : %s%n", field.getName(), printFieldValue(field)))
                            .collect(Collectors.joining(String.format(",%n"))) +
                    "}";
        }
        return "";
    }

    private static Object printFieldValue(Field field) {
        Class<?> fieldType = field.getType();
        if (String.class.equals(fieldType)) {
            return String.format("\"%s\"", field.getName());
        } else if (Integer.class.equals(fieldType)) {
            return R.nextInt(99) + 1;
        } else if (LocalDate.class.equals(fieldType)) {
            return String.format("\"%s\"", LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        } else if (LocalDateTime.class.equals(fieldType)) {
            return String.format("\"%s\"", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")));
        } else if (OffsetDateTime.class.equals(fieldType)) {
            return String.format("\"%s\"", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")));
        } else if (Date.class.equals(fieldType)) {
            return System.currentTimeMillis();
        } else if (List.class.equals(fieldType)) {
            ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
            Class<?> clazz = (Class<?>) parameterizedType.getActualTypeArguments()[0];
            return String.format("[%s]", printObj(clazz));
        } else if (fieldType.isAssignableFrom(Number.class)) {
            return R.nextDouble() * 10.0;
        } else if (BigDecimal.class.equals(fieldType)) {
            return new BigDecimal(R.nextDouble() * 10.0);
        } else if (Boolean.class.equals(fieldType)) {
            return R.nextBoolean();
        } else {
            return printObj(fieldType);
        }
    }
}

最佳答案

感谢@gil.fernandes, 我使用了您的代码并稍作修改。

1) 允许多次使用同一类型,但将访问次数保持在 100 以防止无限循环。我以为您的用例有所不同。

2) 添加了 java.util.Date 和 Enum。

3) 打印虚拟值作为类的简单名称。在枚举的情况下,打印出“String of”及其值的列表。

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.io.Files;
    import com.jnj.na.webmethods.core.dto.MaterialWsDTO;
    import io.vavr.API;
    import io.vavr.collection.Array;

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.io.StringWriter;
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    import java.lang.reflect.ParameterizedType;
    import java.math.BigDecimal;
    import java.nio.charset.StandardCharsets;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.OffsetDateTime;
    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * Sample utility for generating dummy JSON sample code from a JAva class directly.
     */
    public class GenerateJSONFromClasses {

        /**
         * Used to avoid infinite loops.
         */
        private static final Map<Class<?>, Integer> visited = new HashMap<>();

        private static final ObjectMapper mapper = new ObjectMapper();

        public static void main(String[] args) throws IOException {
            Class<MaterialWsDTO> clazz = MaterialWsDTO.class;
            generateDummyJSON(clazz, args);
        }

        public static void generateDummyJSON(Class<MaterialWsDTO> clazz, String... paths) throws IOException {
            StringWriter out = new StringWriter();
            try (PrintWriter writer = new PrintWriter(out)) {
                writer.println(printObj(clazz));
                JsonNode jsonNode = mapper.readTree(out.toString());
                String prettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode);
                if (paths == null || paths.length == 0) {
                    System.out.println(prettyJson);
                } else {
                    Array.of(paths).map(sPath -> Paths.get(sPath))
                            .map(Path::toFile)
                            .map(API.unchecked(file -> {
                                Files.write(prettyJson, file, StandardCharsets.UTF_8);
                                return file;
                            }));
                }
            }
        }

        private static String printObj(Class<?> clazz) {
            if (!visited.containsKey(clazz) || visited.get(clazz) <= 100) {
                visited.merge(clazz, 1, (integer, integer2) -> integer + integer2);
                Field[] declaredFields = clazz.getDeclaredFields();
                return "{" +
                        Array.of(declaredFields)
                                .filterNot(e->Modifier.isStatic(e.getModifiers()))
                                .map(field -> String.format("  \"%s\" : %s%n", field.getName(), printFieldValue(field)))
                                .collect(Collectors.joining(String.format(",%n"))) +
                        "}";
            }
            return "";
        }

        private static Object printFieldValue(Field field) {
            Class<?> fieldType = field.getType();
            if (String.class.equals(fieldType)) {
                return name(fieldType);
            } else if (Integer.class.equals(fieldType)) {
                return name(fieldType);
            } else if (Enum.class.isAssignableFrom(fieldType)) {
                return printEnum(fieldType);
            } else if (Double.class.equals(fieldType)) {
                return name(fieldType);
            } else if (LocalDate.class.equals(fieldType)) {
                return name(fieldType);
            } else if (LocalDateTime.class.equals(fieldType)) {
                return name(fieldType);
            } else if (OffsetDateTime.class.equals(fieldType)) {
                return name(fieldType);
            } else if (Date.class.equals(fieldType)) {
                return name(fieldType);
            } else if (List.class.equals(fieldType)) {
                ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
                Class<?> clazz = (Class<?>) parameterizedType.getActualTypeArguments()[0];
                return String.format("[%s]", printObj(clazz));
            } else if (fieldType.isAssignableFrom(Number.class)) {
                return name(fieldType);
            } else if (BigDecimal.class.equals(fieldType)) {
                return name(fieldType);
            } else if (Boolean.class.equals(fieldType)) {
                return name(fieldType);
            } else {
                return printObj(fieldType);
            }
        }

        private static String printEnum(Class<?> fieldType) {
            Field[] declaredFields = fieldType.getDeclaredFields();
            return "\"String of " + Arrays.stream(declaredFields)
                    .filter(field -> field.getType()==fieldType)
                    .map(Field::getName)
                    .collect(Collectors.joining(",")) +
                   "\"";
        }

        private static Object name(Class<?> fieldType) {
            return "\""+fieldType.getSimpleName()+"\"";
        }
    }

关于java - 从 Java 类生成 JSON 示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51673259/

相关文章:

ajax - .ajax JSONP 解析器错误

php - 查找值是否存在于 PHP 中的 JSONArray 中

java - 在数据库中读取/写入 POJO 作为 JSON 字符串

Java 将数据加载到 Parquet 中

java: ArrayList() 方法返回结果:如果传递参数或不传递参数

java - 有商业/开源 Swing 替代方案吗?

javascript - 如何将 CSS/Styling 应用于导入的联合 js bpmn 对象?

java - Jackson注释无法解析 boolean 字段

java - Spring JSON 转换器。如何绑定(bind)不同类型

java - Hbase MasterNotRunningException 尽管 Hmaster、regionserver 和 Zookeeper 已启动