springfox swagger configuration for JsonNode property in a model class - json

I have a Model 'NewModel' with the following property
import com.fasterxml.jackson.databind.JsonNode;
#ApiModel(
description = "Data Class to hold new details"
)
public class NewModel {
#ApiModelProperty(
notes = "Value in JSON key:value format. Can be any key:value pair",
example = "{ds:2017:08:05,hh:11}"
)
private final JsonNode value;
(... getters and setters ...)
}
Apart from this, I have some rest controllers which get a JSON in request body. I use this model to get the JSOn from request body.
I have configured springfox swagger using maven, and generated the api definition. But in the generated API definitions, this model has been generated as
"NewModel": {
"type": "object",
"properties": {
"value": {
"example": "{nds:2017:08:05,hh:11}",
"description": "Value of the stamp in JSON key:value format",
"$ref": "#/definitions/JsonNode"
}
},
"description": "Data Class to hold details"
}
And the reference JsonNode definition generated is
"definitions": {
"JsonNode": {
"type": "object",
"properties": {
"array": {
"type": "boolean"
},
"bigDecimal": {
"type": "boolean"
},
"bigInteger": {
"type": "boolean"
},
"binary": {
"type": "boolean"
},
"boolean": {
"type": "boolean"
},
"containerNode": {
"type": "boolean"
},
"double": {
"type": "boolean"
},
"float": {
"type": "boolean"
},
"floatingPointNumber": {
"type": "boolean"
},
"int": {
"type": "boolean"
},
"integralNumber": {
"type": "boolean"
},
"long": {
"type": "boolean"
},
"missingNode": {
"type": "boolean"
},
"nodeType": {
"type": "string",
"enum": [
"ARRAY",
"BINARY",
"BOOLEAN",
"MISSING",
"NULL",
"NUMBER",
"OBJECT",
"POJO",
"STRING"
]
},
"null": {
"type": "boolean"
},
"number": {
"type": "boolean"
},
"object": {
"type": "boolean"
},
"pojo": {
"type": "boolean"
},
"short": {
"type": "boolean"
},
"textual": {
"type": "boolean"
},
"valueNode": {
"type": "boolean"
}
}
}
Now, when I generate a client library with this API definition, the JsonNode Object allowed on the client side has only Boolean variables, and I cannot assign actual JSON strings to it, and hence cannot pass a JSON value to the connecting server (from which I generated the API definitions)
I was wondering is there was a way I could get to pass Json Strings from client to server using the swagger generated libraries. Or any other directions in which I can achieve the required end result.
Thanks (and apologies for the long post)

An attribute in ApiModelProperty, dataType="java.util.Map" should help
public class NewModel {
#ApiModelProperty(
example = "{ds:2017:08:05,hh:11}",
dataType = "java.util.Map"
)
private final JsonNode value;

Perhaps AlternateTypeRuleConvention, which is introduced in Springfox, will help you.
For example, you can do this:
#Bean
public AlternateTypeRuleConvention typeConvention(final TypeResolver resolver) {
return new AlternateTypeRuleConvention() {
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
#Override
public List<AlternateTypeRule> rules() {
return Collections.singletonList(
AlternateTypeRules.newRule(resolver.resolve(JsonNode.class), resolver.resolve(jsonNodeApi()))
);
}
};
}
private Type jsonNodeApi() {
return new AlternateTypeBuilder()
.fullyQualifiedClassName(
String.format("%s.generated.%s",
JsonNode.class.getPackage().getName(),
JsonNode.class.getSimpleName()))
.build();
}
AlternateTypeBuilder also allows you to specify custom fields if necessary.

Related

JSON Schema Validator Selecting Validators

My problem is how do I get the json-schema-validator library to actually validate a JSON response against the JSON Schema I have defined. My goal is to get "additionalProperties" and field type checking working. I.e. have the validation reject unknown fields and check that numerics don't contain strings etc.
Files, code and background information follow.
Schema Swagger 2.0 standard definition
Schema Students API Defintion
{
"swagger": "2.0",
"info": {
"title": "Students API",
"description": "Operations on Students",
"version": "1.0"
},
"basePath": "/v1/students",
"schemes": [
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json",
"application/xml"
],
"paths": {
"/{UID}": {
"get": {
"tags": [
"students"
],
"summary": "Get information about a Students Member.",
"description": "Given an University ID, return information for the identified students member.",
"operationId": "getStudentsByUID",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"required": true,
"name": "UID",
"in": "path",
"type": "string"
}
],
"responses": {
"200": {
"description": "OK. The operation was successful.",
"schema": {
"$ref": "#/definitions/Students"
}
},
"204": {
"description": "No Content. No Students the UID"
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Not Authorised"
},
"405": {
"description": "Method Not Allowed"
},
"429": {
"description": "Too Many Requests"
},
"500": {
"description": "Internal Server Error"
}
}
}
}
},
"definitions": {
"Students": {
"type": "object",
"additionalProperties": false,
"properties": {
"Status": {
"$ref": "#/definitions/Status"
},
"Person": {
"type": "array",
"items": {
"$ref": "#/definitions/Person"
}
}
}
},
"Status": {
"type": "object",
"additionalProperties": false,
"properties": {
"StatusCode": {
"type": "integer"
},
"Reason": {
"type": "string"
}
},
"required": [
"StatusCode",
"Reason"
]
},
"Person": {
"type": "object",
"description": "Representation of a person record for a student",
"properties": {
"PersonIdentifiers": {
"type": "object",
"properties": {
"Identifier": {
"type": "array",
"items": {
"$ref": "#/definitions/Identifier"
}
}
}
},
"PersonNames": {
"$ref": "#/definitions/PersonNames"
},
"AcademicPlanDetails": {
"type": "object",
"properties": {
"AcademicPlanDetail": {
"type": "array",
"items": {
"$ref": "#/definitions/AcademicPlanDetail"
}
}
}
}
}
},
"Identifier": {
"type": "object",
"properties": {
"IdentifierType": {
"type": "string"
},
"IdentifierValue": {
"type": "string"
}
}
},
"PersonNames": {
"type": "object",
"properties": {
"FirstName": {
"type": "string"
},
"MiddleName": {
"type": "string"
},
"LastName": {
"type": "string"
},
"Title": {
"type": "string",
"enum": [
"Mr",
"Mrs",
"Ms",
"Master",
"Dr"
]
},
"NameSuffixes": {
"description": "Not applicable to all Persons",
"type": "string",
"enum": [
"Jr",
"CPA",
"Esq",
"Ph.D"
]
},
"FullName": {
"type": "string"
},
"PreferredName": {
"description": "Not applicable to all Persons",
"type": "string"
},
"LongName": {
"type": "string"
},
"AliasName": {
"description": "Not applicable to all Persons",
"type": "string"
},
"Pronunciation": {
"description": "Not applicable to all Persons",
"type": "string"
}
}
},
"AcademicPlanDetail": {
"type": "object",
"properties": {
"AcademicCareer": {
"type": "string"
},
"StudentCareerNumber": {
"type": "string"
},
"EffectiveDate": {
"type": "string"
},
"EffectiveSequence": {
"type": "string"
},
"AcademicProgram": {
"type": "string"
},
"AcademicProgramDescription": {
"type": "string"
},
"AcademicPlan": {
"type": "string"
},
"AcademicPlanDescription": {
"type": "string"
},
"AcademicSubPlan": {
"type": "string"
},
"AcademicSubPlanDescription": {
"type": "string"
},
"ProgramStatus": {
"type": "string"
},
"ProgramStatusDescription": {
"type": "string"
},
"ProgramAction": {
"type": "string"
},
"ProgramActionDescription": {
"type": "string"
},
"ProgramReason": {
"type": "string"
},
"ProgramReasonDescription": {
"type": "string"
},
"AdmittedTerm": {
"type": "string"
},
"ResearchStudentCandidateNumber": {
"type": "string"
}
}
}
},
"tags": [
{
"name": "api-metadata",
"description": "Information about the API including its terms of use"
},
{
"name": "students",
"description": "Operations on all types of University students"
}
]
}
Students Response Good Valid response message
{
"Status": {
"StatusCode": 200,
"Reason": "OK",
},
"Person": [
{
"PersonIdentifiers": {
"Identifier": [
{
"IdentifierType": "UniversityID",
"IdentifierValue": "12345678"
},
{
"IdentifierType": "EmailAddress",
"IdentifierValue": "JohnSmith#no.such.org"
},
{
"IdentifierType": "PositionNumber",
"IdentifierValue": "00006789"
}
]
},
"PersonNames": {
"PreferredName": "",
"FirstName": "Johnathon",
"MiddleName": "",
"LastName": "Smith",
"Title": "Dr",
"NameSuffixes": "",
"FullName": "Smith,Jonathon",
"LongName": "",
"AliasName": "",
"Pronunciation": ""
},
"AcademicPlanDetails": {
"AcademicPlanDetail": [
{
"AcademicCareer": "RSCH",
"StudentCareerNumber": "0",
"EffectiveDate": "2019-12-19",
"EffectiveSequence": "1",
"AcademicProgram": "9876",
"AcademicProgramDescription": "Arts & Social Sciences",
"AcademicPlan": "9876XPHD",
"AcademicPlanDescription": "School of Humanities and the Arts",
"AcademicSubPlan": "HUMAN",
"AcademicSubPlanDescription": "Humanities",
"ProgramStatus": "AC",
"ProgramStatusDescription": "Active",
"ProgramAction": "MATR",
"ProgramActionDescription": "Matriculate",
"ProgramReason": "ACTV",
"ProgramReasonDescription": "Activated Manually",
"AdmittedTerm": "1903",
"ResearchStudentCandidateNumber": "000000034567"
}
]
}
}
]
}
Students Response Bad Invalid response message. Includes unwanted aggregates, fields and wrong data types.
{
"Fred": {
"Freddy": "Kruger"
},
"Status": {
"StatusCode": "200",
"Reason": "OK",
"X-Event-Id": "12340818-5a7c-11ea-920e-0a2835080000-1",
"Unexpected": "Undefined additional propery"
},
"Person": [
{
"PersonIdentifiers": {
"Identifier": [
{
"IdentifierType": "UniversityID",
"IdentifierValue": "12345678"
},
{
"IdentifierType": "EmailAddress",
"IdentifierValue": "JohnSmith#no.such.org"
},
{
"IdentifierType": "PositionNumber",
"IdentifierValue": "00006789"
}
]
},
"PersonNames": {
"PreferredName": "",
"FirstName": "Johnathon",
"MiddleName": "",
"LastName": "Smith",
"Title": "Dr",
"NameSuffixes": "",
"FullName": "Smith,Jonathon",
"LongName": "",
"AliasName": "",
"Pronunciation": ""
},
"AcademicPlanDetails": {
"AcademicPlanDetail": [
{
"AcademicCareer": "RSCH",
"StudentCareerNumber": "0",
"EffectiveDate": "2019-12-19",
"EffectiveSequence": "1",
"AcademicProgram": "9876",
"AcademicProgramDescription": "Arts & Social Sciences",
"AcademicPlan": "9876XPHD",
"AcademicPlanDescription": "School of Humanities and the Arts",
"AcademicSubPlan": "HUMAN",
"AcademicSubPlanDescription": "Humanities",
"ProgramStatus": "AC",
"ProgramStatusDescription": "Active",
"ProgramAction": "MATR",
"ProgramActionDescription": "Matriculate",
"ProgramReason": "ACTV",
"ProgramReasonDescription": "Activated Manually",
"AdmittedTerm": "1903",
"ResearchStudentCandidateNumber": "000000034567"
}
]
}
}
]
}
Code JSON Schema and JSON Instance validation
package com.nsd;
import java.io.File;
import java.io.IOException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.fge.jackson.JsonLoader;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
public class JsvCmd {
public static final String JSON_V4_SCHEMA_IDENTIFIER = "http://json-schema.org/draft-04/schema#";
public static final String JSON_SCHEMA_IDENTIFIER_ELEMENT = "$schema";
public static void main(String[] args) throws IOException, ProcessingException {
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
// Load the JSON Schema for Swagger 2.0 API definition
File swaggerSchemaFile = new File("/Users/syntegrity/Documents/AnuStuff/Swagger2.0.json");
JsonNode jsonNodeSwagger = JsonLoader.fromFile(swaggerSchemaFile);
JsonNode schemaIdentifierSwagger = jsonNodeSwagger.get(JSON_SCHEMA_IDENTIFIER_ELEMENT);
if (null != schemaIdentifierSwagger) {
System.out.println("Swagger Schema Type: " + schemaIdentifierSwagger.asText());
}
final JsonSchema jsonSchemaSwagger = factory.getJsonSchema(jsonNodeSwagger);
// Next load the schema we are interested in and validate it against the Swagger 2.0 API schema
File userSchemaFile = new File("/Users/syntegrity/Documents/AnuStuff/Students_V1_SO.json");
JsonNode jsonNodeUserSchema = JsonLoader.fromFile(userSchemaFile);
ProcessingReport userSchemaReport = jsonSchemaSwagger.validate(jsonNodeUserSchema, true);
if (!userSchemaReport.isSuccess()) {
System.out.println("UserSchema is invalid");
System.out.println(userSchemaReport);
return;
}
// To get the validators we want used happening add a $schema element that specifies IETF Draft-04
JsonNode schemaIdentifierUser = jsonNodeUserSchema.get(JSON_SCHEMA_IDENTIFIER_ELEMENT);
if (null == schemaIdentifierUser) {
((ObjectNode) jsonNodeUserSchema).put(JSON_SCHEMA_IDENTIFIER_ELEMENT, JSON_V4_SCHEMA_IDENTIFIER);
System.out.println("User Schema coerced to IETF Draft-04 for validation purposes");
} else {
// For what we want to do anything other than a $schema value of IETF Draft-04 is going
// to cause problems. NOTE: The Swagger 2.0 API schema does not allow $schema anyway
if (!JSON_V4_SCHEMA_IDENTIFIER.equals(schemaIdentifierUser.asText())) {
System.out.println("Schema Type: " + schemaIdentifierUser.asText() + " is not " + JSON_V4_SCHEMA_IDENTIFIER);
return;
}
}
JsonSchema jsonSchemaUser = factory.getJsonSchema(jsonNodeUserSchema);
// Finally validate the JSON data
File jsonDataFile = new File("/Users/syntegrity/Documents/AnuStuff/Students_Bad_SO.json");
JsonNode jsonNodeData = JsonLoader.fromFile(jsonDataFile);
ProcessingReport userDataReport = jsonSchemaUser.validate(jsonNodeData, true);
if (!userSchemaReport.isSuccess()) {
System.out.println(userDataReport);
} else {
System.out.println("Sweet");
}
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nsd</groupId>
<artifactId>jsvcmd</artifactId>
<version>1.0.0</version>
<name>JsonValidator</name>
<description>JSON Validator Command Line</description>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.atlassian.oai/swagger-request-validator -->
<dependency>
<groupId>com.github.fge</groupId>
<artifactId>json-schema-validator</artifactId>
<version>2.2.6</version>
</dependency>
<dependency>
<groupId>com.github.fge</groupId>
<artifactId>jackson-coreutils</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Run Results
Swagger Schema Type: http://json-schema.org/draft-04/schema#
User Schema coerced to IETF Draft-04 for validation purposes
Sweet
I was hoping to see the following errors rather than "Sweet"
Unwanted: [Fred]
Unwanted: [X-Event-Id]
Unwanted: [Unexpected]
"200" is not of type integer
Debugging
If I change "produces" to "producesx" in the Students Schema the I get the following output.
UserSchema is invalid
com.github.fge.jsonschema.core.report.ListProcessingReport: failure
--- BEGIN MESSAGES ---
error: object instance has properties which are not allowed by the schema: ["producesx"]
level: "error"
schema: {"loadingURI":"#","pointer":""}
instance: {"pointer":""}
domain: "validation"
keyword: "additionalProperties"
unwanted: ["producesx"]
--- END MESSAGES ---
So when I use the Swagger 2.0 Schema to validate my Students Schema after making it invalid I get an error message. Yay.
This is not the case when I try to use Students Schema to validate Students Response Bad.
After getting very frustrated I finally decide to use Java Debug to step into the json-schema-validator and json-schema-core libraries.
In the InstanceValidator.class, see screenshots below, I found that for the first jsonSchemaSwagger.validate(jsonNodeUserSchema, true); call there were three validators linked to the fullContext object whereas in the second jsonSchemaUser.validate(jsonNodeData, true); call there were no validators linked to the fullContext object. Which I'm pretty sure means that no validation will take place.
First Call
InstanceValidator.class
Three Validators AdditionalPropertiesValidator, RequiredKeywordValidator and DraftV4TypeValidator
Second Call
No Validators
Finally
And so finally to the question. What calls do I need to make to use the same set of Validators for my second validation call? I.e. how do a create a list of Validators and then get them executed against the JSON Instance data?

jsonschema validation using allof and complex if else

enter image description hereI have a json schema looks like below,and I want load the definitions into D and E based on the values of B and C for that I've written allOf conditioning.
and i'm using json-schema-validator for json schema validation in application.
i)the below schema always passing as valid because the allOf condition never evaluated and it's not
loading validators properties like maxLenth,multipleOf from the definitions.
ii)I was suspecting I did the conditioning in a wrong place(the root schema or sub schema) and i tried
moving this allof logic to subschema level(inside the B,C and D,E)
iii)I've tried executing the allOf example mentioned on https://json-schema.org/understanding-json-schema/reference/conditionals.html it is also passing as valid. for this I did verified on a online josn schema validator http://json-schema-validator.herokuapp.com/ which is also using same library json-schema-validator.
iv)is there any ValidationConfiguration requires for JsonSchemaFactory to validate the Draft7 jsonSchema conditioning since the Defaultlibrary is DRAFT-4 on this json-schema-validator.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"A",
"B",
"C",
"D",
"E"
],
"properties": {
"A": {
"type": "string"
},
"B": {
"type": "string",
"enum": ["TEST1","TEST2"]
},
"C": {
"type": "string",
"enum": ["TEST3","TEST4"]
},
"D": {
"type": "object"
},
"E": {
"type": "object"
}
},
"allOf": [
{
"if": {
"properties": { "B": { "const": "TEST1" } }
},
"then": {
"properties": { "D": { "$ref": "#/definitions/test" } }
}
},
{
"if": {
"properties": { "B": { "const": "TEST2" } }
},
"then": {
"properties": { "D": { "$ref": "#/definitions/testTwo" } }
}
},
{
"if": {
"properties": { "C": { "const": "TEST3" } }
},
"then": {
"properties": { "E": { "$ref": "#/definitions/testThree" } }
}
},
{
"if": {
"properties": { "C": { "const": "TEST4" } }
},
"then": {
"properties": { "E": { "$ref": "#/definitions/test4" } }
}
}
],
"definitions": {
"testOne":{"type":"object"},
"testTwo":{"type":"object"},
"testThree":{"type":"object"},
"testFour":{"type":"object"}
}
}
And the javaCode looks like
#PostMapping("/sendMessage")
public ProcessingReport sendMessage(#RequestBody SampleRequest request) throws IOException, ProcessingException {
//step-1 writing request object into String
String requestJson = objectMapper.writeValueAsString(request);
//Step-2 getting jsonNode for requested json
JsonNode dataNode = JsonLoader.fromString(requestJson);
//step -3 creating jsonSchema factory(default)
JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
//validating requested jsonNode(dataNode) against SchemaNode(schema of request json,which is loaded from resources)
ProcessingReport report = factory.getJsonSchema(schemaNode).validate(dataNode);
//Processing report resulting the given json validation is successful or not
if(!report.isSuccess()) {
System.out.println(report);
}
return report;
}
json-schema-validator only supports draft-03 and draft-04. if/then/const were added in later drafts. Those keywords get ignored resulting in the no-op behavior you're experiencing.
You have two choices
pick a different implementation that supports draft-07
Use the Implication Pattern instead. It's a little more verbose, but the result is the same.

jsonschema2pojo generating all variable of type object but not the data type i provide

I am new to this API. Trying to generate a class of 10-15 fields of different data type. But generated class has the 1st variable of the type I declared but remaining if type Object as below.
// Schema
{
"type":"object",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "String"
},
"baz": {
"type": "String"
}
}
}
//Generated Class
//...
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"foo",
"bar",
"baz"
})
public class Sample{
#JsonProperty("foo")
private String foo;
#JsonProperty("bar")
private Object bar;
#JsonProperty("baz")
private Object baz;
#JsonIgnore
....//
If you notice the 2nd and 3rd variable are declared String but result generated from class is of type object. Can someone help understand what the issue is?
{
"type":"object",
"properties": {
"length": {
"type": "string"
},
"width": {
"type": "string"
},
"height": {
"type": "string"
},
"dimensionalWeight": {
"type": "string"
}
}
}

Json Schema - how to express a field mixed Types (string and object)?

I have a field in our data with multiple typing:
It could be type=string, which has the schema:
{"mixed_field" : {"type":"string"} }
Other times it could be type=object, the schema looks like:
{"mixed_field" : {
"properties": {
"access_token": {
"type": "string"
},
"created_at": {
"type": "integer"
}
},
"type": "object"
}
}
How do I express that "mixed_field" can be either type string or type object? Should I use the "oneOf" keyword as follows?
{
"mixed_field": {
"oneOf": [
{
"type": "string"
},
{
"properties": {
"access_token": {
"type": "string"
},
"created_at": {
"type": "integer"
}
},
"type": "object"
}
]
}
}
You can use oneOf/anyOf or you can use "type": ["string", "object"], in case it is a string "properties" keyword will be ignored.

How can I define the sequence of properties in JSON Schema?

I have following java Object:
ProcessBean.java
import java.util.List;
import com.fasterxml.jackson.annotation.JsonRootName;
#JsonRootName(value = "process")
public class ProcessBean{
private Integer id;
private String name;
private String description;
private String user;
private String executePermissions;
private String createdDtm;
private String updatedDtm;
private Process tpProcess;
private List<ProcessParamBean> processParameters;
/* --------Getters and Setters ----------*/
}
I need to find the JSON schema for this object which is used to display these fields on UI. The order of fields in UI is determined by the order of properties in JSON schema generated.
I have generated the schema using following code:
DataSpec.java
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
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.factories.SchemaFactoryWrapper;
public class DataSpec {
public static <T> String getDataSpec(Class<T> clazz) {
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();
MetauiVisitorContext obj = new MetauiVisitorContext();
visitor.setVisitorContext(obj);
try {
mapper.acceptJsonFormatVisitor(clazz, visitor);
JsonSchema schema = visitor.finalSchema();
return mapper.writeValueAsString(schema);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
}
MetauiVisitorContext.java
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.module.jsonSchema.factories.VisitorContext;
public class MetauiVisitorContext extends VisitorContext{
#Override
public String getSeenSchemaUri(JavaType aSeenSchema) {
return null;
}
}
The resultant schema looks like below:
{
"type": "object",
"id": "urn:jsonschema:com:restservices:api:jsonbeans:ProcessBean",
"properties": {
"updatedDtm": {
"type": "string"
},
"createdDtm": {
"type": "string"
},
"name": {
"type": "string"
},
"tpProcess": {
"type": "object",
"id": "urn:jsonschema:com:restservices:api:jsonbeans:Process",
"properties": {
"name": {
"type": "string"
},
"id": {
"type": "integer"
}
}
},
"description": {
"type": "string"
},
"id": {
"type": "integer"
},
"processParameters": {
"type": "array",
"items": {
"type": "object",
"id": "urn:jsonschema:com:restservices:api:jsonbeans:ProcessParamBean",
"properties": {
"updatedDtm": {
"type": "string"
},
"defaultValue": {
"type": "string"
},
"createdDtm": {
"type": "string"
},
"masterParam": {
"type": "object",
"id": "urn:jsonschema:com:restservices:api:jsonbeans:MasterParamBean",
"properties": {
"updatedDtm": {
"type": "string"
},
"createdDtm": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "integer"
}
}
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"processParamId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"userPrompted": {
"type": "boolean"
},
"tags": {
"type": "string"
}
}
}
},
"executePermissions": {
"type": "string"
},
"user": {
"type": "string"
}
}
}
As it can be seen that the order of properties in JSON schema does not match the order of fields defined in Java object which is necessary in my case.
So how can I determine the sequence of the properties?
There is not an intrinsic order of properties in a JSON schema object, as it happens with a regular JSON or javascript object. Indeed, it does not change the validation semantics. The following schemas validate exactly the same collection of objects:
Schema 1:
{
"properties" : {
"prop1" : {
"type" : "string"
},
"prop2" : {
"type" : "number"
}
}
}
Schema 2:
{
"properties" : {
"prop2" : {
"type" : "number"
},
"prop1" : {
"type" : "string"
}
}
}
If you want to preserve some ordering you need to do it within and array. You could achieve this by using an array of objects instead of an object in the items clause. An example:
{
"type" : "array" :
"items" : [{
"properties" : {
"prop2" : {
"type" : "number"
}
}
}, {
"properties" : {
"prop1" : {
"type" : "string"
}
}
}
]
}
This way you get an ordered definition of UI items. Unfortunately, it forces you to nest each single property in an object.
Order is out of scope for json-schema. For that you need to look into json-forms https://jsonforms.io/, standards, which is extension of json-schema. It consist of three separate JSON data :
schema
values
ui-schema
The ui-schema contains the information about the ui and presentation, like order of properties (fields) and the their visual presentation, like "hidden", "read-only".