6

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);
        }
    }
}
gil.fernandes
  • 12,978
  • 5
  • 63
  • 76
  • if u used swagger, u get dummy response from swagger-ui – GolamMazid Sajib Aug 03 '18 at 13:04
  • @sajib Interesting. Good to know. But I am not using it right now ... – gil.fernandes Aug 03 '18 at 13:07
  • Why not use Mockito (http://site.mockito.org/) to do that for you? – Dan Aug 03 '18 at 14:08
  • @Dan Mockito allows mocking of Java classes. It does not help you to create JSON as far as I know. – gil.fernandes Aug 03 '18 at 14:11
  • @gil.fernandes - Mock your objects, convert to JSON using Jacksons's `ObjectMapper`, then you have your mocked JSON. – Dan Aug 03 '18 at 14:19
  • @Dan mocking is too much trouble. I just want to have some class and *directly* generate some dummy JSON which reflects this same class and contains dummy content for all fields. Just one step instead of two: mock -> serialize – gil.fernandes Aug 03 '18 at 15:05
  • @gil.fernandes - That is the easiest way to do it, otherwise you're going to spend all your time parsing files by hand. Let Jackson do the work for you and focus your attention on the mocking of POJO's with Mockito (yet another Framework that'll make your life easier). Why re-invent the wheel... – Dan Aug 03 '18 at 15:46

2 Answers2

2

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()+"\"";
        }
    }
zdary
  • 111
  • 7
-1

You can try this code: this will use gson lib to translate a object o json string

public static <T> String convertObjectToJSONString(Object obj) {
    Gson gson = new GsonBuilder().serializeNulls().create();
    if (obj == null) {         
        return null;
    }
    return gson.toJson(obj);
}
  • 2
    Hmm, the input should be a Java class, not an object. This looks like the regular serialization of objects. Input should be Java class output a string with dummy JSON with all possible fields with dummy values. – gil.fernandes Aug 03 '18 at 15:12