Validating json payload against swagger file - json-schema-validator - java

I am trying to validate a json payload against a swagger file that contains the service agreement. I am using the json-schema-validator(2.1.7) library to achieve this, but at the moment it's not validating against the specified patterns or min/max length.
Java Code:
public void validateJsonData(final String jsonData) throws IOException, ProcessingException {
ClassLoader classLoader = getClass().getClassLoader();
File jsonSchemaFile = new File (classLoader.getResource("coachingStatusUpdate.json").getFile());
String jsonSchema = new String(Files.readAllBytes(jsonSchemaFile.toPath()));
final JsonNode dataNode = JsonLoader.fromString(jsonData);
final JsonNode schemaNode = JsonLoader.fromString(jsonSchema);
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
JsonValidator jsonValidator = factory.getValidator();
ProcessingReport report = jsonValidator.validate(schemaNode, dataNode);
System.out.println(report);
if (!report.toString().contains("success")) {
throw new ProcessingException (
report.toString());
}
}
Message I am sending through
{
"a": "b",
"c": "d",
"e": -1,
"f": "2018-10-30",
"g": "string" }
The swagger definition:
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Test",
"termsOfService": "http://www.test.co.za",
"license": {
"name": "Test"
}
},
"host": "localhost:9001",
"basePath": "/test/",
"tags": [
{
"name": "controller",
"description": "Submission"
}
],
"paths": {
"/a": {
"put": {
"tags": [
"controller"
],
"summary": "a",
"operationId": "aPUT",
"consumes": [
"application/json;charset=UTF-8"
],
"produces": [
"application/json;charset=UTF-8"
],
"parameters": [
{
"in": "body",
"name": "aRequest",
"description": "aRequest",
"required": true,
"schema": {
"$ref": "#/definitions/aRequest"
}
}
],
"responses": {
"200": {
"description": "Received",
"schema": {
"$ref": "#/definitions/a"
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Unauthorized"
},
"408": {
"description": "Request Timeout"
},
"500": {
"description": "Generic Error"
},
"502": {
"description": "Bad Gateway"
},
"503": {
"description": "Service Unavailable"
}
}
}
}
},
"definitions": {
"aRequest": {
"type": "object",
"required": [
"a",
"b",
"c",
"d"
],
"properties": {
"a": {
"type": "string",
"description": "Status",
"enum": [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h"
]
},
"aReason": {
"type": "string",
"description": "Reason",
"enum": [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n"
]
},
"correlationID": {
"type": "integer",
"format": "int32",
"description": "",
"minimum": 1,
"maximum": 9999999
},
"effectiveDate": {
"type": "string",
"format": "date",
"description": ""
},
"f": {
"type": "string",
"description": "",
"minLength": 1,
"maxLength": 100
}
}
},
"ResponseEntity": {
"type": "object",
"properties": {
"body": {
"type": "object"
},
"statusCode": {
"type": "string",
"enum": [
"100",
"101",
"102",
"103",
"200",
"201",
"202",
"203",
"204",
"205",
"206",
"207",
"208",
"226",
"300",
"301",
"302",
"303",
"304",
"305",
"307",
"308",
"400",
"401",
"402",
"403",
"404",
"405",
"406",
"407",
"408",
"409",
"410",
"411",
"412",
"413",
"414",
"415",
"416",
"417",
"418",
"419",
"420",
"421",
"422",
"423",
"424",
"426",
"428",
"429",
"431",
"451",
"500",
"501",
"502",
"503",
"504",
"505",
"506",
"507",
"508",
"509",
"510",
"511"
]
},
"statusCodeValue": {
"type": "integer",
"format": "int32"
}
}
}
}
}
As you can see I am sending through a correlationID of -1, which should fail validation, but at the moment is's returning as successful:
com.github.fge.jsonschema.report.ListProcessingReport: success

I suggest using this library, which worked for me:
https://github.com/bjansen/swagger-schema-validator
Example:
invalid-pet.json
{
"id": 0,
"category": {
"id": 0,
"name": "string"
},
"named": "doggie",
"photoUrls": [
"string"
],
"tags": [
{
"id": 0,
"name": "string"
}
],
"status": "available"
}
My SchemaParser:
#Component
public class SchemaParser {
private Logger logger = LoggerFactory.getLogger(getClass());
public boolean isValid(String message, Resource schemaLocation) {
try (InputStream inputStream = schemaLocation.getInputStream()) {
SwaggerValidator validator = SwaggerValidator.forJsonSchema(new InputStreamReader(inputStream));
ProcessingReport report = validator.validate(message, "/definitions/Pet");
return report.isSuccess();
} catch (IOException e) {
logger.error("IOException", e);
return false;
} catch (ProcessingException e) {
e.printStackTrace();
return false;
}
}
}
A test:
#Test
void shouldFailValidateWithPetstoreSchema() throws IOException {
final Resource validPetJson = drl.getResource("http://petstore.swagger.io/v2/swagger.json");
try (Reader reader = new InputStreamReader(validPetJson.getInputStream(), UTF_8)) {
final String petJson = FileCopyUtils.copyToString(reader);
final boolean valid = schemaParser.isValid(petJson, petstoreSchemaResource);
assertFalse(valid);
}
}

json-schema-validator seems to work with pure JSON Schema only. OpenAPI Specification uses an extended subset of JSON Schema, so the schema format is different. You need a library that can validate specifically against OpenAPI/Swagger definitions, such as Atlassian's swagger-request-validator.

Related

Overriding existing property of json, or adding next if not present in json

I have some JSON, declared as string for my testing purposes in main method.
My goal is to use JSONPATH with DocumentContext, to override property if property exists, and to add it if it does not exists.
Is there possibility to achieve that ?
My JSON
How to add new node to Json using JsonPath?
Convert a JSON object to another JSON object in Java
I've visited these two but my result is not JSON but "com.jayway.jsonpath.internal.JsonReader#1ae369b7"
{
"meta": {
"drilldownEnabled": false
},
"chart": {
renderTo:"container",
"additionalData": {
"dateTime": false,
"datetype": "string",
"cliccable": true,
"drillable": false,
"drillableChart": false,
"isCockpit": true,
"categoryColumn": "periodo_analisi",
"categoryGroupBy": "",
"categoryGroupByNamens": "",
"categoryName": "periodo_analisi",
"categoryOrderColumn": "",
"categoryOrderType": "",
"categoryStacked": "",
"categoryStackedType": ""
},
"zoomType": "xy",
"panning": true,
"type": "column",
"options3d": {
"enabled": false,
"alpha": 25,
"beta": 15,
"depth": 50,
"viewDistance": 25
},
"backgroundColor": "#FFFFFF",
"heightDimType": "pixels",
"widthDimType": "pixels",
"plotBackgroundColor": null,
"plotBorderWidth": null,
"plotShadow": false,
"borderColor": "#FFFFFF",
"style": {
"backgroundColor": "#FFFFFF",
"fontFamily": "",
"fontWeight": "",
"fontSize": ""
},
"events": {}
},
"colors": [
"#ff5722"
],
"title": {
"text": "",
"style": {
"align": "",
"color": "",
"fontFamily": "",
"fontSize": "",
"fontWeight": ""
}
},
"legend": {
"enabled": false
},
"xAxis": [
{
"plotBands": [
{
"label": {
"text": "",
"align": "center"
},
"color": "",
"from": 0,
"to": 0
}
],
"plotLines": [
{
"label": {
"text": "",
"align": "center"
},
"color": "",
"dashStyle": "",
"value": 0,
"width": 0
}
],
"type": "category",
"id": 0,
"title": {
"customTitle": false,
"text": "periodo_analisi",
"style": {}
},
"labels": {
"style": {
"color": "",
"fontFamily": "",
"fontSize": "",
"fontWeight": ""
},
"align": ""
}
}
],
"yAxis": [
{
"plotBands": [
{
"label": {
"text": "",
"align": "center"
},
"color": "",
"from": 0,
"to": 0
}
],
"plotLines": [
{
"label": {
"text": "",
"align": "center"
},
"color": "",
"dashStyle": "",
"value": 0,
"width": 0,
"zIndex": 1
}
],
"title": {
"text": "NUM_GG_GIACENZA_AVG",
"customTitle": false,
"style": {
"color": "",
"fontFamily": "",
"fontWeight": "",
"fontSize": ""
}
},
"labels": {
"style": {
"color": "",
"fontFamily": "",
"fontSize": "",
"fontWeight": ""
},
"align": ""
},
"gridLineDashStyle": "$convertedTypeline",
"minorGridLineDashStyle": "$convertedMinorTpeline"
}
],
"series": [
{
"name": "NUM_GG_GIACENZA_AVG",
"dataLabels": {
"style": {
"color": "",
"fontFamily": "",
"fontWeight": "",
"fontSize": "",
"fontStyle": ""
},
"enabled": true,
"labelFormat": "{y:,.2f}"
},
"data": [
{
"drilldown": false,
"y": 32.6667,
"name": "Q1-2019",
"datetype": "string"
},
{
"drilldown": false,
"y": 29,
"name": "Q3-2018",
"datetype": "string"
},
{
"drilldown": false,
"y": 134.5,
"name": "Q4-2018",
"datetype": "string",
"color": "#F10AE8"
}
],
"selected": true,
"tooltip": {
"valueDecimals": 2,
"scaleFactor": "empty",
"ttBackColor": "#FCFFC5"
},
"yAxis": 0
}
],
"tooltip": {
"borderWidth": 0,
"borderRadius": 0,
"followTouchMove": false,
"followPointer": true,
"useHTML": true,
"backgroundColor": null,
"style": {
"padding": 0
}
},
"lang": {
"noData": ""
},
"noData": {
"style": {
"fontFamily": "",
"fontSize": "",
"color": ""
},
"position": {
"align": "center",
"verticalAlign": "middle"
}
},
"credits": {
"enabled": false
},
"plotOptions": {
"line": {
"marker": {
"symbol": "circle",
"lineWidth": 2
}
},
"column": {},
"bar": {},
"series": {
"cursor": "pointer",
"point": {
"events": {}
},
"dataLabels": {
"allowOverlap": true
},
"turboThreshold": 2000
}
}
}
I simply place this JSON in string as cc variable and write
DocumentContext doc = JsonPath.parse(cc).set(JsonPath.compile("$.meta"), "nani");
doc.json();
System.out.println(doc);
You're printing the DocumentContext instance instead of its content.
Try:
System.out.println(doc.read([Your JsonPath]));
Go here for more Info.

how to parse the json response which starts with an array

response:
[
{
"id": "e9299032e8a34d168def176af7d62da3",
"createdAt": "Nov 8, 2017 9:46:40 AM",
"model": {
"id": "eeed0b6733a644cea07cf4c60f87ebb7",
"name": "color",
"app_id": "main",
"created_at": "May 11, 2016 11:35:45 PM",
"model_version": {}
},
"input": {
"id": "df6eae07cd86483f811c5a2202e782eb",
"data": {
"concepts": [],
"metadata": {},
"image": {
"url": "http://www.sachinmittal.com/wp-content/uploads/2017/04/47559184-image.jpg"
}
}
},
"data": [
{
"hex": "#f59b2d",
"webSafeHex": "#ffa500",
"webSafeColorName": "Orange",
"value": 0.0605
},
{
"hex": "#3f1303",
"webSafeHex": "#000000",
"webSafeColorName": "Black",
"value": 0.2085
},
{
"hex": "#a33303",
"webSafeHex": "#8b0000",
"webSafeColorName": "DarkRed",
"value": 0.3815
},
{
"hex": "#000000",
"webSafeHex": "#000000",
"webSafeColorName": "Black",
"value": 0.34275
},
{
"hex": "#f7ce93",
"webSafeHex": "#ffdead",
"webSafeColorName": "NavajoWhite",
"value": 0.00675
}
],
"status": {}
}
]
need to parse this reponse in json. Please help me out.
You can try something like this..
try{
JSONArray array= new JSONArray(Yourresponse);
for(int i=0; i<=array.length();i++){
JSONObject jsonObject=array.getJSONObject(i);
String id= jsonObject.getString("id");
String created_at= jsonObject.getString("createdAt");
String model_id = jsonObject.getJSONObject("model").getString("id");
String app_id=jsonObject.getJSONObject("model").getString("app_id");
//So On... Depends on your requirements. It's just an idea!
}
}
catch (Exception e){
e.printStackTrace();
}

Elasticsearch: sort by value and dynamic templates

I need sorting for the documents like :
{
customer: {
fullname: "Lorem ipsum"
},
order_number: "12313131",
company: {
name: "Test Inc."
},
date: "10.06.2015 18:00"
}
But as far as I unterstood I can not sort by values in analysed fields. There I am trying to create a mapping :
{
"mappings": {
"_default_": {
"dynamic_templates": [
{
"base": {
"match": "*",
"mapping": {
"type": "multi_field",
"fields": {
"{name}": {"type": "string"},
"_sort": {"type": "string", "analyzer": "sort"}
}
}
}
}
]
}
},
"settings": {
"analysis": {
"analyzer": {
"sort": {
"type": "custom",
"tokenizer": "keyword",
"filter": "lowercase"
}
}
}
}
}
But if I put this configuration, I am getting an exception : ElasticsearchIllegalArgumentException: unknown property. Without this mapping my indexing works fine.
What i want to do is create a multifield called name_sort (not_analysed) so I can sort by values.
****
At leas I can able to create a mapping correctly. My mapping looks like:
{
"muhamo": {
"mappings": {
"bookings": {
"dynamic_templates": [
{
"base": {
"mapping": {
"index": "analyzed",
"type": "{dynamic_type}",
"fields": {
"{name}_sort": {
"index": "not_analyzed",
"type": "{dynamic_type}"
}
}
},
"match": "*",
"match_mapping_type": "string"
}
},
{
"catch_all": {
"mapping": {
"fields": {
"{name}_sort": {
"index": "not_analyzed",
"type": "{dynamic_type}"
}
}
},
"match": "*",
"match_mapping_type": "*"
}
}
],
"properties": {
"bookingType": {
"type": "string",
"fields": {
"bookingType_sort": {
"type": "string",
"index": "not_analyzed"
}
}
},
"comment": {
"type": "string",
"fields": {
"comment_sort": {
"type": "string",
"index": "not_analyzed"
}
}
},
"costLocation": {
"type": "string",
"fields": {
"costLocation_sort": {
"type": "string",
"index": "not_analyzed"
}
}
},
"customer": {
"properties": {
"fullname": {
"type": "string",
"fields": {
"fullname_sort": {
"type": "string",
"index": "not_analyzed"
}
}
}
}
},
"date": {
"type": "string",
"fields": {
"date_sort": {
"type": "string",
"index": "not_analyzed"
}
}
},
"deleted": {
"type": "boolean"
},
"toAirport": {
"type": "boolean"
}
}
}
}
}
}
But if I try to sort my results by customer.fullname_sort I am getting an exception as
query[ConstantScore(*:*)],from[-1],size[-1]: Parse Failure [No mapping found for [customer.fullname_sort] in order to sort on]
You should sort on customer.fullname.fullname_sort. That's the path to your field, according to the mapping of the index.

Elasticsearch: Multi-level nested query not working

My mapping is as follows:
{
"mappings": {
"person": {
"properties": {
"lastUpdated": {
"type": "long"
},
"isDeleted": {
"type": "boolean"
},
"person": {
"properties": {
"car": {
"type": "nested",
"properties": {
"model": {
"type": "string"
},
"make": {
"type": "string"
}
}
},
"last_name": {
"type": "string"
},
"first_name": {
"type": "string"
}
}
}
}
}
}
}
I have two documents:
{
"person": {
"first_name": "Bob",
"last_name": "Doe",
"car": [
{
"make": "Saturn",
"model": "Imprezza"
},
{
"make": "Honda",
"model": "Accord"
}
]
},
"isDeleted": false,
"lastUpdated": 1433257051959
}
and
{
"person": {
"first_name": "Zach",
"last_name": "Foobar",
"car": [
{
"make": "Saturn",
"model": "SL"
},
{
"make": "Subaru",
"model": "Imprezza"
}
]
},
"isDeleted": false,
"lastUpdated": 1433257051959
}
I wanted to query the car.make field and so, I wrote the following query:
{
"query": {
"nested": {
"path": "person.person.car",
"query": {
"match": {
"car.make": "Saturn"
}
},
"inner_hits": {}
}
}
}
However, I am not getting anything back results back in return. When I remove the person level object and try to search, then it works. Any idea how to go about doing multi-level nested queries?
EDIT: On the other hand, when I structure my data like this and query then it works.
{
"mappings": {
"person": {
"properties": {
"car": {
"type": "nested",
"properties": {
"model": {
"type": "string"
},
"make": {
"type": "string"
}
}
},
"last_name": {
"type": "string"
},
"first_name": {
"type": "string"
}
}
}
}
}
{
"first_name": "Zach",
"last_name": "Foobar",
"car": [
{
"make": "Saturn",
"model": "SL"
},
{
"make": "Subaru",
"model": "Imprezza"
}
]
}
{
"first_name": "Bob",
"last_name": "Doe",
"car": [
{
"make": "Saturn",
"model": "Imprezza"
},
{
"make": "Honda",
"model": "Accord"
}
]
}
{
"query": {
"nested": {
"path": "person.car",
"query": {
"match": {
"car.make": "Honda"
}
},
"inner_hits": {}
}
}
}
This way the query works. I feel like this has something to do with multi-level nesting. Multi-level nesting is not working.
The nested path attribute needs to be "person.car".
Add "type": "nested", above the (2nd level) person properties line if you wish person to be a nested field type, which is required for Nested Query searches. The default field type is object field.
The naming you are using is confusing, try to rename your mapping not to use person twice.
{
"query": {
"nested": {
"path": "person.car",
"query": {
"match": {
"make": "Saturn"
}
},
"inner_hits": {}
}
}
}

JSONObject keys order reverse

I searched across many sources but could not find the answer to this one..
Its a know fact that a JSONObject keys are returned in reverse order.
Is there any way to recurse through a JSONObject in the correct order as appearing in JSON
String json;
JSONObject obj = new JSONObject(json)
Iterator<String> keys = json.keys() ---> order is reversed
I understand JSONObject is unordered, perhaps there is a way to order it????
JSON is of type below..and the keys start getting recursed from the bottom most styleHint tag
"sections": {
"1": {
"1": {
"1": {
"title": "xxx",
"text": "xxx",
"tags": {
"audience": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
},
"styleHint": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
}
}
},
"title": "xxx",
"text": "xxx",
"tags": {
"audience": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
},
"styleHint": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
}
}
},
"2": {
"title": "xxx",
"text": "xxx",
"tags": {
"audience": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
},
"styleHint": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
}
}
},
"title": "xxx",
"text": "xxx",
"tags": {
"audience": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
},
"2": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
},
"styleHint": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
}
}
},
"2": {
"title": "xxx",
"text": "xxx",
"tags": {
"audience": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
},
"styleHint": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
}
},
"anchor":"xxx"
},
"3": {
"1": {
"title": "xxx",
"text": "xxx",
"tags": {
"audience": {
"tag": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
},
"styleHint": {
"tag": {
"name": "xxx",
"title": "xxx",
"id": "xxx"
}
}
}
},
"title": "xxx",
"text": "xxx",
"tags": {
"audience": {
"1": {
"name": "xxx",
"title": "xxx",
"id": "xxxx"
}
},
"styleHint": {
"1": {
"name": "xx",
"title": "xxx",
"id": "xxxx"
}
}
}
}
}
How about that
Get your org.json.JSONObject source and change these
public ListIterator keys() {
ListIterator iter = new ArrayList(this.keySet()).listIterator();
return iter;
}
and
/**
* Construct an empty JSONObject.
*/
public JSONObject() {
this.map = new LinkedHashMap();
}
and
/**
* The map where the JSONObject's properties are kept.
*/
private final LinkedHashMap map;
and
public JSONObject(Map map) {
this.map = new LinkedHashMap();
if (map != null) {
Iterator i = map.entrySet().iterator();
while (i.hasNext()) {
Map.Entry e = (Map.Entry) i.next();
Object value = e.getValue();
if (value != null) {
this.map.put(e.getKey(), wrap(value));
}
}
}
}
I hope I don't burn in hell for that.

Categories

Resources