61

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"
      }
}
7
  • IS this what you are looking for? stackoverflow.com/questions/9593409/convert-pojo-to-json Commented Oct 5, 2014 at 5:01
  • 1
    No, that converts pojo to json object. I am looking for generating JSON schema as meta [information about the input form fields mapped to pojo fields like datatype, whether it is required or not, etc., ] to the end users). Commented Oct 5, 2014 at 14:23
  • Here is an online site that will produce json schema from json: jsonschema.net Commented Oct 6, 2014 at 19:07
  • possible duplicate of Tool to generate JSON schema from JSON data Commented Oct 6, 2014 at 19:09
  • Actually, I am not looking for any tools. I need an api that can have helper classes or annotations to describe the behavior of fields in a pojo. E.g. i recently found today that jackson 2.4.1 has new annotation @JsonPropertyDescription to add the description to the field in a pojo; [link]stackoverflow.com/questions/24515917/…. Is there a possible way to achieve the example in my post through reflection? Commented Oct 6, 2014 at 19:32

5 Answers 5

16

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.

Sign up to request clarification or add additional context in comments.

Comments

15

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.

4 Comments

The module you specify doesn't work if you have complex objects containing enum types that need to stay enums. See my answer below for a better tool (Still Jackson, but jackson-mapper.) The instructions at your link result in Enums being rendered as simple strings in the schema
Yes, I saw a bug report. I hope we get more contributors for the module -- it's external contribution, quite widely used, but no dedicated owner at this point.
Downvoted... not because it was a bad answer, just because it's a bad answer for today. This library is not being maintained anymore.
Unmaintained and does not support draft 4, 6, 7 github.com/FasterXML/jackson-module-jsonSchema/issues/141
2

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.

1 Comment

github.com/mbknor/mbknor-jackson-jsonSchema can generate Draft 4 schema based on Jackson annotations
2
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;
    }

Comments

0

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";
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.