I have the following pojo:
public class PageRedirect implements Parcelable {
#SerializedName("method") private String method;
#SerializedName("url") private String url;
#SerializedName("parameters") private Parameters parameters;
//#SerializedName("parameters") private String params;
......}
The parameters field is changing depends on some parameter with the originating API. So sometimes it is {} "json object" and if it is empty, it is array []. I know this is a fault in the Backend. But I would like to find a quick work around... Instead of parsing the parameters, I just would like to get it as a string as the commented line and then I will process it. Any ideas?
When creating your instance of Gson, you can set a custom class deserializer as follows:
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Parameter.class, new ParameterTypeAdapter());
final Gson gson = gsonBuilder.create();
PageRedirect pageRedirect = gson.fromJson(yourJsonString, PageRedirect.class);
Then you can create your ParameterTypeAdapter as follows:
public class ParameterTypeAdapter extends TypeAdapter<Parameter> {
#Override
public void write(JsonWriter out, Calendar value) throws IOException {
}
#Override
public Calendar read(JsonReader in) throws IOException {
// do your parsing here
}
You can find more info on it here and here.
EDIT:
If you just want to defer parsing to another moment, you can store your "parameters" field as a JsonElement:
#SerializedName("parameters") private JsonElement parameters;
Afterwards, just convert it to String by using parameters.toString();
Related
I'm trying to deserialize json from worldbank.com to a pojo without any success. The json looks like:
[{"page":1,"pages":7,"per_page":"50","total":304},[{"id":"ABW","iso2Code":"AW","name":"Aruba","region":{"id":"LCN","value":"Latin America & Caribbean "},
and can be found via: http://api.worldbank.org/countries/?format=json
and im running into problems with gson telling me:
WorldBankDemo: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 52 path $[1]
Any clues as to how i can solve this? Preferably without changing from gson since that is the lib used by the networking lib I'm using (retrofit)
WorldBankDataService service = ServiceFactory.createRetrofitService(WorldBankDataService.class, WorldBankDataService.SERVICE_ENDPOINT);
service.getCountries()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<WorldBank[]>() {
#Override
public final void onCompleted() {
// do nothing
}
#Override
public final void onError(Throwable e) {
Log.e("WorldBankDemo", e.getMessage());
}
#Override
public final void onNext(WorldBank[] response) {
Log.d("TAG", "resp: "+response);
//mCardAdapter.addData(response);
}
});
public class ServiceFactory {
/**
* Creates a retrofit service from an arbitrary class (clazz)
* #param clazz Java interface of the retrofit service
* #param endPoint REST endpoint url
* #return retrofit service with defined endpoint
*/
public static <T> T createRetrofitService(final Class<T> clazz, final
String endPoint) {
final RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(endPoint)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
T service = restAdapter.create(clazz);
return service;
}
}
public class WorldBank {
int page;
int pages;
String per_page;
int total;
//Country[] countrys;
}
JSON is not constructed well(especially for auto parsing), Array can contain objects or arrays but not both at same level, in the above JSON structure it starts with Array in that the first element is an object and second element is an array, so this kind of JSON structure is not recommended for auto parsing, if at all you want to continue with same JSON response you can go for manual parsing or change response structure.
It's actually a JSON array. so you can't use class. try this:
YourPojo[] objects = gson.fromJson(jsonString, YourPojo[].class)
works like a charm
try this way
Gson gson = new Gson();
String jsonOutput = "Your JSON String";
Type listType = new TypeToken<List<ApiResponse>>(){}.getType();
List<ApiResponse> posts = (List<ApiResponse>) gson.fromJson(jsonOutput, listType);
and ApiResponse is like
public class ApiResponse{
WorldBank object1;
ArrayList<Country> objects2;
}
I haven't try this on my end, but it will be similar like that.
You can use gson to customize using this dependency
compile 'org.immutables:gson:2.3.1'
But slightly different way while invoking the rest client
For instance .If we have to get a list of countries declare an interface
public interface GetAllAPI {
#GET("/all")
List<Country> getCountries();
}
Now rest client will be
public List<Country> GetAllCountries() {
Gson gson = new GsonBuilder().create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(service_url)
.setConverter(new GsonConverter(gson))
.build();
GetAllAPI service = restAdapter.create(GetAllAPI.class);
List<Country> countrylist = service.getCountries();
return countrylist;
}
Getting the results from API will be
List<Country> countrylist = service.getCountries();
You have to customize this implementation for specific requirement. This is an idea how to implement Gson with Retrofit
Go through this for more clarification
Decided to give up and use another api, the world bank api just sucks :(
In async mode retrofit calls
public void success(T t, Response rawResponse)
were t is the converted response, and rawResponse is the raw response. This provides you with access to both the raw response and the converted response.
In sync mode you can get either the converted response OR the raw response
converted response
#GET("/users/list")
List<User> userList();
raw response
#GET("/users/list")
Response userList();
The Response object does have a method to get the body
TypedInput getBody()
and the retrofit api does have a converter class that can convert this to a java object
Object fromBody(TypedInput body,Type type)
But I can not figure out how to get an instance of the Converter object
I might be able to create an instance of the Converter class, but that would require knowledge of the Gson object used to create the RestAdapter, which I may not have access to. Ideally, I would like obtain a reference to the converter object directly the RestAdpater.
Any of the following will answer my question:
Is there a way to get a reference to the default Converter used by retrofit?
Does anyone know how the default Converter is constructed? (there is no default constructor and there are two Constructors public GsonConverter(Gson gson) and public GsonConverter(Gson gson, String charset)
Is there any other way to get both the raw and converted response in sync mode?
Here's an example of a StringConverter class that implements the Converter found in retrofit. Basically you'll have to override the fromBody() and tell it what you want.
public class StringConverter implements Converter {
/*
* In default cases Retrofit calls on GSON which expects a JSON which gives
* us the following error, com.google.gson.JsonSyntaxException:
* java.lang.IllegalStateException: Expected BEGIN_OBJECT but was
* BEGIN_ARRAY at line x column x
*/
#Override
public Object fromBody(TypedInput typedInput, Type type)
throws ConversionException {
String text = null;
try {
text = fromStream(typedInput.in());
} catch (IOException e) {
e.printStackTrace();
}
return text;
}
#Override
public TypedOutput toBody(Object o) {
return null;
}
// Custom method to convert stream from request to string
public static String fromStream(InputStream in) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String newLine = System.getProperty("line.separator");
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append(newLine);
}
return out.toString();
}
}
Applying this to your request you'll have to do the following:
// initializing Retrofit's rest adapter
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(ApiConstants.MAIN_URL).setLogLevel(LogLevel.FULL)
.setConverter(new StringConverter()).build();
I'm using Google GSON library in my android app to parse json response from server.
In some cases API retrieve html codes in response (e.g »). Is it possible to tell Google GSON to parse that codes and convert to symbol that associated with that code?
Gson does not have anything built in that would do that, no.
The only way to have Gson do this for you would be to write a custom deserializer for String that would decode the strings. You'd also need another library to do the HTML decoding since Java itself doesn't include anything.
Here's an example using the Apache Commons Lang library to do the decoding:
public class App
{
String foo;
public static void main(String[] args) throws MalformedURLException, IOException
{
String json = "{\"Text\":\"«Some message»\"}";
Gson g =
new GsonBuilder()
.registerTypeAdapter(String.class, new MyStringDeserializer()).create();
Type t = new TypeToken<Map<String,String>>(){}.getType();
Map<String,String> map = g.fromJson(json, t);
System.out.println(map.get("Text"));
}
}
class MyStringDeserializer implements JsonDeserializer<String>
{
#Override
public String deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException
{
String s = StringEscapeUtils.unescapeHtml3(je.getAsString());
return s;
}
}
Output:
«Some message»
I'm trying to serialize a list of BasicNameValuePairs using type adapters and Gson
ArrayList<BasicNameValuePair> kvp=new ArrayList<BasicNameValuePair>();
kvp.add(new BasicNameValuePair("car","ferrari"));
kvp.add(new BasicNameValuePair("speed","fast"));
this is the result I want
{"car":"ferrari","speed":"fast"}
instead of this
[{"name":"car","value":"ferrari"},{"name":"speed","value":"fast"}]
To serialize this according to specification you need to make a custom type adapter that will handle the generic list. First create the class that will do the proper formatting on the output.
public class KeyValuePairSerializer extends TypeAdapter<List<BasicNameValuePair>> {
#Override
public void write(JsonWriter out, List<BasicNameValuePair> data) throws IOException {
out.beginObject();
for(int i=0; i<data.size();i++){
out.name(data.get(i).getName());
out.value(data.get(i).getValue());
}
out.endObject();
}
/*I only need Serialization*/
#Override
public List<BasicNameValuePair> read(JsonReader in) throws IOException {
return null;
}
}
Then use a custom Gson builder to use that type adapter to create the proper JSON string.
GsonBuilder gsonBuilder= new GsonBuilder();
gsonBuilder.registerTypeAdapter(KeyValuePairSerializer.class, new KeyValuePairSerializer());
Gson gson=gsonBuilder.create();
Logger.e(getClass().getSimpleName(),gson.toJson(kvp, KeyValuePairSerializer.class));
I'm trying to use GSON to parse some very simple JSON. Here's my code:
Gson gson = new Gson();
InputStreamReader reader = new InputStreamReader(getJsonData(url));
String key = gson.fromJson(reader, String.class);
Here's the JSON returned from the url:
{
"access_token": "abcdefgh"
}
I'm getting this exception:
E/AndroidRuntime(19447): com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2
Any ideas? I'm new to GSON.
The JSON structure is an object with one element named "access_token" -- it's not just a simple string. It could be deserialized to a matching Java data structure, such as a Map, as follows.
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class GsonFoo
{
public static void main(String[] args)
{
String jsonInput = "{\"access_token\": \"abcdefgh\"}";
Map<String, String> map = new Gson().fromJson(jsonInput, new TypeToken<Map<String, String>>() {}.getType());
String key = map.get("access_token");
System.out.println(key);
}
}
Another common approach is to use a more specific Java data structure that matches the JSON. For example:
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class GsonFoo
{
public static void main(String[] args)
{
String jsonInput = "{\"access_token\": \"abcdefgh\"}";
Response response = new Gson().fromJson(jsonInput, Response.class);
System.out.println(response.key);
}
}
class Response
{
#SerializedName("access_token")
String key;
}
Another "low level" possibility using the Gson JsonParser:
package stackoverflow.questions.q11571412;
import com.google.gson.*;
public class GsonFooWithParser
{
public static void main(String[] args)
{
String jsonInput = "{\"access_token\": \"abcdefgh\"}";
JsonElement je = new JsonParser().parse(jsonInput);
String value = je.getAsJsonObject().get("access_token").getAsString();
System.out.println(value);
}
}
If one day you'll write a custom deserializer, JsonElement will be your best friend.
This is normal parsing exception occurred when Pojo key data type is different from json response
This is due to data type mismatch in Pojo class and actually data which comes in the Network api Response
Eg
data class ProcessResponse(
val outputParameters: String,
val pId: Int
)
got the same error due to api gives response as
{
"pId": 1",
"outputParameters": {
"": ""
}
}
Here POJO is outputParameters is String but as per api response its json