How to parse Retrofit JSON response - java

I have a typical Retrofit API request:
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(URL)
.build();
ApiEndpointInterface api = restAdapter.create(ApiEndpointInterface.class);
api.getToken('1', new Callback<DefaultResponse>() {
#Override
public void success(DefaultResponse json, Response response) {
//
}
#Override
public void failure(RetrofitError response) {
//
}
});
And the returned JSON is:
{"success":true,"data":{"token_id":"pPt9AKl0Cg","token_key":"8ax224sFrJZZkStAQuER"}}
How can I parse this JSON? It seems wrong/tedious to create a new model class for each different response across my app. Is there a better way to do it?

you should write your model class like below
public class MyResponseModel {//write setters and getters.
private boolean success;
private DataModel data;
public static class DataModel {
private String token_id;
private String token_key;
}
}
now in your getToken() method should look like this
getToken('1', Callback<MyResponseModel> response);
retrofit will parse the response and convert it to the class above.

Try this code,
JsonElement je = new JsonParser().parse(s);
JsonObject asJsonObject = je.getAsJsonObject();
JsonElement get = asJsonObject.get("data");
System.out.println(s + "\n" + get);
JsonObject asJsonObject1 = get.getAsJsonObject();
JsonElement get1 = asJsonObject1.get("token_id");
System.out.println(get1);
JsonElement get2 = asJsonObject1.get("token_key");
System.out.println(get2);

Related

#RequestBody return null after create body

i have created RequestBody with Gson and add to Post request, but in the controller of api (url), all attrs return null.
Add to RequestBody:
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
Gson gson = new Gson();
JSONObject jsonObject = new JSONObject();
jsonObject.put("dataFromAppChinh", "demo thoi");
jsonObject.put("path", path);
String body = gson.toJson(jsonObject);
RequestBody requestBody = RequestBody.create(body, JSON);
Request request = new Request.Builder().url("http://" + path + "/api/startapp").post(requestBody).build();
Controller
#RestController
#RequestMapping("/api")
public class ChatBot {
#PostMapping(value = "/startapp")
#ResponseBody
public Object start(#RequestBody() ChatBotResponse item) {
try {
item.setResponseList(startApp(item.getPath()));
return item;
} catch (Exception ex) {
log.error(ex);
return ex.getMessage();
}
}
}
My ChatBotResponse POJO:
#Data
public class ChatBotResponse
{
private String dataFromAppChinh;
private String responseList;
private String path;
}
i found problem is gson.toJson(jsonObject) insert map string before my Json String.
I changed to jsonObject.toString() and it worked.

How to map a JSON response to a Java class using Java 11 HttpClient and Jackson?

I'm new to the Java 11 HttpClient and would like to give it a try. I have a simple GET request that return JSON and I would like to map the JSON response to a Java class called Questionnaire.
I understand that I can turn the response out of box into a String or an input stream like this
HttpRequest request = HttpRequest.newBuilder(new URI(String.format("%s%s", this.baseURI, "/state")))
.header(ACCEPT, APPLICATION_JSON)
.PUT(noBody()).build();
HttpResponse<String> response = this.client.send(request, HttpResponse.BodyHandlers.ofString());
How can I write something that converts the JSON string to my Questionnaire class like this?
HttpResponse<Questionnaire> response = this.client.send(request, HttpResponse.BodyHandlers./* what can I do here? */);
I use Jackson to transform JSON into Java class instances. Is there Jackson support for the new Java standard HttpClient yet?
UPDATE 1
I was not precise enough, sorry about that. I am looking for a blocking get example. I was aware of http://openjdk.java.net/groups/net/httpclient/recipes.html#jsonGet
Solution for Java 11 HttpClient::sendAsync only
Based on this link you can do something like this :
public static void main(String[] args) throws IOException, URISyntaxException, ExecutionException, InterruptedException {
UncheckedObjectMapper uncheckedObjectMapper = new UncheckedObjectMapper();
HttpRequest request = HttpRequest.newBuilder(new URI("https://jsonplaceholder.typicode.com/todos/1"))
.header("Accept", "application/json")
.build();
Model model = HttpClient.newHttpClient()
.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenApply(uncheckedObjectMapper::readValue)
.get();
System.out.println(model);
}
class UncheckedObjectMapper extends com.fasterxml.jackson.databind.ObjectMapper {
/**
* Parses the given JSON string into a Map.
*/
Model readValue(String content) {
try {
return this.readValue(content, new TypeReference<Model>() {
});
} catch (IOException ioe) {
throw new CompletionException(ioe);
}
}
}
class Model {
private String userId;
private String id;
private String title;
private boolean completed;
//getters setters constructors toString
}
I used some dummy endpoint which provides sample JSON input and sample model class to map the response directly to Model class using Jackson.
Solution for Java 11 HttpClient::send and HttpClient::sendAsync
I found a way by defining custom HttpResponse.BodyHandler :
public class JsonBodyHandler<W> implements HttpResponse.BodyHandler<W> {
private Class<W> wClass;
public JsonBodyHandler(Class<W> wClass) {
this.wClass = wClass;
}
#Override
public HttpResponse.BodySubscriber<W> apply(HttpResponse.ResponseInfo responseInfo) {
return asJSON(wClass);
}
public static <T> HttpResponse.BodySubscriber<T> asJSON(Class<T> targetType) {
HttpResponse.BodySubscriber<String> upstream = HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8);
return HttpResponse.BodySubscribers.mapping(
upstream,
(String body) -> {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(body, targetType);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}
}
Then I call it :
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder(new URI("https://jsonplaceholder.typicode.com/todos/1"))
.header("Accept", "application/json")
.build();
Model model = HttpClient.newHttpClient()
.send(request, new JsonBodyHandler<>(Model.class))
.body();
System.out.println(model);
}
The response is :
Model{userId='1', id='1', title='delectus aut autem', completed=false}
The JavaDoc of HttpResponse.BodySubscribers::mapping was particulary useful to solve this. It can be further improved to use HttpResponse.BodySubscribers::ofInputStream instead of HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8) to define the BodySubscriber for the JsonBodyHandler.
Simplifying #michalk solution for Java 11 HttpClient::send
HttpService Class Example:
public class HttpService {
private final HttpClient httpClient= HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build();
public HttpService() {}
public <T> T sendGetRequest(String url, Class<T> responseType) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder().GET().uri(URI.create(url)).header("Accept", "application/json").build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
return new ObjectMapper().readValue(response.body(), responseType);
}
public <T> List<T> sendGetListRequest(String url, Class<T> responseType) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder().GET().uri(URI.create(url)).header("Accept", "application/json").build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(response.body(), objectMapper.getTypeFactory().constructCollectionType(List.class, responseType));
}}
Model Class Example:
public class Model {
private String id;
public Model() {}
public String getId() { return this.id; }
public void setId(String id) { this.id = id; }
#Override
public String toString() { return "Model{" + "id='" + id + '\'' + '}'; }}
Sending HTTP GET request:
public class Main {
public static void main(String[] args) {
try {
HttpService httpService = new HttpService();
Model model = httpService.sendGetRequest("http://localhost:8080/api/v1/models/1", Model.class);
System.out.println("Single Object:" + model);
System.out.print('\n');
List<Model> models = httpService.sendGetListRequest("http://localhost:8080/api/v1/models", Model.class);
for(Model m: models) { System.out.println("Object:" + m); }
}
catch (IOException | InterruptedException e) {
System.err.println("Failed to send GET request: " + e.getMessage());
}
}}
Response:
Single Object: Model{id='1'}
Object: Model{id='1'}
Object: Model{id='2'}
Object: Model{id='3'}
Required Maven Dependency (pom.xml):
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.3</version>
</dependency>
If you're OK with including a dependency, check out Methanol (disclaimer: I'm the library's author). The library has special BodyHandler implementations for object mapping. You can add JSON support by installing the jackson adapter.
var request = MutableRequest.GET("https://example.com")
.header("Accept", "application/json");
var modelResponse = client.send(request, MoreBodyHandlers.ofObject(Model.class));
// Use TypeRef<T> for complex types
var modelListResponse = client.send(request, MoreBodyHandlers.ofObject(new TypeRef<List<Model>>() {}));

Try to getting data from API using java

I'm a .Net guy. I tried to call API and getting data from.
Serialized JSON object using java.. but I'm getting this error.
Expected BEGIN_ARRAY but was BEGIN_OBJECT
In .NET it's really easy to do. but in java, I haven't idea how to do that.
this my model class
public class Dictionary {
#SerializedName("metadata")
#Expose
private Metadata metadata;
#SerializedName("results")
#Expose
private List<Result> results = null;
public Metadata getMetadata() {
return metadata;
}
public void setMetadata(Metadata metadata) {
this.metadata = metadata;
}
public List<Result> getResults() {
return results;
}
public void setResults(List<Result> results) {
this.results = results;
}
}
And here the my api call
public class Oxford {
public String URL_OXFORD = "https://od-api.oxforddictionaries.com/api/v1/inflections/en/swimming";
public static List<Dictionary> httpGet(String url, String function) {
List<Dictionary> dataFromService = new ArrayList<Dictionary>();
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
HttpGet request = new HttpGet(url+function);
request.addHeader("content-type", "application/json");
request.addHeader("app_id", "566566");
request.addHeader("app_key", "somekey");
HttpResponse result = httpClient.execute(request);
String json = EntityUtils.toString(result.getEntity(), "UTF-8");
com.google.gson.Gson gson = new com.google.gson.Gson();
Dictionary[] response = gson.fromJson(json, Dictionary[].class);
System.out.println(response.length);
for(Dictionary file : response)
{
dataFromService.add(file);
System.out.println(file.toString());
}
} catch (IOException ex) {
}
return dataFromService;
}
Since the documentation returns one object (starting with {, not a [) you probably need a
Dictionary response
instead of
Dictionary[] response
It is returning one dictionary object, not an array. Checkout the documentation at https://developer.oxforddictionaries.com/documentation

How to access the json objects using volley

this is the api response i ma accessing the json object and setting the textview of uuid in text view but nothing happen
please suggest code for accessing json object from api response
{
"success":true,
"data {
"serial_key_id":"75",
"order_id":"0",
"product_id":"0",
"serial_key":"WURYFO",
"valid_till":null,
"limit":"0",
"uuid":"",
"used":false
}
}
private void jsonobject() {
String url = "http://mylocalpay.com/?serial_key_api=1&coupon=WURYFO";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i("msg", "response" + response);
try {
JSONObject success = response.getJSONObject("success");
JSONObject data = response.getJSONObject("data");
String serial_key_id = data.getString("serial_key_id");
String order_id = data.getString("order_id");
String product_id = data.getString("product_id");
String serial_key = data.getString("serial_key");
String limit = data.getString("limit");
String uuid = data.getString("uuid");
boolean used = data.getBoolean("used");
JSONObject valid_till = data.getJSONObject("valid_till");
textView.setText(uuid);
System.out.println(serial_key);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO: Handle error
}
});
}
}
You need to parse this JSON into a java object. You could write your own code to do this (which is a very large undertaking) or you could use Googles GSON library.
GSON GitHub page
You can use this library as so
Gson gson = new Gson();
String jsonInString = "{'serial_key_id' : '75'}";
YourClass yourClass = gson.fromJson(jsonInString, YourClass.class);

Gson deserializer support multiple types

I want to deserialize a JSON response but I'm not sure about the format. The format can vary in each case. For example the response contains a field named "error" which may be false (boolean) or an object that describes the error eg. "error": { "code": xxx , "description":"etc"}
How should I implement a class that covers both cases? Is there any way to do this?
Thanks
I would prefer using a TypeAdapter for your case:
private static class Error {
private boolean hasError;
private int code;
private String description;
}
private static class ErrorTypeAdapter extends TypeAdapter<Error> {
#Override
public Error read(JsonReader jsonReader) throws IOException {
Error response = null;
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String currentJsonName = jsonReader.nextName();
if("error".equals(currentJsonName)) {
response = new Error();
try {
response.hasError = jsonReader.nextBoolean();
} catch (Exception e) {
response.hasError = true;
jsonReader.beginObject();
}
} else if("code".equals(currentJsonName)) {
response.code = jsonReader.nextInt();
} else if ("description".equals(currentJsonName)) {
response.description = jsonReader.nextString();
}
}
if(response.hasError) {
jsonReader.endObject();
}
jsonReader.endObject();
return response;
}
#Override
public void write(JsonWriter jsonWriter, Error response)
throws IOException {
jsonWriter.beginObject();
jsonWriter.name("hasError").value(response.hasError);
jsonWriter.name("code").value(response.code);
jsonWriter.name("description").value(response.description);
jsonWriter.endObject();
}
}
To test it you can use:
String val1 = "{\"error\": {\"code\": 1 , \"description\":\"etc\"}}";
String val2 = "{\"error\": false}";
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Error.class, new ErrorTypeAdapter());
gsonBuilder.setPrettyPrinting();
final Gson gson = gsonBuilder.create();
gson.fromJson(val1, Error.class);
gson.fromJson(val2, Error.class);
You can read more about TypeAdapters here and also some great examples here.

Categories

Resources