'How to obtain json schema from jsonpaths of all the required fields using java

Say the input is:

[{keyname: firstname, path:person.name.firstname,type:string},
{keyname:age, path:person.age,type:number}]

Then jsonschema should be generated from the json

{ person:{
 name:{ firstname: guest },
 age: 6
}}

I need the json schema



Solution 1:[1]

@Component public class SchemaUtil {

@Autowired
ObjectMapper mapper;

//Converts path of type -> $.eventMessage.phoneNumbers[:1].type to -> /eventMessage/phoneNumbers/0/type
public String pathConverter(String path) {
    String newString=path.replace("$", "").replace(".", "/").replaceAll("\\[(.*?)\\]","/0");
    return newString;
}

public String getSchema(List<SchemaPOJO> schemaList)
{
    ObjectNode rootNode = mapper.createObjectNode();
    StringBuilder output = new StringBuilder();
    try 
    {
        for(SchemaPOJO schema: schemaList)
        {
            String path = pathConverter(schema.getPath());
            create(rootNode,path,schema.getDataType());
            if(path.contains("/0/"))
            {
                int index1=path.indexOf("/0/"); 
                while(index1 != -1)
                {
                    String temp = path.substring(0,index1+1)+'1'+path.substring(index1+2);
                    create(rootNode,temp,schema.getDataType());
                    index1=path.indexOf("/0/",index1+1); 
                }
            }
        }
                    
        output.append("{\"$schema\":\"http://json-schema.org/draft-04/schema#\","
                 + "\"type\": \"object\", \"properties\": {");
        
        output.append(makeSchema(mapper.writeValueAsString(rootNode),null));
    }
    
    catch(Exception e)
    {
        return null;
        
    }
    
    List<String> keys = new ArrayList<>();
    Iterator<String> iterator = rootNode.fieldNames();
    iterator.forEachRemaining(e -> keys.add(e));
    String inParams = String.join(",", keys.stream().map(key1 -> "\""+key1+"\"").collect(Collectors.toList()));
    output.append(",\"required\":["+inParams+"]");
    output.append("}");
    
    return output.toString();
}

//Creates dummy values in json
private void create(ObjectNode rootNode, String path,String dataType)
{
    switch(dataType)
    {
        case "string":createJson(rootNode, JsonPointer.compile(path), new TextNode("stringdummytext"));break;
        case "integer":createJson(rootNode, JsonPointer.compile(path), new IntNode(65734));break;
        case "float":createJson(rootNode, JsonPointer.compile(path), new FloatNode(124));break;
        case "boolean":createJson(rootNode, JsonPointer.compile(path),BooleanNode.getFalse());break;
        default:createJson(rootNode, JsonPointer.compile(path), new TextNode("stringdummytext"));break;
    }
}

//Creates dummy json
private void createJson(ObjectNode node, JsonPointer pointer, JsonNode value) {
    
    JsonPointer parentPointer = pointer.head();
    JsonNode parentNode = node.at(parentPointer);
    String fieldName = pointer.last().toString().substring(1);

    if (parentNode.isMissingNode() || parentNode.isNull()) {
        parentNode = StringUtils.isNumeric(fieldName) ? mapper.createArrayNode() : mapper.createObjectNode();
        createJson(node,parentPointer, parentNode);
    }

    if (parentNode.isArray()) {
        ArrayNode arrayNode = (ArrayNode) parentNode;
        int index = Integer.parseInt(fieldName);
        for (int i = arrayNode.size(); i <= index; i++) {
            arrayNode.addNull();
        }
        arrayNode.set(index, value);
    } else if (parentNode.isObject()) {
        ((ObjectNode) parentNode).set(fieldName, value);
    } else {
          throw new IllegalArgumentException("`" + fieldName + "` can't be set for parent node `"
                + parentPointer + "` because parent is not a container but " + parentNode.getNodeType().name());
    }
    
}

//Makes schema from dummy json
private String makeSchema(String json,JsonNodeType jsonNodeType) throws IOException
{
    JsonNode jsonNode = mapper.readTree(json);
    StringBuilder output = new StringBuilder();
    
    for (Iterator<String> iterator = jsonNode.fieldNames(); iterator.hasNext();)
    {
        String fieldName = iterator.next();
        JsonNodeType nodeType;
        nodeType = jsonNode.get(fieldName).getNodeType();
        output.append(convertNodeToStringSchemaNode(jsonNode, nodeType, fieldName));
        output.append(",");
    }

    if( (jsonNodeType==null) || (jsonNodeType.name().equals("ARRAY")) || (jsonNodeType.name().equals("OBJECT")))
        output.deleteCharAt(output.length()-1);
    else if(jsonNode.getNodeType().name().equals("STRING"))
        output.append("string\"");
    else if(jsonNode.getNodeType().name().equals("NUMBER"))
        output.append("integer\"");
    output.append("}");

    
    return output.toString();
    
}

//Util Method to create json schema
private String convertNodeToStringSchemaNode(JsonNode jsonNode, JsonNodeType nodeType, String key) throws IOException
{
    StringBuilder result = new StringBuilder("\"" + key + "\": { \"type\": \"");
    
    JsonNode node = null;
    switch (nodeType) {
        case ARRAY :
            node = jsonNode.get(key).get(0);
            result.append("array\", \"items\": [{ \"type\":\"");
            if(node.getNodeType().name().equals("OBJECT"))
                result.append("object\", \"properties\": { ");
            result.append(makeSchema(node.toString(), node.getNodeType()));
            if(node.getNodeType().name().equals("OBJECT"))
            {
                List<String> keys = new ArrayList<>();
                Iterator<String> iterator = node.fieldNames();
                iterator.forEachRemaining(e -> keys.add(e));
                String inParams = String.join(",", keys.stream().map(key1 -> "\""+key1+"\"").collect(Collectors.toList()));
                  result.append(",\"required\":["+inParams+"]");
                 result.append("}");
            }
            result.append("]}");
            break;
        case BOOLEAN:
            result.append("boolean\" }");
            break;
        case NUMBER:
            result.append("integer\" }");
            break;
        case OBJECT:
            node = jsonNode.get(key);
            result.append("object\", \"properties\": {");
            result.append(makeSchema(node.toString(), JsonNodeType.OBJECT));
            List<String> keys = new ArrayList<>();
            Iterator<String> iterator = node.fieldNames();
            iterator.forEachRemaining(e -> keys.add(e));
            String inParams = String.join(",", keys.stream().map(key1 -> "\""+key1+"\"").collect(Collectors.toList()));
              result.append(",\"required\":["+inParams+"]");

            result.append("}");
            break;
        case STRING:
            result.append("string\" }");
            break;
        default:
            result.append("string\" }");
    }

    return result.toString();
}

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tanya Bhandari