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);
Related
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 am using retrofit an get Bad Request , I would want to know if there is a place in this library where builds the full JSON in string format before sending it.
If it's about inspecting the JSON at runtime for debugging purposes, you can call setLogLevel(LogLevel.FULL) on your RestAdapter.Builder.
FULL logs the headers, body and metadata for both requests and responses to logcat.
new String(((TypedByteArray) request.getBody()).getBytes());
In order to build a JSON formatted body, create an object with a class whose properties are the same that you want to send to the server. The GSON Library set up (or whichever library you are using) with the RestAdapter should send the request with the body in JSON format.
Also ensure that the call is #POST annotated and the parameter annotd with #Body Below is an example:
#POST("/login")
User login(#Body LoginUser loginUser);
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?
I'm following this guide - https://github.com/excilys/androidannotations/wiki/Rest%20API and I am trying skip JSON<->POJO conversion and work on pure JSONObject (or gson's JsonObject). What should I write as an server's answer?
#Rest("url")
public interface JsonRest
{
#Get("/getjson")
JSONObject getTime();
// or... ?
#Get("/getjson")
ResponseEntity<JSONObject> getTime();
// or... ?
#Get("/getjson")
JsonObject getTime();
}
In all cases I am getting "{}" as a response, but it's contains correct data after POJO conversion. Which HTTPMessageConverter should I provide? Thanks for any help.
Simply add GsonHttpMessageConverter to RestTemplate and try this:
#Get("/getjson")
JsonElement getSomething();
I don't think this is supported by Spring Android RestTemplate by default. You should probably provide your own provider.
You could look at how GsonHttpMessageConverter is implemented here and then implement your own solution based on that.