I am trying to map a JSON structure to a specific POJO that doesn't really match the JSOM, here is a simple example:
JSON
{
"strA": "MyStr",
"Street": "1st Lane",
"Number": "123"
}
POJO
#JsonIgnoreProperties(ignoreUnknown = true)
public class ClassA {
#JsonProperty("strA")
private String strA;
private Address address;
//Constructor, getter,setter
#JsonRootName("Address")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Address {
private String address;
public Address() {
}
public String getAddress() {
return address;
}
#JsonAnySetter
public void setAddress(#JsonProperty("Street") String street, #JsonProperty("Number")String number) {
this.address = number + " " + street;
}
}
Now, Address is properly created from the sample JSON (only made it work with the JsonAnySetter unfortunately), but I can't get ClassA to be created properly.
I've tried annotating the Address property of it, but to no avail.
How can I achieve this in a "simple" way? This is important as this example is simple, but my real use cases involves several composed classes that need information from the JSON root + from complex JSON elements with different names.
Thank you for your time.
Related
In my Spring project I have several objects that should be serialized to a specific JSON format.
public class Person {
private Integer id;
private String name;
private String height;
private Address address;
}
and
public class Address {
private String street;
private String city;
private String phone;
}
Let assume that Person.height and Address.phone should not appear in the JSON.
The resulting JSON should look like
{
"attributes": ["id", "name", "street", "city"],
"values": [12345, "Mr. Smith", "Main street", "Chicago"]
}
I can create create a standard JSON with an ObjectMapper and some annotations like #JsonProperty and #JsonUnwrapped where I disable some SerializationFeatures. But at the moment I'm not able to create such a JSON.
Is there an easy way to create this JSON? And how would the way back (deserialization) look like?
There are good reasons Jackson doesn't serializes maps in this format. It's less readable and also harder to deserialize properly.
But if you just create another POJO it's very easy to achieve what you want to do:
public class AttributeList {
public static AttributeList from(Object o) {
return from(new ObjectMapper().convertValue(o, new TypeReference<Map<String, Object>>() {}));
}
public static AttributeList from(Map<String, Object> attributes) {
return new AttributeList(attributes);
}
private final List<String> attributes;
private final List<Object> values;
private AttributeList(Map<String, Object> o) {
attributes = new ArrayList<>(o.keySet());
values = new ArrayList<>(o.values());
}
}
I'm trying to map two fields from Java POJO to one json field;
public class Person {
private String firstName;
//this two fields should be in separate json property (object)
private String street;
private String streetNo;
...
//getters and setters
}
And I want to get response something like this:
{
firstName: "Peter",
address: {
street: "Square nine",
streetNumber: "12"
}
}
You should implement then another POJO Address and add address field to your Person POJO
public class Person {
private String firstName;
private Address address = new Address();
...
//getters and setters
}
// another POJO
public class Address {
private String street;
private String streetNo;
//getters and setters
}
I am having an object as below
public class Employee{
String firstName;
String lastName;
String address;
String phoneNumber;
List<Contacts> Contacts;
}
public class Contacts{
String name;
String Address;
String phoneNumber;
}
Now considering the Employee object is set with values inside the application and when I try to convert the object say with name empObject(which has all values) into JSON as below
ObjectMapper mapper= new ObjectMapper();
String employeeObjToJSON =mapper.writeValueAsString(empObject);
System.out.println("JSON employee Object" +employeeObjToJSON)
I get the values
{"firstName":"Sawyer","lastName":"Ford","phone":"4555454553", "address": "SNJFJJFJ", "contacts":[{"phoneNumber": "122333"},{"phoneNumber":"122222"}]}
Only the phone number is printed for the Inner Object. How should I get the complete object in JSON
Your class structure seems a little off. Why would the Employee class have a list of contacts as String, rather than a list of Contact objects?
I would suggest you change your Employee class like this:
public class Employee {
String firstName;
String lastName;
String address;
String phoneNumber;
List<Contact> contacts;
}
public class Contact {
String name;
String address;
String phoneNumber;
}
Using this class structure you should not have any problems mapping them to JSON using ObjectMapper.
Edit:
Regarding the null fields not being displayed, as I wrote in the comment, by default Jackson should serialise them and you should see them in the response.
If that is not the case, it might be that this serialisation feature has been overridden somewhere... try setting the following config to your object mapper and see if it works: mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS).
Alternatively, you can also use the Jackson annotation #JsonInclude(JsonInclude.Include.ALWAYS) on your Employee class and Contact class like ibenjelloun suggested in his/her answer.
Did you try the following class annotation :
#JsonInclude(JsonInclude.Include.ALWAYS)
According to the javadoc, it's the default value, maybe it is overwritten somewhere in your code ?
I'm using Spring Boot and Hibernate. I'm trying to create a DTO which will act as a #ModelAttribute binding when I post information from a form to my endpoint in my controller.
My information is coming in like this:
{
"userId": 1239992,
"name": "Tanya",
"phones":[
{"android": 212882939},
{"iPhone": 12321321312},
... perhaps variable amounts more
]
}
My thought is to capture it as such in a DTO:
public class ContactDTO {
private int userId;
private String name;
private Map<String, Int> phones; // unsure of this. This would
//hoping to produce a collection of phone type -> phone number
// getters and setters
}
And then in my controller:
#PostMapping(path = "/newContact")
public #ResponseBody ContactDTO createNewContact(#ModelAttribute ContactDTO newContact) {
Map<String, int> allPhones = newContact.getPhones();
//do stuff with the phones
}
However, I have no idea if that actually binds. How do I go about collecting a variable amount of the same type of field where the amounts are set in the client side before being POST'ed back?
There are a lot of different ways to acheive this but the simplest way IMHO is the POJO way. As per your JSON your phones key is an array of objects.
Simply define another class Contact and use it as a composition in your ContactDTO.
Contact class
public class Contact {
private String phoneType; //This better be an enum
private String phoneNumber;
//setters and getters
}
You can now have a List<Contact> in your ContactDTO like so
public class ContactDTO {
private int userId;
private String name;
private List<Contact> phones; //Now you can have a variable number of phones in your JSON
//setters and getters
}
It would be much better if you could slightly change the format of the incoming JSON to:
{
"userId": 1239992,
"name": "Tanya",
"phones": {
"android": 212882939,
"iPhone": 12321321312
}
}
Then you can keep using the following POJO class (with the desired map):
class ContactDTO {
private int userId;
private String name;
private Map<String, Long> phones;
// getters and setters
}
Note: you need a Long to represent 12321321312, because it's too large to fit in an Integer.
Your json actually by default maps to
public class ContactDTO {
private int userId;
private String name;
private List<Map<String, Integer>> phones;
}
There are lots of ways you can approach this if you want single map
Custom deserializer
Pojo for phones, but your map would actually be a list like in Abdullah Khan answer
Custom getter/setter (probably the easiest to implement if you want to keep Map<String, Int> and preserve json format).
Here is demo:
public static class ContactDTO {
private int userId;
private String name;
private Map<String, Integer> phones; // USE Long and not Integer as value
// getters/setters
//for deserialization
#JsonProperty("phones")
public void setPhonesFromLIist(List<Map<String,Int>> phones) {
this.phones = new HashMap<>();
phones.forEach(phone-> this.phones.putAll(phone));
}
//for serialization
#JsonProperty("phones")
public Set setPhonesAsLIist() {
return phones.entrySet();
}
}
I have a question regarding a web-application I'm building where I have a REST service receiving a json string.
The Json string is something like:
{
"string" : "value",
"string" : "value",
"object" : {
"string" : "value",
"string" : "value",
....
}
}
I'm using resteasy to parse the json string which uses jackson underneath. I have a jaxb annotated class and I want to parse the "object" entirely into a String variable. The reason I want to do this is to be able to parse the json later using the correct parser (it depends on the application that sends the request so it is impossible to know in advance).
My jaxb annotated class looks like this:
#XmlRootElement
#XmlAccessorType(XmlAccessType.PROPERTY)
public class Test{
#XmlElement(type = String.class)
private String object;
//getter and setter
...
}
When I execute the rest call and let jackson parse this code I get an
Can not deserialize instance of java.lang.String out of START_OBJECT token
error. So actually I'm trying to parse a piece of a json string, which is a json object, into a String. I can't seem to find someone with a similar problem.
Thanks in advance for any response.
java.lang.String out of START_OBJECT token
this means that expected character after "object" is quotes ", but not brackets {.
Expected json
"object" : "my object"
Actual json
"object" : { ...
=======
If you want parse json like in your example, then change your class. E.g.
#XmlRootElement
#XmlAccessorType(XmlAccessType.PROPERTY)
public class Test{
#XmlElement
private InnerTest object;
//getter and setter
...
}
#XmlAccessorType(XmlAccessType.PROPERTY)
public class InnerTest{
#XmlElement
private String string;
//getter and setter
...
}
If I understand this question you just want a mechnanism, that converts a Java-Object into a JSON-String and the other way.
I needed this as well, while I was using a WebSocket Client-Server communication where a JSON String has been passed around.
For this I used GSON (see GSON). There you got the possibility to create a complete JSON-String.
Here some example:
// Converts a object into a JSON-String
public String convertMyClassObjectToJsonFormat() {
MyClass myObject = new MyClass();
Gson gson = new Gson();
return gson.toJson(myObject);
}
//Converts a JSON-String into a Java-Class-Object
public MyClass convertJsonToMyClassObject(
CharBuffer jsonMessage) {
Gson gson = new Gson();
return gson.fromJson(jsonMessage.toString(),
MyClass.class);
}
What you need is, that you your Class-Attributes-setter and JSON-Attribute-names are equivalent. E.g.
{
"info":[
{
"name": "Adam",
"address": "Park Street"
}
]
}
Your Class should look like this:
public class Info{
private String name;
private String address;
public void setName(String name){
this.name = name;
}
public void setAddress(String address){
this.address = address;
}
}
#KwintenP Try using the json smart library.
You can then simply retrieve the JSON object first using:
JSONObject test = (JSONObject) JSONValue.parse(yourJSONObject);
String TestString = test.toString();
What's more, you can retrieve a specific object inside a JSON object may it be another object, an array and convert it to a String or manipulate the way you want.
you also can do something like this ;
public class LeaderboardView
{
#NotEmpty
#JsonProperty
private String appId;
#NotEmpty
#JsonProperty
private String userId;
#JsonProperty
private String name = "";
#JsonProperty
private String imagePath = "";
#NotEmpty
#JsonIgnore
private String rank = "";
#NotEmpty
#JsonProperty
private String score;
public LeaderboardView()
{
// Jackson deserialization
}
}