title: Generate JSON sample from Java class
body: <p>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).</p>
  
  <p>What I want is to generate some sample dummy data from a Java class directly. For example you have a class like this one:</p>
  
  <pre><code>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;
  
  }
  </code></pre>
  
  <p>And then you have a function which generates without creating a POJO a JSON string with dummy values like:</p>
  
  <pre><code>{
      "leadTraveller": {
          "firstNames": "firstNames",
          "lastName": "lastName",
          "email": "email",
          "travellerGUID": "travellerGUID",
          "travellerRefs": [{
              "customerReportingRank": 37,
              "value": "value",
              "description": "description"
          }]
      },
      "sourceSystemID": 38,
      "recordLocation": "recordLocation",
      "recordLocatorYear": 9
  }
  </code></pre>
  
  <p>Is there a library which can do this by default?</p>
  
  <p>I have tried to solve this problem using Java code with these Maven dependencies:</p>
  
  <pre><code>&lt;dependency&gt;
      &lt;groupId&gt;fctg-ngrp&lt;/groupId&gt;
      &lt;artifactId&gt;model-core&lt;/artifactId&gt;
      &lt;version&gt;1.0.4-SNAPSHOT-MODEL-CORE&lt;/version&gt;
  &lt;/dependency&gt;
  &lt;dependency&gt;
      &lt;groupId&gt;io.vavr&lt;/groupId&gt;
      &lt;artifactId&gt;vavr&lt;/artifactId&gt;
      &lt;version&gt;0.9.2&lt;/version&gt;
      &lt;scope&gt;test&lt;/scope&gt;
  &lt;/dependency&gt;
  </code></pre>
  
  <p>Jackson is mainly used for verifying and formatting the output JSON. </p>
  
  <p>Below is the Java code I used:</p>
  
  <pre><code>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&lt;Class&lt;?&gt;, Integer&gt; visited = new HashMap&lt;&gt;();
  
      private static final ObjectMapper mapper = new ObjectMapper();
  
      public static void main(String[] args) throws IOException {
          Class&lt;Reservation&gt; clazz = Reservation.class;
          generateDummyJSON(clazz, args);
      }
  
      public static void generateDummyJSON(Class&lt;Reservation&gt; 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 -&gt; Paths.get(sPath))
                          .map(Path::toFile)
                          .map(API.unchecked(file -&gt; {
                              Files.write(prettyJson, file, StandardCharsets.UTF_8);
                              return file;
                          }));
              }
          }
      }
  
      private static String printObj(Class&lt;?&gt; clazz) {
          if (!visited.containsKey(clazz) || visited.get(clazz) &lt;= 1) {
              visited.merge(clazz, 1, (integer, integer2) -&gt; integer + integer2);
              Field[] declaredFields = clazz.getDeclaredFields();
              return "{" +
                      Array.of(declaredFields).map(field -&gt; String.format("  \"%s\" : %s%n", field.getName(), printFieldValue(field)))
                              .collect(Collectors.joining(String.format(",%n"))) +
                      "}";
          }
          return "";
      }
  
      private static Object printFieldValue(Field field) {
          Class&lt;?&gt; 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&lt;?&gt; clazz = (Class&lt;?&gt;) 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);
          }
      }
  }
  </code></pre>