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"
}
]
}
}
Related
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.
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.
This is slight extension of my previous question. So based on dambros' answer, the json now looks like:
"Foo": {
"title": {
"type": "title",
"value": "...",
"variable": "..."
},
"message": {
"type": "message",
"value": "...",
"variable": "..."
}
}
But what I really want is:
"Foo": [
{
{
"type": "title",
"value": "...",
"variable": "..."
},
{
"type": "message",
"value": "...",
"variable": "..."
}
}
]
Is there any way to write the Foo field as an array and also not display the variable names as fields (i.e remove "title" :).
That is not valid JSON, however this is:
{
"Foo": [
{
"type": "title",
"value": "...",
"variable": "..."
},
{
"type": "message",
"value": "...",
"variable": "..."
}
]
}
This is a JSON object with a single field named Foo that is an array of objects.
You should read the JSON spec.
Alternatively, if you have a List<Foo>, you can serialize the list directly, giving you a JSON array as the root, instead of a JSON object as the root:
[
{
"type": "title",
"value": "...",
"variable": "..."
},
{
"type": "message",
"value": "...",
"variable": "..."
}
]
It seems that what you're trying to accomplish is to represent your java object in a way that you can send the object type and fields. Under that assumption, I'd try to get away from manual serialization. Just create a DTO with the format that you need, that you can populate with the domain objects you have. This would be an example:
public class FooSerialization {
public static class Foo {
private String title;
private String message;
}
public static class Foo2 {
private String value;
private String variable;
}
public static class ClassDTO {
private String type;
private List<FieldDTO> fields;
}
public static class FieldDTO {
private String type;
private String value;
private String fieldName;
}
public static void main(String[] args) throws JsonProcessingException {
Foo2 foo2 = new Foo2();
foo2.setValue("valueMessage");
foo2.setVariable("variableMessage");
Foo foo = new Foo();
foo.setMessage("messageMessage");
foo.setTitle("titleMessage");
ObjectMapper mapper = new ObjectMapper();
List<ClassDTO> dtos = new ArrayList<ClassDTO>();
dtos.add(convert(foo));
dtos.add(convert(foo));
System.out.println(mapper.writeValueAsString(dtos));
}
private static ClassDTO convert(Object obj) {
ClassDTO dto = new ClassDTO();
dto.setType(obj.getClass().getSimpleName());
List<FieldDTO> fieldDTOs = new ArrayList<FieldDTO>();
dto.setFields(fieldDTOs);
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
FieldDTO fieldDto = new FieldDTO();
try {
fieldDto.setFieldName(field.getName());
fieldDto.setValue(field.get(obj).toString());
fieldDto.setType(field.getType().getSimpleName());
fieldDTOs.add(fieldDto);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return dto;
}
}
Getters and Setters are omitted for simplicity. This basically converts from Foo or Foo2 to certain ClassDTO, that contains type and a list of FieldDTOs that have the field details.
Output looks like this:
[
{
"type": "Foo",
"fields": [
{
"fieldName": "title",
"type": "String",
"value": "titleMessage"
},
{
"fieldName": "message",
"type": "String",
"value": "messageMessage"
}
]
},
{
"type": "Foo2",
"fields": [
{
"fieldName": "value",
"type": "String",
"value": "valueMessage"
},
{
"fieldName": "variable",
"type": "String",
"value": "variableMessage"
}
]
}
]
It looks to me that you can solve lots of problems if you can use something like this:
#JsonFormat(shape=JsonFormat.Shape.ARRAY)
public static class Foo {
#JsonProperty public Foo1 title;
#JsonProperty public Foo2 message;
}
#JsonTypeInfo(use= JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
#JsonSubTypes({#JsonSubTypes.Type(value = Foo1.class, name = "title"),
#JsonSubTypes.Type(value = Foo2.class, name = "message")})
public static class FooParent{
#JsonProperty private String value;
#JsonProperty private String variable;
}
public static class Foo1 extends FooParent{}
public static class Foo2 extends FooParent{}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Foo foo = new Foo();
foo.title = new Foo1();
foo.message = new Foo2();
String serialized = mapper.writeValueAsString(foo);
System.out.println(serialized);
}
Result is:
[
{"type":"title","value":null,"variable":null},
{"type":"message","value":null,"variable":null}
]
Read following blog json in java
This post is a little bit old but still i want to answer you Question
Step 1: Create a pojo class of your data.
Step 2: now create a object using json.
Foo foo = null;
ObjectMapper mapper = new ObjectMapper();
try{
foo = mapper.readValue(newFile("/home/sumit/foo.json"),Foo.class);
} catch (JsonGenerationException e){
e.printStackTrace();
}
For further reference you can refer following link
Thanks
Ok I have some JSON I get from a service that I am trying to create a POJO for. My JSON looks similar to:
[
{
"id": "someid",
"values": {
"value1": {
"id": "someid"
}
}
},
{
"id": "391055",
"values": {
"value1": {
"id": "someid"
},
"value2": {
"id": "someid"
}
}
},
{
"id": "someid",
"values": {
"value1": {
"id": "someid"
}
}
}
]
and my POJO is like:
#JsonPropertyOrder({
"id",
"values"})
public class ValueTranslation {
#JsonProperty("id")
private String id;
#JsonProperty("values")
private Map<String, String> values;
public ValueTranslation(String id, Map<String, String> values) {
this.id = id;
this.values = values;
}
}
After I figure this out I will work on getting the inner string changed to some object, but I have no idea what is going wrong in the mapping. I have read several JACKSON tutorials and googled, but have found nothing to help me.
I have a json in a specific form that I have to deserialize.
In order to do that, I thought at my very best library Gson, but I'm facing a problem here because I have some key that are dynamic.
I think you will understand with a good exemple.
Here is the json :
{
"institution1": {
"_id": "51cc7bdc544ddb3f94000002",
"announce": { },
"city": "Melun",
"coordinates": [
2.65106,
48.528976
],
"country": "France",
"created_at": "2013-06-27T17:52:28Z",
"name": "italien",
"state": "Seine et Marne",
"street": "Avenue Albert Moreau",
"updated_at": "2013-06-27T17:52:28Z"
},
"institution2": {
"_id": "51d1dfa8544ddb9157000001",
"announce": {
"announce1": {
"_id": "51d1e036544ddb9157000002",
"created_at": "2013-07-01T20:02:35Z",
"description": "description formule 1",
"institution_id": "51d1dfa8544ddb9157000001",
"title": "formule dejeune",
"type": "restoration",
"updated_at": "2013-07-01T20:02:35Z"
},
"announce2": {
"_id": "51d1e074544ddb9157000003",
"created_at": "2013-07-01T20:03:08Z",
"description": "description formule soir",
"institution_id": "51d1dfa8544ddb9157000001",
"title": "formule soiree",
"type": "restoration",
"updated_at": "2013-07-01T20:03:08Z"
}
},
"city": "Melun",
"coordinates": [
2.65106,
48.528976
],
"country": "France",
"created_at": "2013-07-01T19:59:36Z",
"name": "restaurant francais chez pierre",
"state": "Seine et Marne",
"street": "Avenue Albert Moreau",
"updated_at": "2013-07-01T19:59:36Z"
}
}
You can go here for a better view.
So, I created a class to do that, JsonModel.java
public class JsonModel
{
public HashMap<String, Institution> entries;
public static class Institution
{
public String _id;
public HashMap<String, Announce> announce;
public String city;
public String country;
public List<Double> coordinates;
public String created_at;
public String name;
public String state;
public String street;
public String updated_at;
}
public static class Announce
{
public String _id;
public String created_at;
public String description;
public String institution_id;
public String title;
public String type;
public String updated_at;
}
}
And then, I asked Gson to deserialize that with the following code :
JsonModel data = new Gson().fromJson(json, JsonModel.class);
As data is null I presume that it is not working the way I expected...
And I thought about using HashMap because I don't know in advance the key like institution1, institution2, ...
What do you think ? Can I do that ?
And please don't tell me to use bracket, I just dream to have those !
Thank you in advance !
EDIT :
I was able to make this thing work by adding a root object
{
"root":{ ..the json.. }
}
AND changing
public HashMap<String, Institution> entries;
by
public HashMap<String, Institution> root;
So, the problem is gson need to recognise the first element but in fact I will not be able to modify the json, is there a way to get it done differently ?
The use of a Map is perfect, but you can't use your JsonModel class, because with that class you're assuming that in your JSON you have an object that contains a field called "entries" that in turn represents a map, like this:
{
"entries": { the map here... }
}
And you don't have that, but your JSON represents directly a map (not an object with a field called entries that represents a map!). Namely, you have only this:
{ the map here... }
So you need to parse it accordingly, removing the class JsonModel and using directly a Map to deserialize...
You need to use a TypeToken to get the type of your Map, like this:
Type mapType = new TypeToken<Map<String, Institution>>() {}.getType();
And then use the method .fromJson() with that type, like this:
Map<String, Institution> map = gson.fromJson(json, mapType);