Showing posts with label generate. Show all posts
Showing posts with label generate. Show all posts

Thursday, 8 April 2021

Generate json schema from json string

 

Generating json schema from a json string is not straight forward.

 

Approach 1: Get the POJOs from json document and use JsonSchemaGenerator to generate json schema from the POJO class.

 

How to generate POJOs from json document?

Refer this post.


 

How to generate JSON schema from POJO class?

Refer my previous post.

 

 

Approach 2:  Write a parser and generate json schema document.

 

JsonSchemaWriter.java

package com.sample.app.util;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;


public class JsonSchemaWriter {

	private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

	private static String getJsonSchema(JsonNode properties) throws JsonProcessingException {
		ObjectNode schema = OBJECT_MAPPER.createObjectNode();
		schema.put("type", "object");

		schema.set("properties", properties);

		ObjectMapper jacksonObjectMapper = new ObjectMapper();
		String schemaString = jacksonObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
		return schemaString;
	}

	private static ObjectNode createProperty(JsonNode jsonData) throws IOException {
		ObjectNode propObject = OBJECT_MAPPER.createObjectNode();

		Iterator<Entry<String, JsonNode>> fieldsIterator = jsonData.fields();

		while (fieldsIterator.hasNext()) {
			Entry<String, JsonNode> field = fieldsIterator.next();

			String fieldName = field.getKey();
			JsonNode fieldValue = field.getValue();
			JsonNodeType fieldType = fieldValue.getNodeType();

			ObjectNode property = processJsonField(fieldValue, fieldType, fieldName);
			if (!property.isEmpty()) {
				propObject.set(fieldName, property);
			}
		}
		return propObject;
	}

	private static ObjectNode processJsonField(JsonNode fieldValue, JsonNodeType fieldType, String fieldName)
			throws IOException {
		ObjectNode property = OBJECT_MAPPER.createObjectNode();

		switch (fieldType) {

		case ARRAY:
			property.put("type", "array");

			if (fieldValue.isEmpty()) {
				break;
			}

			// Get first element of the array
			JsonNodeType typeOfArrayElements = fieldValue.get(0).getNodeType();
			if (typeOfArrayElements.equals(JsonNodeType.OBJECT)) {
				property.set("items", createProperty(fieldValue.get(0)));
			} else {
				property.set("items", processJsonField(fieldValue.get(0), typeOfArrayElements, fieldName));
			}

			break;
		case BOOLEAN:
			property.put("type", "boolean");
			break;

		case NUMBER:
			property.put("type", "number");
			break;

		case OBJECT:
			property.put("type", "object");
			property.set("properties", createProperty(fieldValue));
			break;

		case STRING:
			property.put("type", "string");
			break;
		default:
			break;
		}
		return property;
	}

	public static String getJsonSchema(String jsonDocument) throws IllegalArgumentException, IOException {
		Map<String, Object> map = OBJECT_MAPPER.readValue(jsonDocument, new TypeReference<Map<String, Object>>() {});
		return getJsonSchema(map);
	}

	public static String getJsonSchema(Map<String, Object> jsonDocument) throws IllegalArgumentException, IOException {

		JsonNode properties = createProperty(OBJECT_MAPPER.convertValue(jsonDocument, JsonNode.class));
		return getJsonSchema(properties);

	}

}

App.java

package com.sample.app;

import java.io.IOException;

import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.sample.app.util.JsonSchemaWriter;

public class App {

  public static void main(String args[]) throws IllegalArgumentException, IOException, ProcessingException {

    String jsonPayload = "{\"id\":1,\"name\":\"Krishna\",\"age\":23,\"address\":{\"street\":\"Chowdeswari\",\"city\":\"Bangalore\",\"country\":\"India\"}}";

    String jsonSchema = JsonSchemaWriter.getJsonSchema(jsonPayload);
    
    System.out.println(jsonSchema);

  }

}


Output

{
  "type" : "object",
  "properties" : {
    "id" : {
      "type" : "number"
    },
    "name" : {
      "type" : "string"
    },
    "age" : {
      "type" : "number"
    },
    "address" : {
      "type" : "object",
      "properties" : {
        "street" : {
          "type" : "string"
        },
        "city" : {
          "type" : "string"
        },
        "country" : {
          "type" : "string"
        }
      }
    }
  }
}






 

 

Previous                                                    Next                                                    Home

Generate json schema from a java class

Using 'generateSchema' method of JsonSchemaGenerator class, we can generate a json schema.

 

Example

public static String getJsonSchema(Class<?> type) throws JsonProcessingException {
	ObjectMapper jacksonObjectMapper = new ObjectMapper();
	JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(jacksonObjectMapper);
	JsonSchema schema = schemaGen.generateSchema(type);
	String schemaString = jacksonObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
	return schemaString;
}

 

Find the below working application.

 

Define Address and Employee model classes.

 

Address.java

 

package com.sample.app.model;

public class Address {

	private String street;
	private String city;
	private String country;

	public String getStreet() {
		return street;
	}

	public void setStreet(String street) {
		this.street = street;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

}

 

Employee.java

package com.sample.app.model;

import java.util.List;

public class Employee {

	private int id;
	private String firstName;
	private String lastName;
	private Address address;
	private List<String> hobbies;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	public List<String> getHobbies() {
		return hobbies;
	}

	public void setHobbies(List<String> hobbies) {
		this.hobbies = hobbies;
	}

}

 

Define JsonSchemaUtil class.

 

JsonSchemaUtil.java

package com.sample.app.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;

public class JsonSchemaUtil {

	public static String getJsonSchema(Class<?> type) throws JsonProcessingException {
		ObjectMapper jacksonObjectMapper = new ObjectMapper();
		JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(jacksonObjectMapper);
		JsonSchema schema = schemaGen.generateSchema(type);
		String schemaString = jacksonObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
		return schemaString;
	}
}

 

Define SchemaFromClass.

 

SchemaFromClass.java

package com.sample.app;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.sample.app.model.Employee;
import com.sample.app.util.JsonSchemaUtil;

public class SchemaFromClass {

	public static void main(String args[]) throws JsonProcessingException {

		String jsonSchema = JsonSchemaUtil.getJsonSchema(Employee.class);

		System.out.println(jsonSchema);
	}

}

 

Output

{
  "type" : "object",
  "id" : "urn:jsonschema:com:sample:app:model:Employee",
  "properties" : {
    "id" : {
      "type" : "integer"
    },
    "firstName" : {
      "type" : "string"
    },
    "lastName" : {
      "type" : "string"
    },
    "address" : {
      "type" : "object",
      "id" : "urn:jsonschema:com:sample:app:model:Address",
      "properties" : {
        "street" : {
          "type" : "string"
        },
        "city" : {
          "type" : "string"
        },
        "country" : {
          "type" : "string"
        }
      }
    },
    "hobbies" : {
      "type" : "array",
      "items" : {
        "type" : "string"
      }
    }
  }
}

 

 

 

 

 

 

 

 

 

Previous                                                    Next                                                    Home

Tuesday, 30 March 2021

Generate POJOs from json document

Most of the time, in web application development, we need to define model classes in sync with json payload. What if there is a way to generate model POJO classes using json document…sounds nice right. In this post, I am going to explain how can you generate Java POJOs using json document.

 

Follow below step-by-step procedure to generate model classes.

 

Step 1: Define an instance of Jackson2Annotator. Jackson2Annotator class generates Java types using the Jackson 2.x mapping annotations.

GenerationConfig generationConfig = new DefaultGenerationConfig() {
	@Override
	public boolean isGenerateBuilders() {
		return true;
	}

	public SourceType getSourceType() {
		return SourceType.JSON;
	}
};

Jackson2Annotator jackson2Annotator = new Jackson2Annotator(generationConfig);

  Step 2: Define SchemaMapper instance. SchemaMapper generates Java types from a JSON schema. Can accept a factory which will be used to create type generation rules for this mapper.

 

SchemaStore schemaStore = new SchemaStore();
RuleFactory ruleFactory = new RuleFactory(generationConfig, jackson2Annotator, schemaStore);
SchemaMapper mapper = new SchemaMapper(ruleFactory, new SchemaGenerator());

Step 3: Reads schema and adds generated types to the given code model.

JCodeModel jCodeModel = new JCodeModel();

File inputJson = new File(INPUT_JSON_FILE);
URL inputJsonURL = inputJson.toURI().toURL();

mapper.generate(jCodeModel, "Employee", PACKAGE_NAME, inputJsonURL);


If the input file is located in classpath, you can get the file url using below statement.

URL inputJsonURL = PojoFromJsonDocument.class.getClassLoader().getResource(INPUT_JSON_FILE);

 

Step 4: Write the generated types to the output directory.

File outputPojoDirectory = new File(OUTPUT_DIR);
outputPojoDirectory.mkdirs();
jCodeModel.build(outputPojoDirectory);

 

Find the below working application.

 

employee.json

{
    "id": 1,
    "firstName": "Ram",
    "lastName": "Gurram",
    "address": {
        "street": "Chowdeswari",
        "city": "Bangalore",
        "country": "India"
    }
}

 

PojoFromJsonDocument.java

import java.io.File;
import java.io.IOException;
import java.net.URL;

import org.jsonschema2pojo.DefaultGenerationConfig;
import org.jsonschema2pojo.GenerationConfig;
import org.jsonschema2pojo.Jackson2Annotator;
import org.jsonschema2pojo.SchemaGenerator;
import org.jsonschema2pojo.SchemaMapper;
import org.jsonschema2pojo.SchemaStore;
import org.jsonschema2pojo.SourceType;
import org.jsonschema2pojo.rules.RuleFactory;

import com.sun.codemodel.JCodeModel;

public class PojoFromJsonDocument {
    private static final String INPUT_JSON_FILE = "employee.json";
    private static final String PACKAGE_NAME = "com.sample.app.model";
    private static final String OUTPUT_DIR = "/Users/Shared/json/modelClasses";

    public static void main(String[] args) throws IOException {

        GenerationConfig generationConfig = new DefaultGenerationConfig() {
            @Override
            public boolean isGenerateBuilders() {
                return true;
            }

            public SourceType getSourceType() {
                return SourceType.JSON;
            }
        };

        Jackson2Annotator jackson2Annotator = new Jackson2Annotator(generationConfig);

        SchemaStore schemaStore = new SchemaStore();
        RuleFactory ruleFactory = new RuleFactory(generationConfig, jackson2Annotator, schemaStore);
        SchemaMapper mapper = new SchemaMapper(ruleFactory, new SchemaGenerator());

        JCodeModel jCodeModel = new JCodeModel();

        URL inputJsonURL = PojoFromJsonDocument.class.getClassLoader().getResource(INPUT_JSON_FILE);

        mapper.generate(jCodeModel, "Employee", PACKAGE_NAME, inputJsonURL);

        File outputPojoDirectory = new File(OUTPUT_DIR);
        outputPojoDirectory.mkdirs();
        jCodeModel.build(outputPojoDirectory);
    }

}

 

Run the application, you will see following messages in console.

 

com/sample/app/model/Address.java

com/sample/app/model/Employee.java

 

You can observe Employee and Address classes are generated.

 

$tree /Users/Shared/json/modelClasses/
/Users/Shared/json/modelClasses/
└── com
    └── sample
        └── app
            └── model
                ├── Address.java
                └── Employee.java

4 directories, 2 files

 

Generated source code

Address.java

package com.sample.app.model;

import java.util.HashMap;
import java.util.Map;
import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
    "street",
    "city",
    "country"
})
@Generated("jsonschema2pojo")
public class Address {

    @JsonProperty("street")
    private String street;
    @JsonProperty("city")
    private String city;
    @JsonProperty("country")
    private String country;
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();

    @JsonProperty("street")
    public String getStreet() {
        return street;
    }

    @JsonProperty("street")
    public void setStreet(String street) {
        this.street = street;
    }

    public Address withStreet(String street) {
        this.street = street;
        return this;
    }

    @JsonProperty("city")
    public String getCity() {
        return city;
    }

    @JsonProperty("city")
    public void setCity(String city) {
        this.city = city;
    }

    public Address withCity(String city) {
        this.city = city;
        return this;
    }

    @JsonProperty("country")
    public String getCountry() {
        return country;
    }

    @JsonProperty("country")
    public void setCountry(String country) {
        this.country = country;
    }

    public Address withCountry(String country) {
        this.country = country;
        return this;
    }

    @JsonAnyGetter
    public Map<String, Object> getAdditionalProperties() {
        return this.additionalProperties;
    }

    @JsonAnySetter
    public void setAdditionalProperty(String name, Object value) {
        this.additionalProperties.put(name, value);
    }

    public Address withAdditionalProperty(String name, Object value) {
        this.additionalProperties.put(name, value);
        return this;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(Address.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('[');
        sb.append("street");
        sb.append('=');
        sb.append(((this.street == null)?"<null>":this.street));
        sb.append(',');
        sb.append("city");
        sb.append('=');
        sb.append(((this.city == null)?"<null>":this.city));
        sb.append(',');
        sb.append("country");
        sb.append('=');
        sb.append(((this.country == null)?"<null>":this.country));
        sb.append(',');
        sb.append("additionalProperties");
        sb.append('=');
        sb.append(((this.additionalProperties == null)?"<null>":this.additionalProperties));
        sb.append(',');
        if (sb.charAt((sb.length()- 1)) == ',') {
            sb.setCharAt((sb.length()- 1), ']');
        } else {
            sb.append(']');
        }
        return sb.toString();
    }

    @Override
    public int hashCode() {
        int result = 1;
        result = ((result* 31)+((this.country == null)? 0 :this.country.hashCode()));
        result = ((result* 31)+((this.additionalProperties == null)? 0 :this.additionalProperties.hashCode()));
        result = ((result* 31)+((this.city == null)? 0 :this.city.hashCode()));
        result = ((result* 31)+((this.street == null)? 0 :this.street.hashCode()));
        return result;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        }
        if ((other instanceof Address) == false) {
            return false;
        }
        Address rhs = ((Address) other);
        return (((((this.country == rhs.country)||((this.country!= null)&&this.country.equals(rhs.country)))&&((this.additionalProperties == rhs.additionalProperties)||((this.additionalProperties!= null)&&this.additionalProperties.equals(rhs.additionalProperties))))&&((this.city == rhs.city)||((this.city!= null)&&this.city.equals(rhs.city))))&&((this.street == rhs.street)||((this.street!= null)&&this.street.equals(rhs.street))));
    }

}

 

Employee.java

package com.sample.app.model;

import java.util.HashMap;
import java.util.Map;
import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
    "id",
    "firstName",
    "lastName",
    "address"
})
@Generated("jsonschema2pojo")
public class Employee {

    @JsonProperty("id")
    private Integer id;
    @JsonProperty("firstName")
    private String firstName;
    @JsonProperty("lastName")
    private String lastName;
    @JsonProperty("address")
    private Address address;
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();

    @JsonProperty("id")
    public Integer getId() {
        return id;
    }

    @JsonProperty("id")
    public void setId(Integer id) {
        this.id = id;
    }

    public Employee withId(Integer id) {
        this.id = id;
        return this;
    }

    @JsonProperty("firstName")
    public String getFirstName() {
        return firstName;
    }

    @JsonProperty("firstName")
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public Employee withFirstName(String firstName) {
        this.firstName = firstName;
        return this;
    }

    @JsonProperty("lastName")
    public String getLastName() {
        return lastName;
    }

    @JsonProperty("lastName")
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Employee withLastName(String lastName) {
        this.lastName = lastName;
        return this;
    }

    @JsonProperty("address")
    public Address getAddress() {
        return address;
    }

    @JsonProperty("address")
    public void setAddress(Address address) {
        this.address = address;
    }

    public Employee withAddress(Address address) {
        this.address = address;
        return this;
    }

    @JsonAnyGetter
    public Map<String, Object> getAdditionalProperties() {
        return this.additionalProperties;
    }

    @JsonAnySetter
    public void setAdditionalProperty(String name, Object value) {
        this.additionalProperties.put(name, value);
    }

    public Employee withAdditionalProperty(String name, Object value) {
        this.additionalProperties.put(name, value);
        return this;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(Employee.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('[');
        sb.append("id");
        sb.append('=');
        sb.append(((this.id == null)?"<null>":this.id));
        sb.append(',');
        sb.append("firstName");
        sb.append('=');
        sb.append(((this.firstName == null)?"<null>":this.firstName));
        sb.append(',');
        sb.append("lastName");
        sb.append('=');
        sb.append(((this.lastName == null)?"<null>":this.lastName));
        sb.append(',');
        sb.append("address");
        sb.append('=');
        sb.append(((this.address == null)?"<null>":this.address));
        sb.append(',');
        sb.append("additionalProperties");
        sb.append('=');
        sb.append(((this.additionalProperties == null)?"<null>":this.additionalProperties));
        sb.append(',');
        if (sb.charAt((sb.length()- 1)) == ',') {
            sb.setCharAt((sb.length()- 1), ']');
        } else {
            sb.append(']');
        }
        return sb.toString();
    }

    @Override
    public int hashCode() {
        int result = 1;
        result = ((result* 31)+((this.firstName == null)? 0 :this.firstName.hashCode()));
        result = ((result* 31)+((this.lastName == null)? 0 :this.lastName.hashCode()));
        result = ((result* 31)+((this.id == null)? 0 :this.id.hashCode()));
        result = ((result* 31)+((this.address == null)? 0 :this.address.hashCode()));
        result = ((result* 31)+((this.additionalProperties == null)? 0 :this.additionalProperties.hashCode()));
        return result;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        }
        if ((other instanceof Employee) == false) {
            return false;
        }
        Employee rhs = ((Employee) other);
        return ((((((this.firstName == rhs.firstName)||((this.firstName!= null)&&this.firstName.equals(rhs.firstName)))&&((this.lastName == rhs.lastName)||((this.lastName!= null)&&this.lastName.equals(rhs.lastName))))&&((this.id == rhs.id)||((this.id!= null)&&this.id.equals(rhs.id))))&&((this.address == rhs.address)||((this.address!= null)&&this.address.equals(rhs.address))))&&((this.additionalProperties == rhs.additionalProperties)||((this.additionalProperties!= null)&&this.additionalProperties.equals(rhs.additionalProperties))));
    }

}

 

 

 

 

 

 

 



 

 

Previous                                                    Next                                                    Home