I am lost in thoughts and tried my best to search and to come up with a possible solution. I have tried most of the answers that could be related to what I am trying to achieve but still no luck.
So to elaborate my question, I am receiving this response from an API
{
"profileList": [
{
"id": "7mmfHGLc0MGtZeQNno/WFqDjlAPj26CS",
"name": "Alexandria Victoria Maxene Kluber van de Gr\\\"oot\""
}
]
}
What I wanted to achieve is to get the "name" field value without the value being escaped. Because on my current setup, what I get from that response after deserialization process is Alexandria Victoria Maxene Kluber van de Gr\"oot""
I let my Retrofit handle the API request and response so that's what I am getting, I currently don't want to tear off my handlers for specific reason, but I am hoping someone could point me in the right direction.
Here is my Retrofit Builder code:
Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.create();
m_builder = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create(gson));
Thank you in advance.
You should try to use JsonPrimitive in your POJO. See below example:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonPrimitive;
import java.io.File;
import java.io.FileReader;
import java.util.List;
public class GsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
Gson gson = new GsonBuilder().create();
System.out.println(gson.fromJson(new FileReader(jsonFile), Profiles.class));
}
}
class Profiles {
private List<Profile> profileList;
// getters, setters, toString
}
class Profile {
private String id;
private JsonPrimitive name;
// getters, setters, toString
}
Above example for your JSON payload prints:
Profiles{profileList=[Profile{id='7mmfHGLc0MGtZeQNno/WFqDjlAPj26CS', name='"Alexandria Victoria Maxene Kluber van de Gr\\\"oot\""'}]}
Related
I'am reading articles about them but it confuses me. What is the difference between the two?
Which is one is better to use?
I have my JSON..how can JACKSON Help me with my parsing?
You cannot compare Jackson and JSON. Jackson is the library for processing JSON data.
Jackson is a multi-purpose Java library for processing JSON data format. Jackson aims to be the best possible combination of fast, correct, lightweight, and ergonomic for developers.
http://wiki.fasterxml.com/JacksonHome
JSON is a data format, Jackson is a Java library for creating and parsing JSON.
Jackson is a library that operate on JSON
JSON stands for javascript object notation and it is a data format
From Wikipedia about JSON:
JavaScript Object Notation, is an open standard format that uses
human-readable text to transmit data objects consisting of
attribute–value pairs. It is used primarily to transmit data between a
server and web application, as an alternative to XML.
From Jackson home page:
Jackson is a:
FAST (measured to be faster than any other Java json parser and data
binder)
Streaming (reading, writing)
Zero-dependency (does not rely on other packages beyond JDK)
Powerful (full data binding for common JDK classes as well as any
Java bean class,
Collection, Map or Enum), Configurable
Open Source (Apache License – or, until 2.1, alternatively LGPL)
Below you can find simple example how to deserialize your JSON data to Java POJO classes:
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
URL osurceUrl = new URL("http://app-dlslsg.azurewebsites.net/json/postList.php");
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
PostList postList = mapper.readValue(osurceUrl, PostList.class);
System.out.println(postList);
}
}
class PostList {
private List<Post> post;
public List<Post> getPost() {
return post;
}
public void setPost(List<Post> post) {
this.post = post;
}
#Override
public String toString() {
return Joiner.on(System.getProperty("line.separator")).join(post);
}
}
class Post {
private int id;
private String body;
private String image;
private Calendar stamp;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public Calendar getStamp() {
return stamp;
}
public void setStamp(Calendar stamp) {
this.stamp = stamp;
}
#Override
public String toString() {
return "Post [id=" + id + ", body=" + body + ", image=" + image + ", stamp=" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(stamp.getTime()) + "]";
}
}
Above program prints:
Post [id=101, body=google, image=http://app-dlslsg.azurewebsites.net/images/google.png, stamp=2013-11-18 12:12:02]
Post [id=61, body=facebook, image=http://app-dlslsg.azurewebsites.net/images/facebook.png, stamp=2013-11-16 13:28:35]
Post [id=111, body=Calendar, image=http://app-dlslsg.azurewebsites.net/images/ical.png, stamp=2013-11-18 12:12:14]
Post [id=121, body=Outlook, image=http://app-dlslsg.azurewebsites.net/images/outlook.png, stamp=2013-11-18 12:12:21]
Post [id=131, body=USG, image=http://app-dlslsg.azurewebsites.net/images/1472825_453923301384770_1942535278_n.jpg, stamp=2013-11-18 12:24:30]
Post [id=231, body=http://dlsu-usg.com/activities/dare-for-10-extended/
WE DARE YOU… To make a change in someone’s life now.
The Office of the Vice President for External Affairs and BLAZE 2013 brings you “DARE FOR TEN" EXTENDED!!!
Your TEN PESOS can make a d, image=http://app-dlslsg.azurewebsites.net/, stamp=2013-11-27 14:47:24]
Post [id=241, body=http://tours.wowbatangas.com/files/2011/01/IMG_6018.jpg, image=http://app-dlslsg.azurewebsites.net/, stamp=2014-01-03 16:06:31]
Post [id=251, body=iTRAVELpost, image=http://app-dlslsg.azurewebsites.net/images/ic_launcher-web.png, stamp=2014-01-10 08:53:19]
I am trying to fix an issue with my RestTemplate PUT request. Basically, the server expects data(an object) to be put in "Raw" content-type but as xml stream.
I tried many combinations(of converter, content-type etc..) but nothing helps. I either end up in getting exception as " org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type com.test.myObject"
Or:
"The server encountered an error processing the request.
The exception message is 'Incoming message for operation 'SendRequest' contains
an unrecognized http body format value 'Xml'. The expected body format value is 'Raw'.
This can be because a WebContentTypeMapper has not been configured on the binding.
".
Any suggestions to fix this will be of great value.
You could provide your own message converter:
Considering that you need to send a custom Content-Type, you will need to create a class that extends AbstractHttpMessageConverter let's say RawHttpMessageConverter. You will need to provide concrete implementations for abstract methods:
supports(...) - feel free to return true
readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage) - here you'll unmarshall your custom object from inputMessage.getBody() InputStream
writeInternal(T t, HttpOutputMessage outputMessage) - here you'll marshall your object T into outputMessage.getBody() OutputStream
Also, very important is to set the list of expected content types: new MediaType("Raw", "8"); and to register into your message converters list.
This is one way of doing it. Another way could be to extend an existing message converter and provide concrete implementations for only what you need. The closest message converter that I can see to your needs (If I understand them correctly) is StringHttpMessageConverter. When providing an implementation you will just create a List of MediaTypes as class variable and add "Raw" type to it - that in constructor. Override getSupportedMediaTypes() and return this list.
When setting up the RestTemplate you will have:
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<AbstractHttpMessageConverter<?>>> converters = new ArrayList<HttpMessageConverter<AbstractHttpMessageConverter<?>>>();
converters.add(new RawHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
To provide more, below is a custom message converter that I am using for Bitmap download:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
public class BitmapMessageConverter implements HttpMessageConverter<Bitmap> {
private static final int BUFFER_SIZE = 8 * 1024;
private List<MediaType> imageMediaTypes;
public BitmapMessageConverter() {
imageMediaTypes = new ArrayList<MediaType>();
imageMediaTypes.add(new MediaType("image", "*"));
imageMediaTypes.add(new MediaType("image", "png"));
imageMediaTypes.add(new MediaType("image", "jpeg"));
}
private boolean isRegisteredMediaType(MediaType mediaType) {
return imageMediaTypes.contains(mediaType);
}
#Override
public List<MediaType> getSupportedMediaTypes() {
return imageMediaTypes;
}
#Override
public Bitmap read(Class<? extends Bitmap> classArg, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
BufferedInputStream bis = new BufferedInputStream(inputMessage.getBody(), BUFFER_SIZE);
Bitmap result = BitmapFactory.decodeStream(bis);
return result;
}
#Override
public void write(Bitmap bitmap, MediaType mediaType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
BufferedOutputStream bos = new BufferedOutputStream(outputMessage.getBody(), BUFFER_SIZE);
bitmap.compress(CompressFormat.JPEG, 100, bos);
}
I am new to android developing, my website returns posts with following format in json:
post= {
'artist':'xxxx',
'title':'xxxx',
'text':'xxxx',
'url':'http://xxxx'
}
I know something about receiving a file from the net and saving it to a SD card, but I want to do it on fly, parse it and show in on some text view, can you please give me some simple code for this?
I tried searching but I can't find a good tutorial for this, so this is the last place I'm coming to solve my problem.
A good framework for parsing XML is Google's GSON.
Basically you could deserialize your XML as follows (import statements left out):
public class Post {
private String artist, title, text, url;
public Post() {} // No args constructor.
}
public class Main {
public static void main(String[] args) {
Gson gson = new Gson();
String jsonString = readFromNetwork(); // Read JSON from network...
Post post = gson.fromJson(jsonString, Post.class);
// Use post instance populated with your JSON data.
}
}
Read more in GSON's user guide.
I'm trying to implement a custom gson serializer/deserialiser for some list of BasicNameValuePair objects.
I saw the partial solution code (for serialization) here:
How do I get Gson to serialize a list of basic name value pairs?
However I wanted to implement also deserialization and I tried my chances and the code is here:
package dto;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.message.BasicNameValuePair;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
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();
}
#Override
public List<BasicNameValuePair> read(JsonReader in) throws IOException {
ArrayList<BasicNameValuePair> list=new ArrayList<BasicNameValuePair>();
in.beginObject();
while (in.hasNext()) {
String key = in.nextName();
String value = in.nextString();
list.add(new BasicNameValuePair(key,value));
}
in.endObject();
return list;
}
}
Code to initialize and fill the list
ArrayList<BasicNameValuePair> postParameters=new ArrayList<BasicNameValuePair>();
postParameters.add(new BasicNameValuePair("some_key","some_value"));
And here is the code to use the new KeyValuePairSerializer class:
GsonBuilder gsonBuilder= new GsonBuilder();
gsonBuilder.registerTypeAdapter(KeyValuePairSerializer.class, new KeyValuePairSerializer());
Gson gson1=gsonBuilder.create();
//serialization works just fine in the next line
String jsonUpdate=gson1.toJson(postParameters, KeyValuePairSerializer.class);
ArrayList<BasicNameValuePair> postParameters2 = new ArrayList<BasicNameValuePair>();
//postParameters2 = gson1.fromJson(jsonUpdate, KeyValuePairSerializer.class); //? how to cast properly
//deserialization throws an error, it can't cast from ArrayList<BasicNameValuePair> to KeyValuePairSerializer
gson1.fromJson(jsonUpdate, KeyValuePairSerializer.class);
The problem is that it throws an exception at the end and I don't know where exactly is the problem and still not sure how to write the last line to get the result back in the new postParameters2 ArrayList.
Adapted from the GSON Collections Examples:
GsonBuilder gsonBuilder= new GsonBuilder();
gsonBuilder.registerTypeAdapter(KeyValuePairSerializer.class, new KeyValuePairSerializer());
Gson gson1=gsonBuilder.create();
Type collectionType = new TypeToken<ArrayList<BasicNameValuePair>>(){}.getType();
ArrayList<BasicNameValuePair> postParameters2 = gson1.fromJson(jsonUpdate, collectionType);
registerTypeAdapter seems to work only for the serializer not for deserializer.
The only way to call the overridden read function of the KeyValuePairSerializer is to call the:
gson1.fromJson(jsonUpdate, KeyValuePairSerializer.class); without saving the result value in a variable. While it will process the function just fine, it will throw an error inside gson class because it will not be able to cast from the ArrayList to the KeyValuePairSerializer. And I kinda understand why (erasure I guess), just don't know how to do it properly.
Anyway I found a workaround to solve this issue.
It seems that instead of registering the gson object and calling registerTypeAdapter and then using gson1.toJson(Object src, Type typeOfSrc) and gson1.fromJson(String json,Class <T> classOfT) I can get away for deserialization with something simpler like:
KeyValuePairSerializer k= new KeyValuePairSerializer();
parametersList = (ArrayList<BasicNameValuePair>)k.fromJson(jsonUpdate);
Both JsonObject's and NameValuePair's behave in a similar way to dictionaries, I don't think you need to convert one into the other if the use case is similar. Additionally JsonObject allows you to treat your values even easier (instead of looping through the array of value pairs to find the key you need to get its value, JsonObject behaves similarly to a Map in a way that you can directly call the name of the key and it'll return the desired property):
jsonObject.get("your key").getAsString(); (getAsBoolean(), getAsInt(), etc).
For your case I'd create a JsonObject from your string, response or stream and then access it as a map (as shown above):
JsonParser parser = new JsonParser();
JsonObject o = (JsonObject)parser.parse("your json string");
I followed this blog for GSON Collection Examples .
Link is simple to understand and implement.
public class TimeSerializer implements JsonSerializer<time> {
/**
* Implementing the interface JsonSerializer.
* Notice that the the interface has a generic
* type associated with it.
* Because of this we do not have ugly casts in our code.
* {#inheritDoc}
*/
public JsonElement serialize(
final Time time,
final Type type,
final JsonSerializationContext jsonSerializationContext) {
/**
* Returning the reference of JsonPremitive
* which is nothing but a JSONString.
* with value in the format "HH:MM"
*/
return new JsonPrimitive(String.format("%1$02d:%2$02d",
time.getHour(), time.getMinute()));
}
Jersey seems to fail when returning JSON...
This:
#GET
#Produces( MediaType.APPLICATION_JSON + ";charset=UTF-8")
public List<MyObject> getMyObjects() {
return ....;
}
is needed to return JSON utf-8 encoded. If I use only
#Produces( MediaType.APPLICATION_JSON)
fails and for example German umlaute (üöä), will be returned in a wrong way.
Two questions:
1 - For JSON utf-8 ist standard - why not with Jersey?
2 - Can I set utf-8 for the whole REST-Servlet if a JSON Request comes in?
I am using Jersey 1.5 and CRest 1.0.1 on Android...
SRGs suggestion works like a charm. However, since Jersey 2.0 the interfaces are slightly different, so we had to adapt the filter a little bit:
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MediaType;
public class CharsetResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response) {
MediaType type = response.getMediaType();
if (type != null) {
String contentType = type.toString();
if (!contentType.contains("charset")) {
contentType = contentType + ";charset=utf-8";
response.getHeaders().putSingle("Content-Type", contentType);
}
}
}
}
I had the same problem : i don't like adding the charset in the "#Produces" tag everywhere.
I found the solution right here : http://stephen.genoprime.com/2011/05/29/jersey-charset-in-content-type.html
Basically, you just have to add a response filter that will add the charset (for example if the content type currently returned is either text, xml or json)
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
import javax.ws.rs.core.MediaType;
public class CharsetResponseFilter implements ContainerResponseFilter {
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
MediaType contentType = response.getMediaType();
response.getHttpHeaders().putSingle("Content-Type", contentType.toString() + ";charset=UTF-8");
return response;
}
}
And to register the filter :
ServletAdapter jerseyAdapter = new ServletAdapter();
jerseyAdapter.addInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.my.package.MyResponseFilter");
Works too with Guice, of course, for example in your class extending ServletModule :
final Map<String, String> parameters = new HashMap<String, String>();
parameters.put("com.sun.jersey.spi.container.ContainerResponseFilters", com.package.JerseyCharsetResponseFilter.class.getName());
serve("/*").with(GuiceContainer.class, parameters);
SRGs and martins solution worked well for me.
However, I had to apply the following changes to the filter:
If the client does a request with an Accept header, Jersey adds a quality factor to the content type. This looks as follows:
No problem: request without Accept header:
curl -i http://www.example.com/my-rest-endpoint
response.getMediaType().toString() is application/json. We can simply append ;charset=utf-8.
Problem: request with Accept header:
curl -i -H "Accept: application/json" http://www.example.com/my-rest-endpoint
response.getMediaType().toString() is {application/json, q=1000}. We cannot simply append ;charset=utf-8, since this would lead to the following exception:
java.lang.IllegalArgumentException: Error parsing media type '{application/json, q=1000};charset=utf-8'
at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:92) ~[na:na]
at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:60) ~[na:na]
at javax.ws.rs.core.MediaType.valueOf(MediaType.java:179) ~[na:na]
...
Caused by: java.text.ParseException: Next event is not a Token
at org.glassfish.jersey.message.internal.HttpHeaderReader.nextToken(HttpHeaderReader.java:129) ~[na:na]
at org.glassfish.jersey.message.internal.MediaTypeProvider.valueOf(MediaTypeProvider.java:110) ~[na:na]
at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:90) ~[na:na]
... 193 common frames omitted
I'd suggest the following code to solve this problem:
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MediaType;
public class CharsetResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response) {
MediaType type = response.getMediaType();
if (type != null) {
if (!type.getParameters().containsKey(MediaType.CHARSET_PARAMETER)) {
MediaType typeWithCharset = type.withCharset("utf-8");
response.getHeaders().putSingle("Content-Type", typeWithCharset);
}
}
}
}