I have a JSON Schema fetched from a DB, Which is now stored in a string in Java. I want to print only a section of schema but not all. How can I split the JSON/String and print.
I have tried converting the String back to JSON format. But not sure how to separate the required content. Also split method didn't worked for me as well.
Input:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"employee_id": {
"type": "string"
},
"course_id": {
"type": "string"
},
"college_id": {
"type": "string"
}
},
"required": [
"employee_id",
"course_id",
"college_id"
]
}
Expected Result:
employee_id, course_id, college_id
As your question doesn't provide any details on which library you are using to parse the JSON document, I have put together some approaches using popular JSON parsing libraries for Java.
JsonPath
It is pretty straightforward to be achieved with JsonPath:
List<String> required = JsonPath.parse(json).read("$.required");
Jackson
It also could be achieved with Jackson:
ObjectMapper mapper = new ObjectMapper();
List<String> required = mapper.convertValue(mapper.readTree(json).get("required"),
new TypeReference<List<String>>() {});
Gson
In case you prefer Gson:
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(json, JsonObject.class);
List<String> required = gson.fromJson(jsonObject.getAsJsonArray("required"),
new TypeToken<List<String>>() {}.getType());
JsonPath with Jackson or Gson
Depending on your needs, you could combine JsonPath with Jackson or Gson:
Configuration conf = Configuration.builder()
.jsonProvider(new JacksonJsonProvider())
.mappingProvider(new JacksonMappingProvider())
.build();
Configuration conf = Configuration.builder()
.jsonProvider(new GsonJsonProvider())
.mappingProvider(new GsonMappingProvider())
.build();
List<String> required = JsonPath
.using(conf)
.parse(json)
.read("$.required", new TypeRef<List<String>>() {});
String str=
"{
"key":{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"employee_id": {
"type": "string"
},
"course_id": {
"type": "string"
},
"college_id": {
"type": "string"
}
},
"required": [
"employee_id",
"course_id",
"college_id"
]
}
}
";
JSONObject jsonObj=new JSONObject(str);
JSONObject keyJon= jsonObj.getJSONObject("key");
String strUrl=keyJon.getString("$schema");
System.err.println("str "+strUrl);
I've made a helper library that uses gson and has ability to search json for subtrees/elements:
https://github.com/Enerccio/gson-utilities
In your case you would do
List<JsonElement> contents = JsonHelper.getAll(data, "key.required", x -> x instanceof JsonPrimitive);
System.out.print(contents.stream().map(JsonElement::getAsString).collect(Collectors.joining(", ")));
But you have invalid JSON, the valid version would be:
{
"key":{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"employee_id": {
"type": "string"
},
"course_id": {
"type": "string"
},
"college_id": {
"type": "string"
}
},
"required": [
"employee_id",
"course_id",
"college_id"
]
}
}
The below-mentioned method solved my problem.
JSONObject jsonObject = new JSONObject(key);
JSONArray req = jsonObject.getJSONArray("required");
System.out.println("Required Parameters : "+req);
Related
What I want to do is have Gson Type Adapters that don't have to have the property labels for a given JSON object hard coded into the adapter, but instead pull the Strings from the JSON Schema.
So if I have a schema like this (borrowing from json-schema.org):
{
"$id": "/schemas/address",
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
}
}
Is there a way to extract the property names "street_address", "city", and "state" from the schema and assign them to variables in a Gson TypeAdapter or Factory such that I don't have to declare a String like
String streetName = "street_address";
But could instead do something in the vein of
String streetName = getSchemaProperty("/schemas/address").getProperty(0);
Where getSchemaProperty() would get the object schema from the "/schemas/address" file and getProperty would return the first property label in the schema. That way, if the schema was updated with new property labels, I would not have to update the Adapters with new Strings.
I can certainly write something that would do this (parse the schema file(s) and extract that information), I'm just wondering if that kind of work has already been done (maybe with annotations or some such?) & I'm just missing it?
Easier than I thought, actually, since a Schema is a JSON file.
Here is an example Schema:
{
"$id": "/path/to/schema/MySchema",
"$schema": "http://json-schema.org/draft/2019-09/schema#",
"title": "My Example JSON Schema",
"description": "JSON Schema for me",
"$comment": "Hey! A Comment!",
"$defs" :
{
"My Class":
{
"$comment": "Another Comment! I love comments, so useful!",
"type": "object",
"required": [ "Value", "Description" ],
"properties":
{
"Value": { "type": "number" },
"Description": { "type": "string" }
}
}
}
}
Here is the default constructor of my Google GSON Type Adapter:
public MyTypeAdapter()
{
InputStream is = getClass().getResourceAsStream("/path/to/schema/MySchema.json");
InputStreamReader isr= new InputStreamReader(is, "UTF-8");
JsonObject schemaJO= JsonParser.parseReader(isr).getAsJsonObject;
JsonObject thisJO = schemaJO.getAsJsonObject("$defs").getAsJsonObject("My Class").getAsJsonObject("properties");
//Get the list of property labels\names\keys
Set<String> keySet = thisJO .keySet();
//loop over the set and distribute the Strings as desired.
}
Easy Peasy Lemon Squeezy!
I need to serialize simple java object with three fields (one is a List of objects) into json to look something like this:
{
"id": "1",
"fields": [
{
"value": {
"someNumber": "0.0.2"
},
"id": "67"
}
],
"name": "Daniel"}
I've read guides on custom serializers StdSerializer and JsonGenerator, as i undestood, to write "name": "Daniel" into json you need to do somwthing like gen.writeObjectField("name", name); but i cannot get my head on two things:
How to write some string value like here:
"value": {
"name": "0.0.2"
},
And how to write java List as an array like this:
"fields": [
{
"value": {
"someNumber": "0.0.2"
},
"id": "67"
}]
where "fields" is an List full of objects having two fields: "value" and "id".
Any help is appreciated
like this
public class Test {
public static void main(String[] args) throws IOException {
String ret;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper mapper = new ObjectMapper();
JsonGenerator jg = mapper.getJsonFactory().createJsonGenerator(new PrintWriter(bos));
jg.writeStartObject();
jg.writeStringField("id", "1");
jg.writeArrayFieldStart("fields");
jg.writeStartObject();
jg.writeObjectFieldStart("value");
jg.writeStringField("someNumber","0.0.2");
jg.writeEndObject();
jg.writeStringField("id","67");
jg.writeEndObject();
//you can write more objects in fields here
jg.writeEndArray();
jg.writeStringField("name","Daniel");
jg.writeEndObject();
jg.flush();
jg.close();
ret = bos.toString();
bos.close();
System.out.println(ret);
}
}
and the result is
{
"id":"1",
"fields":[
{
"value":{
"someNumber":"0.0.2"
},
"id":"67"
}
],
"name":"Daniel"
}
I have the following Spring Method :
#RequestMapping(value = "/product/{productId}", method = RequestMethod.GET ,produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getProductById(
//ProductDTO database query in order to retrieve productg by ID and population
final ObjectMapper objectMapper = new ObjectMapper();
final String json = objectMapper.writeValueAsString(productDTO);
return new ResponseEntity<>(json, HttpStatus.OK);
That returns a product representation in JSON format, the problem that I have is when I return this JSON , in the response I get it escaped like this:
"{\"uid\":\"test\",\"type\":\"Fragrance\",\"modifiedtime\":1575379505000,\"name\":\"test
name\",\"otherProperties\":{\"container\":false,\" ETC...``
I would need it unescaped in the response , how can I achieve this?
The reason I transform the DTO manually is because if I just return the DTO in the ResponseEntity the representation of the JSON handled by Spring is not the same as the one I get using objectMapper.writeValueAsString method , instead of getting this:
"name": "nombre de prueba",
"otherProperties": {
"container": false,
"onlineExclusive": false,
"sizeGuide": "size guide",etc..
I get this:
"name": "nombre de prueba",
"otherProperties": [
{
"key": "container",
"value": {
"type": "boolean",
"value": false
}
},
{
"key": "onlineExclusive",
"value": {
"type": "boolean",
"value": false
}
},
{
"key": "sizeGuide",
"value": {
"type": "string",
"value": "size guide"
}
},
```
There is a perfect .NET library Json.NET Schema. I use it in my C# application to parse schemas and make a Dictionary<string, JSchema> with pairs "name_of_simple_element" - "simple_element". Then I process each pair and for example try to find "string" type elements with pattern "[a-z]" or "string" elements with maximumLength > 300.
Now I should create application with same functions in Java. It is very simple in C#:
Jschema schema = JSchema.Parse(string json);
IDictionary<string, JSchema> dict = schema.Properties;
... etc.
But i cant find same way to do that in Java. I need to convert this
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://iitrust.ru",
"type": "object",
"properties": {
"regions": {
"id": "...regions",
"type": "array",
"items": {
"id": "http://iitrust.ru/regions/0",
"type": "object",
"properties": {
"id": {
"id": "...id",
"type": "string",
"pattern": "^[0-9]+$",
"description": "Идентификатор региона"
},
"name": {
"id": "...name",
"type": "string",
"maxLength": 255,
"description": "Наименование региона"
},
"code": {
"id": "...code",
"type": "string",
"pattern": "^[0-9]{1,3}$",
"description": "Код региона"
}
},
"additionalProperties": false,
"required": ["id",
"name",
"code"]
}
}
},
"additionalProperties": false,
"required": ["regions"]
}
to pseudocode dictionary/map like this
["...id" : "id": { ... };
"...name" : "name": { ... };
"...code": "code": { ... }]
What is the best way to do that?
Ok, problem is resolved by Jackson library. Code below is based on generally accepted rule that JSON Schema object is always has a "properties" element, "array" node is always has a "items" element, "id" is always unique. This is my customer's standart format. Instead of a C#'s Dictionary<string, Jschema> I have got a Java's HashMap<String, JsonNode>.
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
...
static Map<String, JsonNode> elementsMap = new HashMap<>();
public static void Execute(File file) {
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(file);
JsonNode rootNode = root.path("properties");
FillTheElementMap(rootNode);
}
private static void FillTheElementMap(JsonNode rootNode) {
for (JsonNode cNode : rootNode){
if(cNode.path("type").toString().toLowerCase().contains("array")){
for(JsonNode ccNode : cNode.path("items")){
FillTheElementMap(ccNode);
}
}
else if(cNode.path("type").toString().toLowerCase().contains("object")){
FillTheElementMap(cNode.path("properties");
}
else{
elementsMap.put(cNode.path("id").asText(), cNode);
}
}
A good option for you should be this Java implementation of JSONPath.
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONObject;
...
DocumentContext context = JsonPath.parse(jsonSchemaFile);
//"string" elements with maximumLength == 255
List<Map<String, JSONObject>> arr2 = context.read(
"$..[?(#.type == 'string' && #.maxLength == 255)]");
And if you want to create a JsonSchema from Java code, you could use jackson-module-jsonSchema.
If you want to validate a JsonSchema, then the library from fge is an option: json-schema-validator
You may want to take a look at this library, it's helped me with similar requirements. With a couple lines of code you can traverse a pretty straightforward Java object model that describes a JSON schema.
https://github.com/jimblackler/jsonschemafriend (Apache 2.0 license)
From the README:
jsonschemafriend is a JSON Schema loader and validator, delivered as a Java library...
It is compatible with the following metaschemas
http://json-schema.org/draft-03/schema#
http://json-schema.org/draft-04/schema#
http://json-schema.org/draft-06/schema#
http://json-schema.org/draft-07/schema#
https://json-schema.org/draft/2019-09/schema
I want to parse this json in android. Can you help me how to parse, if i need to start from head to parse or from results for this I don't know. Can you help me
{
"head":
{
"link": [],
"vars": ["city", "country"]
},
"results":
{
"distinct": false,
"ordered": true,
"bindings":
[
{
"city":
{
"type": "uri",
"value": "http://dbpedia.org/resource/Ferizaj"
} ,
"country":
{
"type": "uri",
"value": "http://dbpedia.org/resource/Kosovo"
}
}
]
}
}
Okay, first of all the JSON string you've given is invalid. I've written my answer based on the correct version of the JSON string that you have provided
{
"head":
{
"link": [],
"vars": ["city", "country"]
},
"results":
{
"distinct": false,
"ordered": true,
"bindings":
[
{
"city":
{
"type": "uri",
"value": "http://dbpedia.org/resource/Ferizaj"
} ,
"country":
{
"type": "uri",
"value": "http://dbpedia.org/resource/Kosovo"
}
}
]
}
}
Now, to get the "values", you'll need to do this.
JSONObject jsonObject = new JSONObject(response);
JSONObject results = jsonObject.getJSONObject("results");
JSONArray bindings = results.getJSONArray("bindings");
for (int i = 0; i < bindings.length(); i++) {
JSONObject binding = bindings.getJSONObject(i);
JSONObject city = binding.getJSONObject("city");
// Get value in city
String cityValue = city.getString("value");
Log.d("CITY", cityValue);
JSONObject country = binding.getJSONObject("country");
// Get value in country
String countryValue = country.getString("value");
Log.d("COUNTRY", countryValue);
}