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) { ... }
....
}
Related
JIRA JQL Search Query: post method with end point http://localhost:8080/rest/api/2/search
body:
{
"jql":"project = QA and key=123",
"startAt":0,
"maxResults":1,
"fields":[
"id",
"key",
"custom_Field1"
]
}
above structure giving expected values for variables from fields array in postman
ISSUE :
REST API JAVA IMPLEMENTATION
For above structure POJO class been defined and while creating JSCON from POJO Class, variables from fields POJO class are ignored as they are not set by setter method. Due to this not getting desired output from response. How to convert POJO class to JSCON as per above structure.
Converted JSCON from POJO CLASS
{
"jql":"project = QA and key=123",
"startAt":0,
"maxResults":1,
"fields":[]
}
with this structure it is not returning value for custom_Field1
in Java Rest API POJO Class created as below
public root{
private String jql;
private int startAt;
private int maxResults;
private List<field> fields;
public void setjql(String jql){
this.jql=jql;
}
public String getjql(){
return this.jql;
}
public void setstartAt(int startAt){
this.startAt=startAt;
}
public int getstartAt(){
return this.startAt;
}
public void setmaxResults(int maxResults){
this.maxResults=maxResults;
}
public int getmaxResults(){
return this.maxResults;
}
public void setfields(List<field> fields){
this.fields=fields;
}
public List<fields> getfileds(){
return this.fields;
}
}
public field{
private int id;
private String key;
private String custom_Field1;
public void setID(int id){
this.id=id;
}
public int getID(){
return this.id;
}
public void setKey(String key){
this.key=key;
}
public String getKey(){
return this.key;
}
public void setcustom_Field1(String custom_Field1){
this.custom_Field1=custom_Field1;
}
public String getcustom_Field1(){
return this.custom_Field1;
}
}
I want to convert below JSON structure to java object, Annotation bases.
What will be the pojo java class structure?
{
"Data1":{
"Name":"abc",
"Number":2
}
}
Data1 can by any string-like if it coming as data1 first time, next time it can be like "xyz".
How can we convert it using fasterxml json annotations?
class Node {
public String name;
public int number
}
class ConvertedPojo {
public Map<String, Node> attributes;
}
Since Data1 can be any string you need a map which will store all different string as key and value as json object
Class structure will be :
public class Data1{
#JsonProperty("Name")
private String name;
#JsonProperty("Number")
private int number;
public String getName() {
return name;
}
public void setName(String name) {
name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
number = number;
}
}
public class Data {
#JsonProperty("Data1")
Object data1;
public Object getData1() {
return data1;
}
public void setData1(Object data1) {
this.data1 = data1;
}
}
Take care of the variable naming convention.
Code to test:
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Data data1 = mapper.readValue("{\"Data1\":{\"Name\":\"abc\",\"Number\":2}}", Data.class);
System.out.println(mapper.writeValueAsString(data1));//{"Data1":{"Name":"abc","Number":2}}
Data data2 = mapper.readValue("{\"Data1\":\"data value\"}", Data.class);
System.out.println(mapper.writeValueAsString(data2));//{"Data1":"data value"}
}
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.
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?
I am using Retrofit and Parceler libraries in order to communicate with my server.
The server has the following two API methods:
GET /api/metadata/{id} that returns the following JSON
{
"id": 1,
"active": true,
"location": {
"type": "Point",
"coordinates": [
30.0000,
30.0000
]
}
}
POST /api/metadata/{id} that expects the following JSON
{
"id": 1,
"active": true,
"location_latitude": 30.0000,
"location_longitude": 30.0000
}
That is so for historic reasons and cannot change.
In my android application, I declare Retrofit in the following way:
public interface ServerApi {
#GET("/api/metadata/{id}")
Metadata getMetadata(#Path("id") int id);
#POST("/api/metadata/{id}")
Metadata updateMetadata(#Path("id") int id, #Body Metadata metadata);
}
Parcel classes are defined in the following way:
Metadata:
#Parcel
public class Metadata {
#SerializedName("id")
private Integer id;
#SerializedName("location")
private GeometryPoint location;
#SerializedName("location_latitude")
private float locationLatitude;
#SerializedName("location_longitude")
private float locationLongitude;
public void setId(Integer id) {
this.id = id;
}
public void setLocationLatitude(float locationLatitude) {
this.locationLatitude = locationLatitude;
}
public void setLocationLongitude(float locationLongitude) {
this.locationLongitude = locationLongitude;
}
public void setLocation(GeometryPoint location) {
this.location = location;
}
public Integer getId() {
return id;
}
public float getLocationLatitude() {
return locationLatitude;
}
public float getLocationLongitude() {
return locationLongitude;
}
public GeometryPoint getLocation() {
return location;
}
}
GeometryPoint:
#Parcel
public class GeometryPoint {
#SerializedName("type")
private String type;
#SerializedName("coordinates")
private float[] coordinates;
public void setType(String type) {
this.type = type;
}
public void setCoordinates(float[] coordinates) {
this.coordinates = coordinates;
}
public String getType() {
return type;
}
public float[] getCoordinates() {
return coordinates;
}
}
I would like to use Metadata class throughout my application. I would like to query the server, receive Metadata, update it, and send it to the server. Obviously, the formats of metadata differ between the GET and POST. As such, I'd like to have GET coverted to POST format upon receiving it.
My question is whether it is possible to somehow declare annotations so that Retrofit and Parceler would be aware of location parameter, deserialize it from JSON but write it to Metadata class via setLocation() method where I could break it down into `location_latitude' and 'location_longitude'.
This is some pseudocode of the desired Metadata class:
#Parcel
public class Metadata {
#SerializedName("id")
private Integer id;
// I'd like not having location variable defined at all
// but use some annotation magic :)) to tell GSON to deserialize
// JSON and call setLocation() when it tries to process location
// parameter of the server response
/*
#SerializedName("location")
private GeometryPoint location;
*/
#SerializedName("location_latitude")
private float locationLatitude;
#SerializedName("location_longitude")
private float locationLongitude;
public void setId(Integer id) {
this.id = id;
}
public void setLocationLatitude(float locationLatitude) {
this.locationLatitude = locationLatitude;
}
public void setLocationLongitude(float locationLongitude) {
this.locationLongitude = locationLongitude;
}
public void setLocation(GeometryPoint location) {
this.location_latitude = location.getCoordinates()[1];
this.location_longitude = location.getCoordinates()[0];
}
public Integer getId() {
return id;
}
public float getLocationLatitude() {
return locationLatitude;
}
public float getLocationLongitude() {
return locationLongitude;
}
// No need for getLocation method
}
Or am I just being silly (I literally picked up Retrofit, Parceler, and GSON awareness yesterday) and should create two metadata classes MetadataExternal and MetadataInternal to use for receiving and sending to the server?