Single java field gets mapped to two JSON fields with jackson - java

There is a isCase field in POJO that gets mapped to case and is_case at the same time(which is not what expected).
Removing #JsonProperty annotation gets rid of is_case field in json, but is_case is what it's supposed to be.
Putting #JsonIgnore on isCase doesn't get rid of case in response json.
Renaming isCase to is_case does get rid of case in response json, but that doesn't seem too right.
Why would Jackson ever map single java field to two fields?
A POJO is declared like this:
public class CreateRuleResponse {
#JsonProperty(value = "rule_name", required = true)
private String name;
#JsonProperty("rule_num")
private String ruleNum;
#JsonProperty(value = "rule_category")
private RuleCategory ruleCategory;
#JsonProperty(value = "rule_status")
private RuleStatus ruleStatus;
#JsonProperty(value = "rule_channel_type")
private String ruleChannelType;
#JsonProperty("action")
private RuleAction ruleAction;
#JsonProperty("is_case")
private Boolean isCase;
public CreateRuleResponse() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRuleNum() {
return ruleNum;
}
public void setRuleNum(String ruleNum) {
this.ruleNum = ruleNum;
}
public RuleCategory getRuleCategory() {
return ruleCategory;
}
public void setRuleCategory(RuleCategory ruleCategory) {
this.ruleCategory = ruleCategory;
}
public RuleStatus getRuleStatus() {
return ruleStatus;
}
public void setRuleStatus(RuleStatus ruleStatus) {
this.ruleStatus = ruleStatus;
}
public String getRuleChannelType() {
return ruleChannelType;
}
public void setRuleChannelType(String ruleChannelType) {
this.ruleChannelType = ruleChannelType;
}
public RuleAction getRuleAction() {
return ruleAction;
}
public void setRuleAction(RuleAction ruleAction) {
this.ruleAction = ruleAction;
}
public Boolean getCase() {
return isCase;
}
public void setCase(Boolean aCase) {
isCase = aCase;
}
}

It's mapping the variables and also the getter methods.

Rename this getter method from getCase() to getIsCase() (following the convention). Jackson is treating it as 2 different fields because the getter and the field name do not match.

Related

Expected END_ELEMENT, got event of type 1 (through reference chain: ...->java.util.ArrayList[0])

I'm using XMLMapper to deserialize AIML code (mostly the same as XML) and got this problem when I mix text and tags under the same tag. Example:
<set name="setVar">
<srai>FUNCTION1</srai>
<srai>FUNCTION2<star index="1"/></srai>
</set>
My java classes definition are:
#JacksonXmlRootElement(localName = "set")
public class Set {
#JacksonXmlProperty(isAttribute = true, localName = "name")
public String name;
#JacksonXmlElementWrapper(useWrapping = false)
#JacksonXmlProperty(localName = "srai")
public List<Srai> srais;
public Set() {
}
public Set(String name, List<Srai> srais) {
this.name = name;
this.srais = srais;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Srai> getSrais() {
return srais;
}
public void setSrais(List<Srai> srais) {
this.srais = srais;
}
}
#JacksonXmlRootElement(localName = "srai")
public class Srai {
#JacksonXmlElementWrapper(useWrapping = false)
#JacksonXmlProperty(localName = "star")
public List<Star> stars;
#JacksonXmlText
public String text;
public Srai() {}
public Srai(String text, List<Star> stars) {
this.text = text;
this.stars = stars;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public List<Star> getStars() {
return stars;
}
public void setStars(List<Star> stars) {
this.stars = stars;
}
}
#JacksonXmlRootElement(localName = "star")
public class Star {
#JacksonXmlProperty(isAttribute = true)
public int index;
public Star() {
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
If I try to deserialize code in which there are only text or only stars into the srai, everything works perfect, the problem appears when I mix text and tags.
I finally managed to solve it upgrading my jackson-databind, jackson-core, jackson-annotation and jackson-dataformat-xml to the version 2.12.1 as tnci suggested here.
To do this, just change their version into the pom.xml to 2.12.1 or later versions.
Then I created a new property into the star class:
#JacksonXmlText
public String text;
This way, when there is text before or between xml tags, it will be saved in this property on a star object. If the text is after all xml tags, there will appear this problem:
Unexpected end-of-input when trying read value of type `**root-agent-class**`
So the problem persists but now it's much better since we can read some text+tags code.

Handle different types for some fields while serializing and deserializing with Jackson

I am using Jackson 2.
When reading from remote service I obtain a JSON object like this:
{
"country":"1",
"complex":{
"link":"...",
"value":"..."
},
"test":""
}
so I have created the related POJOs for the purpose:
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"link",
"value"
})
public class Complex {
#JsonProperty("link")
private String link;
#JsonProperty("value")
private String value;
#JsonProperty("link")
public String getLink() {
return link;
}
#JsonProperty("link")
public void setLink(String link) {
this.link = link;
}
#JsonProperty("value")
public String getValue() {
return value;
}
#JsonProperty("value")
public void setValue(String value) {
this.value = value;
}
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"country",
"complex",
"test"
})
public class Resource {
#JsonProperty("country")
private String country;
#JsonProperty("complex")
private Complex complex;
#JsonProperty("test")
private String test;
#JsonProperty("country")
public String getCountry() {
return country;
}
#JsonProperty("country")
public void setCountry(String country) {
this.country = country;
}
#JsonProperty("complex")
public Complex getComplex() {
return complex;
}
#JsonProperty("complex")
public void setComplex(Complex complex) {
this.complex = complex;
}
#JsonProperty("test")
public String getTest() {
return test;
}
#JsonProperty("test")
public void setTest(String test) {
this.test = test;
}
}
so that I'm able to do:
Resource res = MAPPER.readValue(response.readEntity(String.class), Resource.class);
My problem is that, when executing POST requests, I need to send a different object, that is:
{
"country":"1",
"complex": "value",
"test":""
}
so where all "complex" objects must be simply strings.
Any idea about how to handle this situation?
I have tried to create a JsonDeserializer class:
public class ComplexValueDeserializer extends JsonDeserializer<Object> {
#Override
public Object deserialize(final JsonParser parser, final DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
final JsonToken jsonToken = parser.getCurrentToken();
if (jsonToken == null
|| (jsonToken == JsonToken.START_OBJECT && parser.getValueAsString().equals("{}"))) {
return "";
}
return null;
}
}
and add it to:
#JsonProperty("complex")
#JsonDeserialize(using = ComplexValueDeserializer.class)
private Complex complex;
but I get java.lang.IllegalArgumentException: argument type mismatch error.
Thanks!
On your Complex Object type you can define a toString() method and then Annotate it with #JsonValue. This will indicate to Jackson that the returned result will be the value serialized for that object. You can them implement whatever logic you need there to represent the Complex type in the way you want. e.g.:
#JsonValue
public String toString() {
return value;
}
Why do you need
"complex":{
"link":"...",
"value":"..."
},
for api documentation?

Same named fields with different types in gson parsing

I have a RequestModel defined as
public class RequestModel
{
public class Footage
{
public String date;
public String retrievedAt;
public String videoFileName;
public String availableUntil;
public boolean isAvailable;
}
public class People
{
public String first;
public String last;
}
public static final int USER_BLOCKED = 0;
public static final int USER_ACTIVE = 1;
public static final int USER_WAIT_PIN = 2;
public String _id;
public String status;
public String submittedAt;
public Footage footage;
public People teacher;
public People student;
public ArrayList<MessageModel> messages = new ArrayList<MessageModel>();
public boolean isExpanded = false;
public RequestModel()
{
}
My MessageModel is defined as
public class MessageModel
{
public String _id;
public String statusMessage;
public String submittedAt;
public RequestModel request;
public String status;
public String timestamp;
public boolean isExpanded = false;
public MessageModel()
{
}
}
I have an api call that pulls a single "RequestModel" item. However the messages list in that api call has "request" as a String instead of "RequestModel" object.
Is there any way i can make it parse as a different name or omit it entirely to bypass exceptions causing because of different types.
Use the annotation #SerializedName("") before declaring member to give it a substitute name
ex,
if you json looks like this
{
name:"",
age:0,
items:[...]
}
but your model class have the fields,
class User{
String name;
int age;
Data userItems[];
}
The field userItems in model is named items in the json,
you need to use that annotation on the field:
class User{
String name;
int age;
#SerializedName("items")
Data userItems[];
}
this way GSON will map items to userItems.

Json response value is not setting to the Bean class

When I do rest class I have received below response.
Response:
{
"_index": "a_index",
"total":9,
"_type": "e",
"_id": "BSKnamtd_8-egMNvh",
"_data": 2.076404564,
"_secure": {
"email": "abcd1#gmail.com"
}
}
To set this response. I have created pojo class as shown blow.
public class data implements Serializable {
private static final long serialVersionUID = 644188100766481108L;
private String _index;
private Integer total;
private String _type;
private String _id;
private Double _data;
private Source _secure;
public String getIndex() {
return _index;
}
public void setIndex(String _index) {
this._index = _index;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
public String getType() {
return _type;
}
public void setType(String _type) {
this._type = _type;
}
public String getId() {
return _id;
}
public void setId(String _id) {
this._id = _id;
}
public Double getData() {
return _data;
}
public void setData(Double _data) {
this._data = _data;
}
public Source getSecure() {
return _secure;
}
public void setSecure(Source _secure) {
this._secure = _secure;
}
}
When I hit the restClient call, I am getting only "total" value remaining values getting as null. "total" variable not having underscore("") remaining variables have "" so that I am facing Issue..?
Please help how to solve this issue.
The Json object is
...
"_index": "a_index",
"total":9,
...
And the properties for those two properties are:
public void setIndex(String _index) {
this._index = _index;
}
public void setTotal(Integer total) {
this.total = total;
}
As you can see, the java property for the Json _index property is index (setIndex).
index is different from _index, so when the Json object is mapped it gets null, because it can't find the property _index.
In the other hand you have that the java property for the Json total property is total (setTotal).
In this case the properties in Json and Java have the same name, so it gets the value loaded.
Java class property name is invisible to object mapper (it is private). What matters in your case is getter/setter name. It is used to map JSON object property name to Java class (POJO).
You have two options I can think of. Dirty one is just to change setter names to set_index (), set_type(), etc so that they correspond to JSON property names, or you can do it right:
Change names of Java class properties and methods to standard convention so that code is nice and readabl.
Annotate properties with #JsonProperty to express different that default mapping between JSON and Java object.
From Annotation Type JsonProperty Java docs:
Default value ("") indicates that the field name is used as the
property name without any modifications, but it can be specified to
non-empty value to specify different name. Property name refers to
name used externally, as the field name in JSON objects.
Example with annotation:
public class test {
#JsonProperty("_index")
private String index;
private Integer total;
#JsonProperty("_type")
private String type;
public String getIndex() { return index; }
public void setIndex(String index){ this.index = index; }
public Integer getTotal() { ... }
public void setTotal(Integer total) { ... }
public String getType() { ... }
public void setType(String type) { ... }
....
}

parse json when value of one json becomes key of another json in java

I have two jsons like these
{
"clientId":"patientId",
"vendorId":"businessKey"
}
{
"patientId":"1234",
"businessKey":"abcd"
}
I have java POJOs created like these
public class Patient{
private String patientId;
private String businessKey;
public String getPatientId() {
return patientId;
}
public void setPatientId(String patientId) {
this.patientId = patientId;
}
public String getBusinessKey() {
return businessKey;
}
public void setBusinessKey(String businessKey) {
this.businessKey = businessKey;
}
}
public class Client {
private String clientId;
private String vendorId;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getVendorId() {
return vendorId;
}
public void setVendorId(String vendorId) {
this.vendorId = vendorId;
}
}
I am using Jackson's ObjectMapper to parse the JSON. What I want to achieve is first read the first JSON, get the value from that and then read the actual value from the second JSON.
Ex: I read the first JSON to getClientId - "patientId"
Then in the second JSON I should read getPatientId - 1234.
How do I achieve this programmatically. I dont want to clutter my code by adding lot many if else blocks. Is there any library that I could use?

Categories

Resources