I'm trying to convert below simple JSON to Java Object using com.fasterxml.jackson.core. I have problem with bonusAmount field setter method.
JSON:
{"amount":332.5, "bonusamount":3, "action":"Spend"}
Java class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class GameRequest {
#JsonProperty("amount")
private BigDecimal amount;
#JsonProperty("bonusamount")
private BigDecimal bonusAmount;
#JsonProperty("action")
private String action;
.....
public BigDecimal getBonusAmount() {
return bonusAmount;
}
public void setBonusAmount(BigDecimal bonusAmount) {
this.bonusAmount = bonusAmount;
}
Value of bonusAmount field is NULL when I try to use it but if I change name of setter method from setBonusAmount to setBonusamount then it works. Can someone tell me why??
That is because you have renamed your field using #JsonProperty("bonusamount") that means Jackson searches for a method named setBonusamount (first char toUpperCase, rest stays the same)
Related
Maybe it's simple, but I'm stuck...
I have an app using Spring Boot and springframework.web.client.RestTemplate, so there's Jackson on backseat doing JSON job automatically.
I want to deserialize REST input with JSON like this:
{
"serial_no": 12345678,
"last_dt": [
{
"lp": "2022-04-22T15:00:00"
},
{
"bp": null
},
{
"dp": "2022-04-22T00:00:00"
},
{
"iv": "2022-04-22T00:05:11"
}
]
}
Please, help me to create POJO for this model... If I created following classes (simplified with lombok):
#Data
public class LastDt {
#JsonProperty("lp")
private String lp;
#JsonProperty("bp")
private String bp;
#JsonProperty("dp")
private String dp;
#JsonProperty("iv")
private String iv;
}
#Data
public class Device {
#JsonProperty("serial_no")
private Long serialNo;
#JsonProperty("last_dt")
private List<LastDt> lastDt;
}
deserialization is technically ok - I got an object with serialNo Long value and unfortunatelly list of 4 instances of class LastDt: first instance (lastDt[0]) had field "lp" with value and "bp", "dp", "iv" null; second (lastDt[1]): "bp" with value and "lp", "dp", "iv" null and so on - only one value was set and others are not. That's far from what I want to get. As you can see, there's four pair-like anonymous objects with different key names, so my model is bad, and I know this, but got stuck trying to create other ones... Can anyone help me?
You can use #JsonAlias. The idea is to have a single field in LastDt, with all possible names of the property mapped to that field.
public class LastDt {
#JsonAlias({"lp", "bp", "dp", "iv"})
private String value;
//getter and setters
#Override
public String toString() {
return "LastDt{" +
"value='" + value + '\'' +
'}';
}
}
No changes are required to Device.
And a simple test:
public class Temp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
InputStream dataStream = getTheStream();
Device device = mapper.readValue(dataStream, Device.class);
System.out.println(device);
}
}
You should use #JsonInclude(JsonInclude.Include.NON_NULL) in your class:
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
public class LastDt {
#JsonProperty("lp")
private String lp;
#JsonProperty("bp")
private String bp;
#JsonProperty("dp")
private String dp;
#JsonProperty("iv")
private String iv;
}
The webservice return the following JSON string:
{"errorCode":0,"error":"","status":"OK","data":{"id":"1234A"}}
So to get a class that receives the response in a function like this that performs a post in Retrofit:
Call<UploadImageData> postData(#Header("Cookie") String sessionId, #Body UploadImageModal image);
I'd need to make a class like this;
public class UploadImageData {
private int errorCode;
private String error;
private String status;
}
But I'm lost in how I would have to declare the part that would take "data":{"id":"1234A"}, so it gets the data from there correctly.
How could I do this?
Since data is a nested object within the surrounding json object, you can include it as another class in your UploadImageData class.
public class UploadImageData {
private int errorCode;
private String error;
private String status;
private MyDataClass data;
}
public class MyDataClass {
private String id;
}
DonĀ“t forget setter methods oder make fields public.
I have a nested POJO structure defined something like this,
public class Employee {
private String id;
private Personal personal;
private Official official;
}
public class Personal {
private String fName;
private String lName;
private String address;
}
public class Official {
private boolean active;
private Salary salary;
}
public class Salary {
private double hourly;
private double monthly;
private double yearly;
}
I get updates from a service with dot annotaion on what value changed, for ex,
id change --> id=100
address change --> personal.address=123 Main Street
hourly salary change --> official.salary.hourly=100
This POJO structure could be 3-4 level deeps. I need to look for this incoming change value and update the corresponding value in POJO. What's the best way of doing it?
If you would like to create Java objects that allows you to edit fields. You can specify your object fields with the public/default/protected access modifiers. This will enable you to get and set fields such as personal.address or official.salary.hours
This approach is typically frowned upon as the object is no longer encapsulated and any calling methods are welcome to manipulate the object. If these fields are not encapsulated with getters and setters, your object is no longer a POJO.
public provides access from any anywhere.
default provides access from any package
protected provides access from package or subclass.
public class Employee {
public String id;
public Personal personal;
public Official official;
}
public class Personal {
public String fName;
public String lName;
public String address;
}
Here's a quick approach using reflection to set fields dynamically. It surely isn't and can't be clean. If I were you, I would use a scripting engine for that (assuming it's safe to do so).
private static void setValueAt(Object target, String path, String value)
throws Exception {
String[] fields = path.split("\\.");
if (fields.length > 1) {
setValueAt(readField(target, fields[0]),
path.substring(path.indexOf('.') + 1), value);
return;
}
Field f = target.getClass()
.getDeclaredField(path);
f.setAccessible(true);
f.set(target, parse(value, f.getType())); // cast or convert value first
}
//Example code for converting strings to primitives
private static Object parse(String value, Class<?> type) {
if (String.class.equals(type)) {
return value;
} else if (double.class.equals(type) || Double.class.equals(type)) {
return Long.parseLong(value);
} else if (boolean.class.equals(type) || Boolean.class.equals(type)) {
return Boolean.valueOf(value);
}
return value;// ?
}
private static Object readField(Object from, String field) throws Exception {
Field f = from.getClass()
.getDeclaredField(field);
f.setAccessible(true);
return f.get(from);
}
Just be aware that there's a lot to improve in this code (exception handling, null checks, etc.), although it seems to achieve what you're looking for (split your input on = to call setValueAt()):
Employee e = new Employee();
e.setOfficial(new Official());
e.setPersonal(new Personal());
e.getOfficial().setSalary(new Salary());
ObjectMapper mapper = new ObjectMapper();
setValueAt(e, "id", "123");
// {"id":"123","personal":{},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "personal.address", "123 Main Street");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "official.salary.hourly", "100");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":100.0,"monthly":0.0,"yearly":0.0}}}
I am working on this test class and trying to change the response expected to a bean response as I have changed the requests to bean requests.
private void assertXmlResponse(Document xmlResponse, int Elements,
String Message, String Code, String name,
String Funds)
{
Node topLevelElement = xmlResponse.getFirstChild();
NodeList childElements = topLevelElement.getChildNodes();
assertEquals("result", topLevelElement.getNodeName());
assertEquals(Elements, childElements.getLength());
assertEquals("message", childElements.item(0).getNodeName());
assertEquals(Message, childElements.item(0).getTextContent());
assertEquals("code", childElements.item(1).getNodeName());
assertEquals(Code, childElements.item(1).getTextContent());
assertEquals("name", childElements.item(2).getNodeName());
assertEquals(name, childElements.item(2).getTextContent());
}
Please can someone point me in the right direction or even let me know if it's possible?
Thanks
You are about to make POJO(Plain Old Java Objects).
public Class A{
private int Elements;
private String Message;
private String Funds;
private String code;
private String name;
//getters and setters
}
Keep the reference of this class as Parameter in your method.
Use the getters for accessing the value in your method.
I am working with a legacy database that makes frequent use of blobs of JSON stored as text. I am trying to write some JPA classes that will hide this implementation detail, make it easier to work with the database, and allow us to refactor the database schema in the future. My current approach is:
class MyTableObject{
#Lob
#Column(name = "stuff")
private String jsonString;
public List<Stuff> getStuff(){
return jsonToStuff(jsonString);
}
public setStuff(List<Stuff> stuff){
jsonString = stuffToJsonString(stuff);
}
}
Here, the representation is always as a JSON string in both the the database and the Object and although it works (so far) , it is pretty inefficient as the JSON has to be parsed every time the state of the object is modified. I appreciate that I could improve performance of my current solution by cacheing the Stuff objects in memory, but I would still have to serialize them to JSON every time the setter is called and ensure that the 2 representations of the state (Objects and JSON) were always in sync. What I would like to be able to do is to tell the framework to convert my field on the way in and out, something like:
class MyTableObject{
private List<Stuff> stuff;
#Lob
#Column(name = "stuff")
public String getStuffAsJsonString(){
return stuffToJsonString(stuff);
}
#Column(name = "stuff")
public setStuffFromJsonString(String jsonString){
stuff = stuffFromJsonString(jsonString);
}
}
However, as far as I know annotations are only valid on the getter. Can I achieve something like the above - with one representation in the Object and a different representation in the database? I am new to JPA so I could easily be missing something obvious.
Many thanks in advance
You can just annotate the getter. The corresponding setter will be used by JPA when the object is loaded from the database.
I would use a protected property that is only for JPA and a public accessor for the clients.
The public accessor converts the json string to the List of stuffs when it needs it.
In the same way the property accessor methods for JPA converts the list of stuff to the json string if it is needed.
class MyTableObject {
private String jsonStuff;
private List<Stuff> stuff;
#Lob
#Column(name = "stuff")
protected String getJsonStuff(){
if(jsonStuff == null){
jsonStuff = stuffToJsonString(stuff);
}
return jsonStuff;
}
protected void setJsonStuff(String jsonString){
if(jsonString != null && jsonString.equals(this.jsonStuff)){
// the new string is equal to the old one. No need to re-convert.
return;
}
this.jsonStuff = jsonString;
// jsonStuff changed we have to re-convert json to list
// thus we set stuff to null
stuff = null;
}
public List<Stuff> getStuff(){
if(stuff == null){
stuff = stuffFromJsonString(jsonStuff);
}
return Collections.unmodifiableList(stuff);
}
public void setStuff(List<String> stuff){
if(suffListNotChanged(stuff)){
// the new stuff list is equal to the old one. No need to rebuild json.
return;
}
this.stuff = new ArrayList<String>(stuff);
// the stuff list changed
// thus the jsonStuff string must be rebuild
this.jsonStuff = null;
}
private boolean suffListNotChanged(List<Stuff> stuffList){
...
}
private String stuffToJsonString(List<Stuff> stuffList){
if(stuffList == null){
....
}
}
private List<Stuff> stuffFromJsonString(String stuff){
if(stuff == null){
....
}
}
}
It's not exactly that the annotations are only valid on the getter. A single annotation takes care of the getter and the setter: you don't doubly-annotate.
So, you've basically figured it out already. Remove the extra #Column(name = "stuff") on the setter and you're off to the races.
class MyTableObject {
private List<Stuff> stuff;
#Lob
#Column(name = "stuff")
public String getStuffAsJsonString(){
return stuffToJsonString(stuff);
}
public setStuffFromJsonString(String jsonString){
stuff = stuffFromJsonString(jsonString);
}
}
You don't even to worry for which of the getter/setter should be annotated. The below code should be all set:
class MyTableObject{
#Lob
#Column(name = "stuff")
private List<Stuff> stuffAsJsonString;
public String getStuffAsJsonString(){
return stuffToJsonString(stuff);
}
public setStuffFromJsonString(String jsonString){
stuff = stuffFromJsonString(jsonString);
}
}