I'm trying to use gson to deserialize some data that I'm getting back from a SonarQube API on various code metrics. This is an example of the raw JSON coming back from the server:
{
"component": {
"id": "c5fc9d6k-e28b-4ea0-8922-df18c7e07ac1",
"key": "APP:master",
"name": "master",
"qualifier": "TRK",
"measures": [
{
"metric": "coverage",
"value": "19.9",
"periods": [
{
"index": 1,
"value": "0.09999999999999787"
},
{
"index": 2,
"value": "0.09999999999999787"
},
{
"index": 3,
"value": "0.6999999999999993"
},
{
"index": 4,
"value": "8.7"
}
]
},
{
"metric": "overall_coverage",
"value": "55.7",
"periods": [
{
"index": 1,
"value": "0.0"
},
{
"index": 2,
"value": "0.0"
},
{
"index": 3,
"value": "3.0"
},
{
"index": 4,
"value": "55.7"
}
]
},
{
"metric": "ncloc",
"value": "1089127",
"periods": [
{
"index": 1,
"value": "3835"
},
{
"index": 2,
"value": "3835"
},
{
"index": 3,
"value": "-74350"
},
{
"index": 4,
"value": "102501"
}
]
}
]
}
}
I'm attempting to deserialize it into a Component class with this code:
public Component getComponentMeasures(String componentKey, List<String> measures) throws ClientProtocolException,
IOException, JsonSyntaxException, UnsupportedOperationException, JSONException
{
HttpGet request = new HttpGet(baseURL + String.format("/api/measures/component?componentKey=%s&metricKeys=%s",
componentKey, StringUtils.join(measures, ",")));
HttpResponse response = client.execute(request);
Gson gson = new Gson();
String componenta = getJSONResponse(response);
System.out.print(componenta);
Component component = gson.fromJson(componenta, Component.class);
return component;
}
This is the Component class that I'm deserializing it into:
public class Component {
#SerializedName("id")
#Expose
private String id;
#SerializedName("key")
#Expose
private String key;
#SerializedName("name")
#Expose
private String name;
#SerializedName("qualifier")
#Expose
private String qualifier;
#SerializedName("path")
#Expose
private String path;
#SerializedName("measures")
#Expose
private Measure[] measures = null;
public String getId() {
return id;
}
public String getKey() {
return key;
}
public String getName() {
return name;
}
public String getQualifier() {
return qualifier;
}
public String getPath() {
return path;
}
public Measure[] getMeasures() {
return measures;
}
}
This Component class also contains an array of Measures which in turn contain an array of periods.
Measure Class:
public class Measure {
#SerializedName("metric")
#Expose
private String metric;
#SerializedName("value")
#Expose
private String value;
#SerializedName("periods")
#Expose
private Period[] periods = null;
public String getMetric() {
return metric;
}
public String getValue() {
return value;
}
public Period[] getPeriods() {
return periods;
}
}
Period class:
public class Period {
#SerializedName("index")
#Expose
private Integer index;
#SerializedName("value")
#Expose
private String value;
public Integer getIndex() {
return index;
}
public String getValue() {
return value;
}
}
When I run this code, the deserialized component is null. Any ideas on anything that I may be doing wrong here? Note that there is an extra parameter in the Component class, "path", that is null in the JSON. This is optional and exists in other classes which contain a collection of Component objects. In those cases, this Component object and JSON deserialize fine. I've compared the JSON side-by-side and they are identical. I only seem to have the issue when trying to deserialize a standalone component object. Any help would be greatly appreciated!
Note that your JSON document is a JSON object with a single property (the path: $.component) with a nested component, however you're trying to deserialize it as if it were the top-most object:
Component component = gson.fromJson(componenta, Component.class);
Just create another class to match the top-most single property object, say something like:
final class Response {
#SerializedName("component")
#Expose
final Component component = null;
}
And then sample code like
final Response response = gson.fromJson(componenta, Response.class);
for ( final Measure measure : response.component.measures ) {
System.out.println(measure.metric + " " + measure.value);
}
will print the following output:
coverage 19.9
overall_coverage 55.7
ncloc 1089127
Sonar has an SDK for their API that encapsulates all of this and you don't have to create your own classes, etc. I used it to get info out like you're doing. See https://docs.sonarqube.org/display/SONARQUBE45/Using+the+Web+Service+Java+client and my use of it: http://myvogonpoetry.com/wp/2013/02/21/using-the-sonar-rest-api-for-weekly-emails/
Related
i have JSON :
{
"id": "string",
"name": "string",
"port": 0,
"location": "string",
"useCustomLocation": true,
"inMemoryMode": true,
"enabled": true,
"active": true,
"autoStartup": true,
"partitions": [
{
"id": "string",
"name": "string",
"factorUser": {
"username": "string",
"password": "string",
"admin": true,
"perms": "string"
},
"users": [
{
"username": "string",
"password": "string",
"admin": true,
"perms": "string"
}
]
}
]
}
My pojo classes:
public class Root {
private String id;
private String name;
private long port;
private String location;
private boolean useCustomLocation;
private boolean inMemoryMode;
private boolean enabled;
private boolean active;
private boolean autoStartup;
private Partition[] partitions;
//Getter and Setters simple variebles
public Partition[] getPartitions() {
return partitions;
}
public void setPartitions(Partition[] value) {
this.partitions = value;
}
}
Partition class:
public class Partition {
private String id;
private String name;
private User factorUser;
private User[] users;
//Getter and Setters simple variebles
public User getFactorUser() {
return factorUser;
}
public void setFactorUser(User value) {
this.factorUser = value;
}
public User[] getUsers() {
return users;
}
public void setUsers(User[] value) {
this.users = value;
}
}
and the next two classes work similarly(FactorUser and User)
my Test:
public void postBaseData() {
Root root = new Root();
Response response = given()
.contentType(ContentType.JSON)
.log().all()
.auth()
.preemptive()
.basic("login", "password")
.body(root)
.baseUri(BaseUrl + STORE_INSTANCE)
.when()
.post()
.then()
.extract().response();
System.out.println(response.getBody().asString());
Assert.assertEquals(200, response.statusCode());
}
Why is only part of the request sent to me? And therefore returning status code 400
Part of body which posted:
{
"id": null,
"name": null,
"port": 0,
"location": null,
"useCustomLocation": false,
"inMemoryMode": false,
"enabled": false,
"active": false,
"autoStartup": false,
"partitions": null
}
I understand that the error is somewhere in the initialization of nested classes, for example "partition", but I can not understand how to do it correctly.I asked a similar question with get, but for a long time I can’t figure out how to work with such complex json requests. I also tried the line: "private Partition[] partitions" changing to "private List<Partition> partitions" and etc... but I still can't send full json.
i don't use constructor because in POSTMAN i get 200 ok with empty fields
scr
I have an API built in Java Spring that return (using JacksonJaxbJsonProvider 2.5.5) a JSON object from this class:
public class FieldValues {
private String code;
private Object value;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
In the main object I've
#JsonRootName(value = "WorkRequest")
#XmlRootElement(name = "WorkRequest")
#JsonIgnoreProperties(ignoreUnknown = true)
public class WorkRequestDTOResponse {
private List<FieldValues> fieldValues;
public List<FieldValues> getFieldValues() {
return fieldValues;
}
public void setFieldValues(List<FieldValues> fieldValues) {
this.fieldValues = fieldValues;
}
}
But the output of the fieldValues object is this:
"fieldValues": [
{
"code": "anomaly",
"value": {
"#xsi.type": "ns3:boolean",
"$": "true"
}
},{
"code": "internal_note",
"value": {
"#xsi.type": "ns3:string",
"$": "Test text example"
}
}
]
instead what I need is this:
"fieldValues": [
{
"code": "anomaly",
"value": true
},{
"code": "internal_note",
"value": "Test text example"
}
]
This is my JSON Provider:
public class ErmesJSONProvider extends JacksonJaxbJsonProvider {
public ErmesJSONProvider() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
mapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, false);
_mapperConfig.setMapper(mapper);
_mapperConfig.getConfiguredMapper().setAnnotationIntrospector(new JacksonAnnotationIntrospector());
}
}
Trying to use a String instead an object:
public class FieldValues {
private String code;
private String value;
But if I set this value as String fieldValues.setValue("true"), the JSON output is "value": true instead "value": "true"
Likewise if I set this value as String but with an Integer fieldValues.setValue("1"), the JSON output is "value": 1 instead "value": "1"
If I print the return object using ObjectMapper I've the right JSON:
String payload = new ObjectMapper().writeValueAsString(requestResult)
but if I return a Response like this:
return Response.status(Response.Status.CREATED).entity(new GenericEntity<RequestResult>(requestResult){}).build()
it return the wrong JSON.
I can't understand why 😥
Someone can help me? Thanks.
Currently I'm trying to write a site that interacts with a public API using Feign and Spring.
I'm having trouble deciding how to handle the object mapping for deeply nested JSON.
Ex:
[
{
"type": "console",
"category": "Console",
"result_count": 1,
"shown_count": 1,
"result": [
{
"name": "Nintendo Switch",
"id": "nintendo-switch",
"platform": {
"name": "Nintendo",
"category": "nintendo",
"type": "platform"
},
"image": {
"url": "https://encrypted-tbn1.gstatic.com/shopping?q=tbn:ANd9GcRqJYIheMDjTE9WAHjMSW4bjh7OplS7Bep9CdsBBLWMwGdXim7xOG4&usqp=CAc",
"height": 409,
"width": 631
},
"min_price": 205,
"variations": [
{
"items": [
{
"hex_code": "#696969",
"name": "Gray",
"id": "space-gray",
"type": "color"
},
{
"hex_code": "#C0C0C0",
"name": "Silver",
"id": "silver",
"type": "color"
}
],
"name": "Color",
"type": "color"
},
{
"items": [
{
"name": "Nintendo",
"id": "nintendo",
"type": "platform"
}
],
"name": "Platform",
"type": "platform"
}
]
}
]
}
]
As of now, I have a single Java file with a class for each object in the JSON, and I've considered having the Object mapper just put everything into a HashMap. Is there a more elegant way to do this?
public class SearchResults {
private List<SearchResult> products;
private int resultCount;
private String type;
}
class SearchResult {
private String name;
private String slug;
private Image image;
}
class Image {
private String URL;
private String height;
private String width;
}
Based on the json file provided i have designed the classes and also provided the code to parse the json file to java
public class Console{
String type;
String category;
int result_count;
int show_count;
Result [] result;
}
public class Result{
String name;
String id;
Platform platform;
Image image;
int mini_price;
Variation [] variations;
}
public class Platform{
String name;
String category;
String type;
}
public class Image{
String url;
int height;
int width;
}
public class Variation{
String name;
String type;
Item [] items;
}
public class Item{
String hex_code;
String name;
String id;
String type;
}
code to parse:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
Console[] consoles = objectMapper.readValue(ResourceUtils.getFile("path of json file"), Console[].class);
logger.info("Continents -> {}",(Object)continents);
for(Console console:consoles) {
//read the data accordingly
}
I'm using retrofit at my android application. At my webapi, there is a nested json result which i need to parse. Not nested ones are fine, but when i encountered nested one, it seems i can't parse them.
This is my json example. I've shortened it a bit but all same.
When i executed call method, it just bypassing onResponse or onFailure.
I'm thinking i made a mistake at my class file but i cant figure out what or how.
JSON:
[
{
"name": "All joined for mobile",
"selectedOnes": [
"1",
"2"
],
"lines": [
{
"details": "",
"cancelDetails": null,
"isCancel": null,
"hours": [
{
"arrivalTime": "",
"departTime": "07:15:00"
},
{
"arrivalTime": "07:30:00",
"departTime": ""
}
]
},
{
"details": "",
"cancelDetails": null,
"isCancel": null,
"hours": [
{
"arrivalTime": "",
"departTime": "07:30:00"
},
{
"arrivalTime": "07:45:00",
"departTime": ""
}
]
}
]
}
]
ParsedJsonClass.java:
public class ParsedJsonClass {
#SerializedName("name")
#Expose
private String name;
#SerializedName("selectedOnes")
#Expose
private List<String> selectedOnes = null;
#SerializedName("lines")
#Expose
private List<lines> lines = null;
public class lines {
#SerializedName("details")
#Expose
private String details;
#SerializedName("cancelDetails")
#Expose
private Object cancelDetails;
#SerializedName("isCancel")
#Expose
private Object isCancel;
#SerializedName("hours")
#Expose
private List<hours> hours = null;
public class hours {
#SerializedName("arrivalTime")
#Expose
private String arrivalTime;
#SerializedName("departTime")
#Expose
private String departTime;
}
}
}
I'm querying an API with Retrofit, where the answer is this
[
{
"Id": "BT00",
"Text": "Registrarme"
},
{
"Id": "BT01",
"Text": "Iniciar sesión"
},
{
"Id": "BT02",
"Text": "Siguiente"
},
{
"Id": "BT03",
"Text": "Si"
},
{
"Id": "BT04",
"Text": "No"
}
]
and the body response look like this screenshot
This call is stored in a ArrayList.
#SerializedName("Id")
#Expose
private String id;
#SerializedName("Text")
#Expose
private String text;
//Getters&Setters
My answer is, how to access of elements of the response?
I tried the following ways but it does not work
apptext_id.setText(response.body().get(0).toString());
Logger.d("Body %s", response.body().get(0).toString());
Logger.d("Body %s", response.body().get(0));
the answer look like this
What you need to do to get the first element of the list is: response.body().get(0).getText();
If you need to get each item, you need to:
if (response.isSuccessful()) {
List<AppTextModel> list_elements = response.body();
for (AppTextModel item : list_elements) {
Logger.d("Body %s", item.getText()); // print every text item in list
}
}
You also need in the POJO class:
public class AppTextModel {
#SerializedName("Id")
#Expose
private String id;
#SerializedName("Text")
#Expose
private String text;
//Getters&Setters
public String getText() {
return text;
}
}