I have an Android app communicating with an external MySQL Database. I can do my operations without any problem, but each query generates a lot of code, ( HTTPost + Json Parsing) and I have a lot of queries.
Is there a way to factorise code, a good lib, or something like that?
There is AsyncHttpClient: http://loopj.com/android-async-http/
where you get onSuccess and onFailure methods to work with the response.
To parse your data:
As your response is JSON format, you may be better off using Gson library to map data and with custom model classes. Eg.:
Gson gson = new Gson();
ModelClass modelClass= new ModelClass();
modelClass= gson.fromJson(responseContent,ModelClass.class);
//where responseContent is your jsonString
Log.i("Web service response", ""+modelClass.toString());
More on: https://code.google.com/p/google-gson/
For Naming discrepancies(according to the variables in webservice), can use annotations like
#SerializedName.
Use a for each loop to verify/browse/access the data that would be populated in/as objects/fields of your model class:
Check these for doubts:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
How does the Java 'for each' loop work?
Related
I am trying to parse the results of an API call which returns a unique first property.
{
"AlwaysDifferent12345": {
"fixedname1" : "ABC1",
"fixedname2" : "ABC2"
}
}
I am using retrofit2 and jackson/gson and cannot figure out how to cope with dynamic property names within the retrofit2 framework. The following works fine
data class AlwaysDifferentDTO(
#JsonProperty("AlwaysDifferent12345") val alwaysDifferentEntry: AlwaysDifferentEntry
)
I have tried
data class AlwaysDifferentDTO(
#JsonProperty
val response: Map<String, AlwaysDifferentEntry>
)
But this returns errors Can not instantiate value of type... The return value from the API is fixed i.e. map<string, object>.
I have read you can write a deserializer but it looks like I need to deserialize the whole object when all I want to do is just ignore the string associated with the response.
I have read
https://discuss.kotlinlang.org/t/set-dynamic-serializedname-annotation-for-gson-data-class/14758
and several other answers. Given unique properties names are quite common it would be nice to understand how people deal with this when using retrofit2
Thanks
Because the JSON doesn't have a 1-to-1 mapping Jackson can't map it automatically using annotations. You are going to need to make your own Deserializer.
In this tutorial you can learn how to create your own custom Deserializer for Jackson. https://www.baeldung.com/jackson-deserialization
In the tutorial you will see the first line under the deserialize function is
JsonNode node = jp.getCodec().readTree(jp);
using this line you can get the JSON node as a whole and once you have it you can call this function
JsonNode AlwaysDifferent12345Node = node.findParent("fixedname1");
Now that you have that node you can retrieve its value like shown in the rest of the tutorial. Once you have all the values you can return a new instance of the AlwaysDifferentDTO data class.
Previously I was receiving the response like this:
I was parsing it like: Call<List<MyObject>> getList();
But now there are some new elements were added and the response changed to:
How to parse this object now? I searched my could not find any solutions.
This is how I am setting up my client.
This is the json object which i recieve as a response:
{"map":{"01":{"F":".","E":".","D":null,"C":null,"B":".","A":"."},"02":{"F":".","E":".","D":null,"C":null,"B":"Z","A":"."},"03":{"F":"A","E":"A","D":null,"C":null,"B":"A","A":"A"},"board":false,"type":{"num":"TT334","board":"WW","date":"31MAR","route":"AWETSW","pcount":""}}}
I dont
There are two potential solutions:
You create a DTO. Gson will ignore fields you don't map in your dto. Your json doesn't use a list it is entirely objects.
You manually parse the json using Gson's JsonReader
You can use a mixture of DTOs and manual parsing. I have done this for large json datasets and inconsistent datasets.
I was wondering if somewhere out there exists a java library able to query a JSONObject. In more depth I'm looking for something like:
String json = "{ data: { data2 : { value : 'hello'}}}";
...
// Somehow we managed to convert json to jsonObject
...
String result = jsonObject.getAsString("data.data2.value");
System.out.println(result);
I expect to get "hello" as output.
So far, the fastest way I have found is using Gson:
jsonObject.getAsJsonObject("data").getAsJsonObject().get("data2").getAsJsonObject("value").getAsString();
It's not actually easy to write and read. Is there something faster?
I've just unexpectedly found very interesting project: JSON Path
JsonPath is to JSON what XPATH is to XML, a simple way to extract parts of a given document.
With this library you can do what you are requesting even easier, then my previous suggestion:
String hello = JsonPath.read(json, "$.data.data2.value");
System.out.println(hello); //prints hello
Hope this might be helpful either.
While not exactly the same, Jackson has Tree Model representation similar to Gson:
JsonNode root = objectMapper.readTree(jsonInput);
return root.get("data").get("data2").get("value").asText();
so you need to traverse it step by step.
EDIT (August 2015)
There actually is now (since Jackson 2.3) support for JSON Pointer expressions with Jackson. So you could alternatively use:
return root.at("/data/data2/value").asText();
First of all, I would recommend consider JSON object binding.
But in case if you get arbitrary JSON objects and you would like process them in the way you described, I would suggest combine Jackson JSON processor along with Apache's Commons Beanutils.
The idea is the following: Jackson by default process all JSON's as java.util.Map instances, meanwhile Commons Beanutils simplifies property access for objects, including arrays and Map supports.
So you may use it something like this:
//actually it is a Map instance with maps-fields within
Object jsonObj = objectMapper.readValue(json, Object.class);
Object hello = PropertyUtils.getProperty(jsonObj, "data.data2.value")
System.out.println(hello); //prints hello
You can use org.json
String json = "{ data: { data2 : { value : 'hello'}}}";
org.json.JSONObject obj = new org.json.JSONObject(json);
System.out.println(obj.query("/data/data2/value"));
I think no way.
Consider a java class
class Student {
Subject subject = new Subject();
}
class Subject {
String name;
}
Here if we want to access subject name then
Student stud = new Student();
stud.subject.name;
We cant access name directly, if so then we will not get correct subject name. Like here:
jsonObject.getAsJsonObject("data")
.getAsJsonObject()
.get("data2")
.getAsJsonObject("value")
.getAsString();
If you want to use same like java object then use
ClassName classObject = new Gson().fromJson(JsonString, ClassName.class);
ClassName must have all fields to match jsonstring. If you have a jsonobject inside a jsonobject then you have to create separate class like I'm doing in Student and Subject class.
Using Java JSON API 1.1.x (javax.json) one can make use of new JavaPointer interface. Instance implementing this interface can be considered to some extend as kind of XPath expression analog (see RFC-6901 for details). So in your case you could write this:
import javax.json.*;
//...
var jp = Json.createPointer("/data/data2/value");
System.out.println(jp.getValue(jsonObject));
In 1.1.4 version of JSON there's also nice addition to JsonStructure interface (which is implemented by JsonObject and JsonArray), namely getValue(String jsonPointer). So it all comes down to this simple one-liner:
System.out.println(jsonObject.getValue("/data/data2/value"));
I want to send POST request to server. I have to pass JSON object as a parameter, and get JSON as a response, but I am getting this error:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [com.package.Response] and content type [application/octet-stream]
Code
Sending request:
#RestService
RestClient restClient;
...
String json = "{\"param\":3}";
restClient.getRestTemplate().getMessageConverters().add(new GsonHttpMessageConverter());
Response res = restClient.send(json);
RestClient
#Rest("http://my-url.com")
public interface RestClient
{
#Post("/something/")
Response send(String json);
RestTemplate getRestTemplate();
void setRestTemplate(RestTemplate restTemplate);
}
I'm using these JAR files:
spring-android-rest-template-1.0.0.RC1
spring-android-core-1.0.0.RC1
spring-android-auth-1.0.0.RC1
gson-2.2.2
What I'm doing wrong? When I change send parameter to JSONObject I am getting the same error.
Btw. AA docs are really enigmatic - can I use Gson anyway? Or should I use Jackson? Which file do I need to include then?
Thanks for any help!
You can use RestTemplate with either Gson or Jackson.
Gson is fine and easier to use of you have small json data set. Jackson is more suitable if you have a complex / deep json tree, because Gson creates a lot of temporary objects which leads to stop the world GCs.
The error here says that it cannot find a HttpMessageConverter able to parse application/octet-stream.
If you look at the sources for GsonHttpMessageConverter, you'll notice that it only supports the mimetype application/json.
This means you have two options :
Either return the application/json mimetype from your content, which would seam quite appropriate
Or just change the supported media types on GsonHttpMessageConverter :
String json = "{\"param\":3}";
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
converter.setSupportedMediaTypes(new MediaType("application", "octet-stream", Charset.forName("UTF-8")));
restClient.getRestTemplate().getMessageConverters().add(converter);
Response res = restClient.send(json);
I just had this problem. After several hours I realised that the class I was passing in to the RestTemplate.postForObject call had Date variables. You need to make sure it only contains simple data types. Hope this helps someone else!
I have to modify it little to work:
final List<MediaType> list = new ArrayList<>();
list.addAll(converter.getSupportedMediaTypes());
list.add(MediaType.APPLICATION_OCTET_STREAM);
converter.setSupportedMediaTypes(list);
I am facing issues with deserialization since I use same object structure for two different web-response. In 'search', I get array of object, and in 'details' I get just one object.
Search Code:
InputStream source = Helper.retrieveStream("http://<domainname>/search.jsp?action=search&q=" + query);
Reader reader = new InputStreamReader(source);
Gson gson = new Gson();
SearchObj searchResponse = gson.fromJson(reader, SearchObj.class);
Details Code:
InputStream source = Helper.retrieveStream("http://<domainname>/search.jsp?action=detail&id=" + id);
From services I get response with same object hireachy TopObject -> SearchResponse -> Response, but in first case (Search) I get array of Response[] and in second case (Details) I get single Response object.
Obiviously, my deserialization fails in second scenario since code is expecting array of Response instead of just one response.
I realized that I can not change name of the object like I can change name of the properties with annotation #SerializedName.
Any suggestion?
Using Gson, to deserialize such JSON that is sometimes an array and sometimes an object would require custom deserialization. This specific issue has been covered in previous StackOverflow threads, such as Parsing JSON with GSON, object sometimes contains list sometimes contains object.