Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate JSON sample from Java class

Tags:

java

json

jackson

How can you generate a JSON sample with dummy data from a Java class definition? (Note: I am not asking about generating JSON from a POJO. This is something that has been asked before on stackoverflow).

What I want is to generate some sample dummy data from a Java class directly. For example you have a class like this one:

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;

}

And then you have a function which generates without creating a POJO a JSON string with dummy values like:

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

Is there a library which can do this by default?

I have tried to solve this problem using Java code with these Maven dependencies:

<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 is mainly used for verifying and formatting the output JSON.

Below is the Java code I used:

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);
        }
    }
}
like image 846
gil.fernandes Avatar asked Aug 03 '18 13:08

gil.fernandes


People also ask

What is JSON pojo?

POJO stands for Plain Old Java Object. It is an ordinary Java object, not bound by any special restriction other than those forced by the Java Language Specification and not requiring any classpath. POJOs are used for increasing the readability and re-usability of a program. JSON To POJO. Input (Editable)


1 Answers

thanks @gil.fernandes, I have used your code with small modifications.

1) allow the same type multiple times but keep visited count to 100 to prevent infinite loops. I supposed your use case was different.

2) added java.util.Date and Enum.

3) print dummy values as the simple name of the class. In the case of enum print out "String of " and a list of its values.

    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()+"\"";
        }
    }
like image 88
zdary Avatar answered Oct 08 '22 14:10

zdary