Java Class to JSON custom Schema by Annotation - java

I am currently generating my Json Schema like this:
class Item {
public int id;
public string name;
public string description;
}
ObjectMapper mapper = new ObjectMapper();
SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();
mapper.acceptJsonFormatVisitor(Item.class, visitor);
JsonSchema schema = visitor.finalSchema();
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema));
Which prints:
{
"type": "object",
"id": "urn:jsonschema:de:foo:bar:User",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"description": { "type": "string" }
}
}
Now I want to append additional information to each type from annotations of the Item class. I want this to provide information for how to display an input for that field.
class User {
public int id;
public string name;
#MyJsonSchemaAnnotation(fieldName = "input", value = "textarea")
public string description;
}
Which will give me:
{
"type": "object",
"id": "urn:jsonschema:de:foo:bar:User",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"description": { "type": "string", "input": "textarea" }
}
}
I think this is similar to #JsonDescription or the JSR 303 Annotations. I'm a bit lost if this is possible at all and if so which way i have to implement it. So if anyone could give me a hint where to look at it would be much appreciated!

The mbknor-jackson-jsonSchema package converts java POJOs to json schema. It has #JsonPropertyDescription annotation which could be used to customize schema.
Note that it only supports till draft 4 of json schema, till now.

Related

Custom Gson serializer with fields that are unknown at runtime

I'm attempting to do custom Gson serialization to create a Json object to send to a service except their are some fields that are not known at runtime.
The json I wish to create should look something like this:
{
"type": "configuration/entityTypes/HCP",
"attributes": {
"FirstName": [
{
"type": "configuration/entityTypes/HCP/attributes/FirstName",
"value": "Michael"
}
]
},
"crosswalks": [
{
"type": "configuration/sources/AMA",
"value": "10000012"
}
]
}
I am able to successfully create this json using Gson, but the issue is that I have thousands of fields that could be under the attributes object, in this example there is only the FirstName but if I was doing a create there would be as many attributes as that person, place or thing had associated with them.
Because currently I am able to create this using Gson by having 4 different classes:
Type
Attributes
FirstName
Crosswalks
But I want to be able to have FirstName, LastName, MiddleName, etc. all underneath the attributes object without creating an individual java class for all of them. The json would look like this in that case:
{
"type": "configuration/entityTypes/HCP",
"attributes": {
"FirstName": [
{
"type": "configuration/entityTypes/HCP/attributes/FirstName",
"value": "Doe"
}
],
"LastName": [
{
"type": "configuration/entityTypes/HCP/attributes/LastName",
"value": "John"
}
],
"MiddleName": [
{
"type": "configuration/entityTypes/HCP/attributes/MiddleName",
"value": "Michael"
}
]
},
"crosswalks": [
{
"type": "configuration/sources/AMA",
"value": "10000012"
}
]
}
Is there a way to use Gson to create the attributes object without creating java objects for all of the different attributes I have?
You can use Map<String, Object> where Object will be an one-element-array. See, for example, below model:
class Attributes {
private Map<String, Object> attributes;
// getters, setters
}
class Type {
private final String type;
private final String value;
public Type(String type, String value) {
this.type = type;
this.value = value;
}
// getters
}
Now, let's build attributes manually:
import com.google.gson.Gson;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class GsonApp {
public static void main(String[] args) {
Map<String, Object> map = new HashMap<>();
map.put("FirstName", Collections.singletonList(new Type("url/FirstName", "Rick")));
map.put("LastName", Collections.singletonList(new Type("url/LastName", "Pickle")));
Attributes attributes = new Attributes();
attributes.setAttributes(map);
String json = new Gson().newBuilder().setPrettyPrinting().create().toJson(attributes);
System.out.println(json);
}
}
Above code prints:
{
"attributes": {
"FirstName": [
{
"type": "url/FirstName",
"value": "Rick"
}
],
"LastName": [
{
"type": "url/LastName",
"value": "Pickle"
}
]
}
}

Java Jackson deserialize objects of the same name but different class types

I have POJOs that are used as the request and response object in a REST API like so (I know duplicate #JsonProperty isn't syntactically correct, see below):
public class Request {
#JsonProperty("patient")
PatientObjectA patientA;
#JsonProperty("patient")
PatientObjectB patientB;
}
public class PatientObjectA {
#JsonProperty("identifier")
Private Identifier identifier
#JsonProperty("system")
Private String system;
#JsonProperty("value")
Private String value;
}
public class PatientObjectA {
#JsonProperty("identifier")
Private List<Identifier> identifier
#JsonProperty("system")
Private String system;
#JsonProperty("value")
Private String value;
}
There are minor differences in cardinality in that I want to be able to consume i.e the "Patient" object will sometimes be (PatientObjectA in Request class):
"patient": {
"identifier": {
"type": {
"coding": {
"system": "NA",
"code": "Patient"
},
"text": "Patient"
},
"system": "Patient",
"value": "000000000"
}
}
or this case (note the differences in cardinality on the identifier object, where in this case identifier can have one or more items) (PatientBObject in Request class):
"patient": {
"identifier": [{
"type": {
"coding": {
"system": "NA",
"code": "Patient"
},
"text": "Patient"
},
"system": "Patient",
"value": "3018572032"
}]
}
I would like to achieve a functionality where requests are mapped to the correct objects. Is there a way (other than a custom deserializer) where I can map the requests to the appropriate object by type/cardinality? Any insight would be appreciated!
Jackson support this with the #JsonTypeInfo annotation.
I recommend specifying the type info in a property (a json field) and use the full class name (as opposed to a short name) to provide a better guarantee of uniqueness:
#JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, use = JsonTypeInfo.Id.CLASS, property = "jsonType")
public class PatientObjectA {
..
Output A looks like:
"patient": {
"jsonType": "com.company.PatientAObject"
"identifier": {
"type": {
"coding": {
"system": "NA",
"code": "Patient"
},
"text": "Patient"
},
"system": "Patient",
"value": "000000000"
}
}
Output B looks like:
"patient": {
"jsonType": "com.company.PatientBObject"
"identifier": {
"type": {
"coding": {
"system": "NA",
"code": "Patient"
},
"text": "Patient"
},
"system": "Patient",
"value": "000000000"
}
}
Note: Also, check out #JsonRootName, as it will give you the ability to create a 'rooted' json object without having to have that wrapper object you have.
#JsonRootName("Patient")
#JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, use = JsonTypeInfo.Id.CLASS, property = "jsonType")
public class PatientObjectA {
..
.. and ..
#JsonRootName("Patient")
#JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, use = JsonTypeInfo.Id.CLASS, property = "jsonType")
public class PatientObjectB {
..
Related terms to assist with more research:
polymorphism in json
json equivalent of xml namespaces.

minItems=1 and "uniqueItems": true for array type property in mongodb #document

I am using spring data for a REST API. There is a document with following properties
"properties": {
"id": {
"type": "string",
"description": "Object id from the database"
},
"name": {
"type": "string",
"description": "English User name"
},
"continents": {
"type": "array",
"description": "Continents the User exist in",
"minItems": 1,
"items": { "type": "string" },
"uniqueItems": true
}
}
For these properties I am writing a java persistent class as below
#Document(collection = "users")
public class User {
private String id;
private String name;
// what annotation I should I apply here for constraints minItems=1 and "uniqueItems": true ?
private String[] continents;
// getter and setters
}
I want to support "minItems": 1, "uniqueItems": true for continents. Can anyone please help me how to do it in User.java?

How to ignore wrap element when parse json to dto

I have a json like this
{
"135": {
"id": "135",
"name": "My Awesome Washing Machine!",
"powerswitch": {
"available": "true",
"state": "on",
"reachable": "true",
"locked": "false"
},
"reference": {
"id": "4",
"name": "Lave-linge",
"category_id":"2"
}
},
"491": {
"id": "491",
"name": "My Fridge",
"powerswitch": {
"available": "true",
"state": "on",
"reachable": "false",
"locked": "false"
},
"reference": {
"id": "1",
"name": "Réfrigérateur",
"category_id":"1"
}
}
}
And here is my dto:
public class Device {
private String id;
private String name;
private DevicePowerswitch powerswitch;
private DeviceReference reference;
//getter, setter
}
The question is how can I parse json to a list of device.
Note that there is a non-static id value wrapper in this above json.
You'll need to parse the JSON into a JsonNode, and then iterate over the children. The nodes you pull out as a result can then be mapped using an ObjectMapper to Device instances.
ObjectMapper mapper = new ObjectMapper();
final JsonNode jsonNode = mapper.readTree(JSON);
for (JsonNode node : jsonNode)
{
final Device device = mapper.convertValue(node,
Device.class);
// do something with the device
}

How to create schema containing list of objects using Avro?

Does anyone knows how to create Avro schema which contains list of objects of some class?
I want my generated classes to look like below :
class Child {
String name;
}
class Parent {
list<Child> children;
}
For this, I have written part of schema file but do not know how to tell Avro to create list of objects of type Children?
My schema file looks like below :
{
"name": "Parent",
"type":"record",
"fields":[
{
"name":"children",
"type":{
"name":"Child",
"type":"record",
"fields":[
{"name":"name", "type":"string"}
]
}
}
]
}
Now problem is that I can mark field children as either Child type or array but do not know how to mark it as a array of objects of type Child class?
Can anyone please help?
You need to use array type for creating the list.
Following is the updated schema that handles your usecase.
{
"name": "Parent",
"type":"record",
"fields":[
{
"name":"children",
"type":{
"type": "array",
"items":{
"name":"Child",
"type":"record",
"fields":[
{"name":"name", "type":"string"}
]
}
}
}
]
}
I had following class and avro maven plugin generated two classes accordingly :
public class Employees{
String accountNumber;
String address;
List<Account> accountList;
}
public class Account {
String accountNumber;
String id;
}
Avro file format :
{
"type": "record",
"namespace": "com.mypackage",
"name": "AccountEvent",
"fields": [
{
"name": "accountNumber",
"type": "string"
},
{
"name": "address",
"type": "string"
},
{
"name": "accountList",
"type": {
"type": "array",
"items":{
"name": "Account",
"type": "record",
"fields":[
{ "name": "accountNumber",
"type": "string"
},
{ "name": "id",
"type": "string"
}
]
}
}
}
]
}
Array as type
{
"type": "record",
"name": "jamesMedice",
"fields": [{
"name": "columns",
"type": {
"type": "array",
"items": {
"type": "record",
"name": "columnValues",
"fields": [{
"name": "personId",
"type": "string",
"default": "null"
},
{
"name": "email",
"type": "string",
"default": "null"
}
]
}
}
}]
}

Categories