问题
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);
}
}
}
回答1:
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()+"\"";
}
}
回答2:
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);
}
来源:https://stackoverflow.com/questions/51673259/generate-json-sample-from-java-class