Reputation: 701
I have a POJO class:
public class Stock {
int id;
String name;
Date date;
}
Are there any annotations or development framework/API that can convert POJO to JSON schema like below:
{"id":
{
"type" : "int"
},
"name":{
"type" : "string"
}
"date":{
"type" : "Date"
}
}
And also I can expand the schema to add information like "Required" : "Yes"
, description for each field, etc., by specifying some annotations or configurations on POJO and can generate JSON Schema like below:
{"id":
{
"type" : "int",
"Required" : "Yes",
"format" : "id must not be greater than 99999",
"description" : "id of the stock"
},
"name":{
"type" : "string",
"Required" : "Yes",
"format" : "name must not be empty and must be 15-30 characters length",
"description" : "name of the stock"
}
"date":{
"type" : "Date",
"Required" : "Yes",
"format" : "must be in EST format",
"description" : "filing date of the stock"
}
}
Upvotes: 61
Views: 126733
Reputation: 909
If you are looking for a custom solution, here is one.
public static String generateSchema(Class currentClass) {
StringBuilder schema = new StringBuilder();
schema.append("{\n");
buildProperties(currentClass, schema);
schema.append("}");
return schema.toString();
}
private static void buildProperties(Class<?> clazz, StringBuilder schema) {
for (Field field : clazz.getDeclaredFields()) {
String fieldName = field.getName();
field.setAccessible(true);
if ("object".equals(getFieldType(field.getType()))) {
if (field.isAnnotationPresent(JsonIncludeProperties.class)) {
String[] includedProps = field.getAnnotation(JsonIncludeProperties.class).value();
schema.append(" \"" + fieldName + "\": {\n");
for (String prop : includedProps) {
Optional<Field> innerField = null;
if (!field.getType().isPrimitive()) {
innerField = Arrays.stream(field.getType().getDeclaredFields())
.filter(item -> item.getName().equals(prop))
.findFirst();
}
if (innerField.isPresent()) {
schema.append(" \"" + prop + "\":");
schema.append("\"" + getFieldType(innerField.get().getType()) + "\"\n"); // Add placeholder for definition
}
}
schema.append(" },\n");
} else {
schema.append(" \"" + fieldName + "\": {\n");
for (Field innerField : field.getType().getDeclaredFields()) {
if (isPrimitive(innerField)) {
schema.append(" \"" + innerField.getName() + "\":");
schema.append("\"" + getFieldType(innerField.getType()) + "\"\n");
}
}
schema.append(" },\n");
}
} else if ("set".equals(getFieldType(field.getType()))) {
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
if (actualTypeArguments.length == 1 && actualTypeArguments[0] instanceof Class) {
Class<?> elementType = (Class<?>) actualTypeArguments[0];
schema.append(" \"" + fieldName + "\": [\n");
for (Field innerField : elementType.getDeclaredFields()) {
if (isPrimitive(innerField)) {
schema.append(" \"" + innerField.getName() + "\":");
schema.append("\"" + getFieldType(innerField.getType()) + "\"\n");
}
}
schema.append(" ],\n");
}
}
} else {
schema.append(" \"" + fieldName + "\": \"" + getFieldType(field.getType()) + "\",\n");
}
}
}
private static String getFieldType(Class<?> type) {
if (type.isPrimitive()) {
if (type.equals(int.class) || type.equals(Integer.class)) {
return "integer";
} else if (type.equals(long.class) || type.equals(Long.class)) {
return "number"; // Can be "integer" depending on schema needs
} else if (type.equals(boolean.class) || type.equals(Boolean.class)) {
return "boolean";
} else if (type.equals(float.class) || type.equals(Float.class) ||
type.equals(double.class) || type.equals(Double.class)) {
return "number";
} else {
return "string";
}
} else if (type.equals(String.class)) {
return "string";
} else if (type.equals(Integer.class)) {
return "integer";
} else if (type.equals(Long.class)) {
return "long";
} else if (type.equals(UUID.class)) {
return "UUID";
} else if (type.isArray()) {
return "array";
} else if (Collection.class.isAssignableFrom(type)) {
return "set";
} else {
return "object";
}
}
Upvotes: 0
Reputation: 116512
EDIT: as pointed out by commenters, module is being deprecated, not maintained. So, Caveat Emptor etc
One such tool is Jackson JSON Schema module:
https://github.com/FasterXML/jackson-module-jsonSchema
which uses Jackson databind's POJO introspection to traverse POJO properties, taking into account Jackson annotations, and produces a JSON Schema object, which may then be serialized as JSON or used for other purposes.
Upvotes: 15
Reputation: 990
Java JSON Schema Generator: https://github.com/victools/jsonschema-generator
Creates JSON Schema (Draft 6, Draft 7 or Draft 2019-09) from Java classes using Jackson.
Upvotes: 16
Reputation: 401
public static String getJsonSchema(Class clazz) throws IOException {
Field[] fields = clazz.getDeclaredFields();
List<Map<String,String>> map=new ArrayList<Map<String,String>>();
for (Field field : fields) {
HashMap<String, String> objMap=new HashMap<String, String>();
objMap.put("name", field.getName());
objMap.put("type", field.getType().getSimpleName());
objMap.put("format", "");
map.add(objMap);
}
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(map);
return json;
}
Upvotes: 2
Reputation: 7234
Use JJschema. It can generate draft 4 compliant JSON schemas. Refer this post http://wilddiary.com/generate-json-schema-from-java-class/ for details.
Though Jackson Json Schema module can too generate schema but it can, as of today, only generate draft 3 compliant schemas only.
Upvotes: 2