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]
Related
Complete base 64 string is not uploding to json request
Actual json request is:
{
"obj":
{
"FarmerName":"abcd",
"IdAgent":"123",
"TPFileUpload":"_9j_4AAQSkZJRgABAQAAAQABAAD_2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFx..............",
"TPFileUploadType":"jpg"
}
}
But From code json request as follows:
{"obj":{"FarmerName":"","
IdAgent":"",
"TPFileUpload":"_9j_4AAQSkZJRgABAQAAAQABAAD_2wBDABALDA4MChAODQ4
Issues are:
1)json is not closed
2)base 64 string of image is not completely uploading to json request.
3)The parameter after "TPFileUpload" are not adding to json request because
of Base 64 encoded string of image.
Service Request as follows:
#Headers("Content-Type: application/json")
#POST("service/saveinput")
Call<SaveInputResponse> saveInput(#Body SaveInput saveinput);
saveInput pojo class:
public class SaveInput {
#SerializedName("obj")
#Expose
private Input obj;
public Input getObj() {
return obj;
}
public void setObj(Input obj) {
this.obj = obj;
}
}
Input class:
public class FooInput {
#SerializedName("FarmerName")
#Expose
private String farmerName;
#SerializedName("IdAgent")
#Expose
private String idAgent;
#SerializedName("TPFileUpload")
#Expose
private String tPFileUpload;
#SerializedName("TPFileUploadType")
#Expose
private String tPFileUploadType;
//Getters and setters of Variables...
}
I have tried the request using retrofit library and also with volley library,but no result,can you please provide suggestion to upload base64 string to json request in android.and some times "/" is replaced by "_"base64 string of request...
Note:base64 encode string is too large i.e,more than 180 lines..
I am also using this. I add my code. May help this.
01. First get your image and convert it base64.
02. Http request with Json format.
[
{
"attachment": "Your base64 String",
"clients": {
"CLIENTS_ID": "18081000000120"
},
"projects": {
"PROJECT_ID": "18081000000306"
},
"userCode": "18011000000027"
}
]
I am trying to get the CompanyEndpoint for each client's site but I am confused with the use of retrofit on the interface.
Here's what I have so far:
CompanyName : "company1"
CompanyEndpoint : "https://example.com"
IdentityEndpoint : "https://example.com/identity"
AppLoginMode : "Anonymous"
AppRouterApi.java
public interface AppRouterApi {
#GET("api/sites/{CompanyName}")
Call<Company> getCompanyName (#Url String companyName);
}
Company.java
public class Company {
String Endpoint;
public String getEndpoint() {
return endpoint;
}
}
MainActivity.java
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
appRouterApi = retrofit.create(AppRouterApi.class);
getCompany();
}
private void getCompany(){
retrofit2.Call<Company> companyRequest = appRouterApi.getCompanyName(); //Error here saying a string cant be applied to ()
companyRequest.enqueue(new retrofit2.Callback<Company>() {
#Override
public void onResponse(retrofit2.Call<Company> call, retrofit2.Response<Company> response) {
if(!response.isSuccessful()){
textViewResult.setText("Code:" + response.code());
return;
}
Company company = response.body();
String content = "";
content += "Url" + company.getEndpoint();
textViewResult.setText(content);
}
#Override
public void onFailure(retrofit2.Call<Company> call, Throwable t) {
}
});
}
https://example/sites/{companyName}
So if I search for:
https://example/sites/company1
The JSON will have one object and I need to get the endpoint URL value which would be: https://company1.com
Edit: My textViewReslt is returning 403
There are several things going on as far as I can tell. Let me break it into chunks.
First thing is you're confusing the annotation #Path with the annotation #Url. They serve different purposes.
You use #Path when you want to format a bit of the path into the url inside the annotations like #GET.
public interface AppRouterApi {
#GET("api/sites/{CompanyName}")
Call<Company> getCompanyName (#Path("CompanyName") String companyName);
}
This interface will format the argument passed to getCompanyName as part of the path. Calling getCompanyName("foo") will call the endpoint "https://example.com/api/sites/foo".
You use #Url when you want to simply call that url. In this case, you only annotate the interface method with the http method. For example,
public interface AppRouterApi {
#GET
Call<Company> getCompanyName (#Url String url);
}
You then would have to call the method with the entire url. To call the same url as before you'd have to call getCompanyName("https://example.com/api/sites/foo").
This is the main difference of usage between these 2 annotations. The reason why you're seeing null in your text view is because you're model's attribute name doesn't match the json. You have 2 options.
First, you can change the model to:
public class Company {
String CompanyEndpoint;
public String getEndpoint() {
return endpoint;
}
}
CompanyEndpoint is the exact same name as you have in the json. Another approach, is to tell your json serializer what name you want to use. Since you're using gson, you can use #SerializedName like so:
public class Company {
#SerializedName("CompanyEndpoint")
String Endpoint;
public String getEndpoint() {
return endpoint;
}
}
#SerializedName("CompanyEndpoint") tells gson which name to use while serializing and deserializing.
In essence, you have 2 options. You either use the endpoint, or the company's name. If you don't expect the domain to change, I'd suggest using the first approach with the #Path annotation. This is what it's usually done with Retrofit and personally, I think it's easier to handle than passing urls around. My suggestion is, use a model like:
public class Company {
#SerializedName("CompanyName")
String name;
public String getName() {
return name;
}
}
This would let you access the company's name property and call getCompanyName(company.getName()). Retrofit would format the company's name into the path and you'd call the right url.
I've been using Retrofit 2 with some POJO objects for a while now. It's a lovely library and works very well, but it's necessitating some horrendous and messy models that I want to get rid of.
I'll show you... I have the following JSON to peruse:
{
"things": [
{
"thing": {
"id": 823,
"created_at": "2016-02-09T22:55:07.153Z",
"published_at": "2016-02-10T19:23:42.666Z",
"downloads": 16073,
"size": 10716291
}
},
],
"count": 4,
"links": {}
}
Using the POJO Schema generator this creates unnecessary classes that make maintaining code hard to do.
This would create:
Things.java
#SerializedName("things")
#Expose
public List<Things_> things = new ArrayList<>();
Things_.java
#SerializedName("thing")
#Expose
private Thing__ thing;
Things__.java
// Insert normal variables and getter/setters here
I've reduced that down a little as it's just for the idea. In my usage I have of course renamed these classes to make them more managable. But I figured there was a way of simply skipping over Thing and Thing_ and allowing me to just return a list of the actual model data (Thing__) and this two of those classes could be removed and "Thing__" could simple be "Thing".
I was right. Gson allows custom deserialization that lets me achieve this end. I threw together a quick Deserializer and used an appropriate TypeToken
Gson gson = new GsonBuilder()
.registerTypeAdapter(new TypeToken<ArrayList<Thing>>(){}.getType(), new AddonDeserializer())
.create();
List<Thing> model = gson.fromJson(jsonString, new TypeToken<ArrayList<Thing>>(){}.getType());
Sure enough, passing this that exact Json above give me a List of Things that were usable.
Enter Retrofit 2! Having added the registerTypeAdapter() to my Retrofit 2 instance (via my gson instance) I now get an error message:
Expected BEGIN_ARRAY but was BEGIN_OBJECT
This is because, probably, my call is:
#Get("end/of/url/here/{slug}.json")
Call<List<Thing>> getThings(#Path("slug") String slug);
My Json starts with an object ("things") which contains an array of "thing" objects. My deserializer had no issues with this:
public class ThingDeserializer implements JsonDeserializer<List<Thing>> {
#Override
public List<Thing> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonArray array = json.getAsJsonObject().getAsJsonArray("things");
ArrayList<Thing> list = new ArrayList<>();
for (JsonElement anArray : array) {
list.add((Thing) context.deserialize(anArray.getAsJsonObject().get("thing").getAsJsonObject(), Thing.class));
}
return list;
}
}
Anyway, thanks for sticking with this very long question!
What do I need to do differently or how can I manipulate Retrofit to act the same as the Gson Deserializer I wrote? What I have works, but in the interests of learning something new and writing nicer and more maintainable code I want to figure this out. I could just resort to using ResponseBody callbacks and throwing the Json through my Deserializer but there has to be a better method.
Thanks to #JonathanAste I figured it out.
Instead of a Deserializer, I needed a TypeAdapterFactory implementation.
public class ThingTypeAdapterFactory implements TypeAdapterFactory {
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<T>() {
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}
public T read(JsonReader in) throws IOException {
JsonElement jsonElement = elementAdapter.read(in);
if (jsonElement.isJsonObject()) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
if (jsonObject.has("things") && jsonObject.get("things").isJsonArray())
{
jsonElement = jsonObject.get("things");
}
}
if (jsonElement.isJsonObject()) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
if (jsonObject.has("thing") && jsonObject.get("thing").isJsonObject())
{
jsonElement = jsonObject.get("thing");
}
}
return delegate.fromJsonTree(jsonElement);
}
}.nullSafe();
}
}
And this allows you to then use
#GET("end/of/url/here/{slug}.json")
Call<List<Thing>> getThings(#Path("slug") String slug);
Without issue.
I am using RestTemplate for android client. I am using Simple XML annotated object and same java object with JaxB annotation on server side. I am successful in sending/recieving String and other primitive types but for byte array having problems. The byte array I am sending from Simple XML is converted to something else when I see on JaxB side on server. Below is the code..
JaxB annotated object on REST server
import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Device implements Serializable
{
private final static long serialVersionUID = 1L;
protected byte[] imageRef;
public Device() {
super();
}
public byte[] getImageRef() {
return imageRef;
}
public void setImageRef(byte[] imageRef) {
this.imageRef = imageRef;
}
}
Here is how the Rest server looks like.. I am using Apache CXF for that.
<bean id="xmlBeanProvider" class="org.apache.cxf.jaxrs.provider.XMLBeansElementProvider"/>
<bean id="jacksonJsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>
<jaxrs:server id="dataRESTService" address="/">
<jaxrs:serviceBeans>
<ref bean="MyDataRESTService"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="xmlBeanProvider"/>
<ref bean="jacksonJsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
<context:component-scan base-package="com.xxx.restservices" />
and the controller
#Path("/mydata")
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_XML)
#Service
public class MyDataRESTService
{
#POST
#Path("/testpost")
public String testPost(Device device)
{
//device.getImageRef() returns [-41, 109, -8] for the bytes
}
}
Here is how the Android client side looks
Simple XML Annotated object on Android
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
#Root
public class Device implements Serializable
{
private final static long serialVersionUID = 1L;
#Element
protected byte[] imageRef;
public Device() {
super();
}
public byte[] getImageRef() {
return imageRef;
}
public void setImageRef(byte[] imageRef) {
this.imageRef = imageRef;
}
}
RestTemplate client with Simple XML converters
public void testPost()
{
RestTemplate restTemplate = new RestTemplate();
Serializer serializer = new Persister();
restTemplate.getMessageConverters().add(new SimpleXmlHttpMessageConverter(serializer));
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
Device device = new Device();
device.setImageRef(new byte[]{1,2,3,4,5});
String response = restTemplate.postForObject("http://10.0.0.3:8080/rest/mydata/testpost", device, String.class);
assertNotNull(response);
}
So basically when I send byte array of byte[]{1,2,3,4,5} on server I get this byte array [-41, 109, -8]. I tried to decode with Base64 on server side thinking that may be simple xml is encoding it but couldn't figure out what is going on?
Similarly if I do a Get operation instead of Post then I get a NumberFormat exception in android client.. org.springframework.http.converter.HttpMessageNotReadableException Caused by: java.lang.NumberFormatException: Invalid int: "AQ=="
at java.lang.Integer.invalidInt(Integer.java:138)
at java.lang.Integer.parse(Integer.java:375)
at java.lang.Integer.parseInt(Integer.java:366)
at java.lang.Byte.parseByte(Byte.java:214)
at java.lang.Byte.parseByte(Byte.java:195)
at java.lang.Byte.valueOf(Byte.java:264)
at org.simpleframework.xml.transform.ByteTransform.read(ByteTransform.java:55)
Any help will be greatly appreciated.
I followed up on #Blaise Doughan advice to write a custom converter. I wrote one on Simple XML side. However it is only working for sending data to server but for receiving it doesn't work.
Here is how the converter looks. I think this may be a Simple XML issue and as such the answer to this post is that we have to write a custom converter. I posted a follow-up question for Simple XML guys to see why the read method is not called when we serialize the xml back to object? See the question here custom converter for simple xml is not working properly
I put a break point in the read method and looks like it was never called. Simple XML parser fails way before this exception org.springframework.http.converter.HttpMessageNotReadableException: Could not read [class cs.core.mobile.database.JaxBResponse]; nested exception is java.lang.NumberFormatException: Invalid int: "AAECAwQ="
import org.restlet.engine.util.Base64;
import org.simpleframework.xml.convert.Converter;
import org.simpleframework.xml.stream.InputNode;
import org.simpleframework.xml.stream.OutputNode;
public class ByteArrayConverter implements Converter<byte[]>
{
#Override
public byte[] read(InputNode node) throws Exception
{
String value = node.getValue();
return Base64.decode(value);
}
#Override
public void write(OutputNode node, byte[] byteArray) throws Exception
{
node.setValue(Base64.encode(byteArray, false));
}
}
Yay... I got it working. phew.. So I wrote this ByteArrayConverter in simple xml. I created a wrapper class around byte[] called ByteArrayWrapper and replace Converter with Converter
public class ByteArrayConverter implements Converter<ByteArrayWrapper>
{
#Override
public ByteArrayWrapper read(InputNode node) throws Exception
{
InputNode nextnode = node.getNext();
return new ByteArrayWrapper(Base64.decode(nextnode.getValue()));
}
public void write(OutputNode node, ByteArrayWrapper byteArray) throws Exception
{
OutputNode byteArrayNode = node.getChild("byteArray");
byteArrayNode.setValue(Base64.encode(byteArray.getByteArray(), false));
}
}
Here is my simple ByteArrayWrapper class
#Root
public class ByteArrayWrapper
{
#Element
protected byte[] byteArray;
public ByteArrayWrapper()
{
super();
}
getters..
setters..
}
Here is how the Device class looks
#Root
public class Device implements Serializable
{
private final static long serialVersionUID = 1L;
#Element
#Convert(ByteArrayConverter.class)
private ByteArrayWrapper imageRef;
public Device() {
super();
}
public ByteArrayWrapper getImageRef() {
return imageRef;
}
public void setImageRefByteArrayWrapper imageRef) {
this.imageRef = imageRef;
}
}
and finally the RestTemplate client
public void testPost()
{
RestTemplate restTemplate = new RestTemplate();
Strategy strategy = new AnnotationStrategy();
Serializer serializer = new Persister(strategy);
restTemplate.getMessageConverters().add(new SimpleXmlHttpMessageConverter(serializer));
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
Device device = new Device();
device.setImageRef(new byte[]{1,2,3,4,5});
String response = restTemplate.postForObject("http://10.0.0.3:8080/rest/mydata/testpost", device, String.class);
assertNotNull(response);
}
Everything is working great! Thanks #Blaise Doughan for your pointer.
A JAXB implementation will expect a byte[] to be represented as base64Binary in the XML. Based on your comment Simple XML has the following representation for byte[].
<imageRef length="5">1, 2, 3, 4, 5</imageRef>
You will need to choose whether you want to use the base64Binary representation from JAXB, or the proprietary representation from Simple XML and use an adapter/converter for the other side to make it understand the representation you choose.
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.