HI!
I am working with a .json file, like this:
[{
"SourceFile": "videos/KobeAlleyOop.flv",
"ExifTool": {
"ExifToolVersion": 8.22,
"Warning": "Truncated 'mdat' data"
},
"System": {
"FileName": "KobeAlleyOop.flv",
"Directory": "videos",
"FileSize": "4.8 MB",
"FileModifyDate": "2010:06:15 14:57:24+02:00",
"FilePermissions": "rwxr-xr-x"
},
"File": {
"FileType": "MP4",
"MIMEType": "video/mp4"
}]
I made a Bean with 3 components:
public class MetadataContentBean {
SourceFileBean sourceFileBean;
FileBean fileBean;
SystemBean systemBean;
public FileBean getFileBean() { return fileBean; }
#JsonProperty("File")
public void setFileBean(FileBean fileBean) {
this.fileBean = fileBean; }
public SystemBean getSystemBean() {
return systemBean; }
#JsonProperty("System")
public void setSystemBean(SystemBean systemBean) {
this.systemBean = systemBean; }
public SourceFileBean
getSourceFileBean() {
sourceFileBean.getSource(); return
sourceFileBean; }
#JsonProperty("SourceFile")
public void setSourceFileBean(SourceFileBean
sourceFileBean) {
this.sourceFileBean = sourceFileBean;
} }
And I add an example of SourceFileBean, the others are similar:
public class SourceFileBean {
private String source;
public String getSource() {
return source;
}
#JsonProperty("SourceFile")
public void setSource(String source) {
this.source = source;
}
}
In the main program I make this call:
InputStream is = this.getClass().getClassLoader().getResourceAsStream(filename);
String jsonTxt = IOUtils.toString(is);
JSONArray json = (JSONArray) JSONSerializer.toJSON(jsonTxt);
JSONObject metadatacontent = json.getJSONObject(0);
ObjectMapper mapper = new ObjectMapper(); mapper.readValue(metadatacontent.toString(),MetadataContentBean.class);
But I get this error when I run it, I don't know why:
org.codehaus.jackson.map.JsonMappingException:
Can not construct instance of
com.path.bean.SourceFileBean,
problem: no suitable creator method
found at [Source:
java.io.StringReader#12d7a10; line: 1,
column: 2] at
org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:159)
at
org.codehaus.jackson.map.deser.StdDeserializationContext.instantiationException(StdDeserializationContext.java:212)
at
org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromString(BeanDeserializer.java:415)
at
org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:291)
at
org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:135)
at
org.codehaus.jackson.map.deser.SettableBeanProperty$MethodProperty.deserializeAndSet(SettableBeanProperty.java:221)
at
org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:390)
at
org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:286)
at
org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:1588)
at
org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1116)
at
com.path.parser.JSon.Parser(JSon.java:65)
at
com.path.parser.JSon.main(JSon.java:29)
Any help?? Thanks in advance!
I'm guessing that this is just because your JSON represents an array, with a single object inside it. You're asking Jackson to deserialize this array data onto a single instance of MetadataContentBean, which it can't do.
Try removing the [] brackets from around the JSOn, and try again.
The problem was about sintaxis and the way of writting the fields in my program.
You must be absotuely sure that it is the SAME as in the json file.
On the other hand
"SourceFile": "videos/KobeAlleyOop.flv"
is a field with just one field, so is not neccesary make a bean for it.
It is a stupid error which could make you waist a lot of time!!! :s
One problem is that you have unnecessary code in there: lines 3 and 4 are not needed and could cause issues. So just do:
InputStream is = this.getClass().getClassLoader().getResourceAsStream(filename);
String jsonTxt = IOUtils.toString(is);
ObjectMapper mapper = new ObjectMapper();
MetadataContentBean[] beans = mapper.readValue(metadatacontent.toString(),MetadataContentBean[].class);
so you don't have to use json.org's parser in there. This may not explain exact problem but helps avoid secondary issues.
But the specific problem that throws exception is simple(r): JSON value for type is String, but you are trying to make an Object (bean) out of it.
To make it work, add a public constructor that takes one String argument, and it should work.
You can annotate it with #JsonCreator if you want (or if it's not public constructor), but that should not be necessary.
Conversely, if you want to serialize a bean as JSON String, you need to do something like
#JsonValue public String asString() { return valueOfThisAsString; }
Related
I Have a REST api that contains the data like this way
{
...
... //<- more data here
...
"currencies": {
"BTN": {
"name": "Bhutanese ngultrum",
"symbol": "Nu."
},
"INR": {
"name": "Indian rupee",
"symbol": "₹"
}
}
...
... //<- more data here
...
}
i am doing a project in java where i need to use okhttp and show information about a country from an available rest api and before when i used this api it had all the data in currencies in an data array and that was helpful as you can just get the first zero object from the array , but after they updated the api they made all data in currencies an object and i only want the first object , any way i can get it?
OK, so you have two options here ...
Option 1.
Create two classes like this and use ObjectMapper class to do automatic deserealisation for you.
class CurrencyData {
String name;
String symbol;
}
class CurrencyJsonResponse {
CurrencyData INR;
CurrencyData BTN;
}
public static void main(String[] args) {
OkHttpClient client = // build an instance;
ObjectMapper objectMapper = new ObjectMapper();
ResponseBody responseBody = client.newCall(request).execute().body();
CurrencyJsonResponse currencyResponse = objectMapper.readValue(responseBody.string(), CurrencyJsonResponse.class);
//Get data by using getters on currencyResponse object
}
Option 2
You can write a custom deserealizer by extending the StdDeserializer<T> class. You'll have to programmatically inspect the JsonNode parse tree and assemble the object that you want.
This article explains how to do it and comes with a working code sample
{
"localeCode": "",
"map": {
"DynamicName1": [],
"DynamicName2": [
{
"date": "2016-05-15T00:00:00",
"seqId": 1,
"status": 10
},
{
"date": "2016-05-16T00:00:00",
"seqId": 83,
"status": 10
}
],
"DynamicName3": [],
"DynamicName4": []
},
"respCode": 100,
"respMsg": "success",
"status": 1
}
How to correctly map this kind of json. If you can see that, Dynamic is a dynamic name. So far I have done this :
public class MapModel {
public MapObject map;
public static class MapObject{
public java.util.Map<String, Student> queryStudent;
public static class Student{
public String date;
public String seqId;
public String status;
}
}
}
But when run the app. I'm getting NullPointerException. Can somebody help me?
You're getting the NullPointerException accessing queryStudent of your MapObject inside your MapModel since it's not correctly filled when you're trying to deserialize your Json.
So to solve your problem look at Gson documentation where you can see:
You can serialize the collection with Gson without doing anything
specific: toJson(collection) would write out the desired output.
However, deserialization with fromJson(json, Collection.class) will
not work since Gson has no way of knowing how to map the input to the
types. Gson requires that you provide a genericised version of
collection type in fromJson(). So, you have three options:
Use Gson's parser API (low-level streaming parser or the DOM parser
JsonParser) to parse the array elements and then use Gson.fromJson()
on each of the array elements.This is the preferred approach. Here is
an example that demonstrates how to do this.
Register a type adapter for Collection.class that looks at each of the
array members and maps them to appropriate objects. The disadvantage
of this approach is that it will screw up deserialization of other
collection types in Gson.
Register a type adapter for MyCollectionMemberType and use fromJson()
with Collection.
Since your MapObject containts a java.util.Map but your class itself it's not generic, I think that a good approach for your case is create a Deserializer.
Before this try to clean up your class definition, to provide constructors to make the deserializer easy to build. Your POJO classes could be:
Student class
public class Student{
public String date;
public String seqId;
public String status;
public Student(String date, String seqId, String status){
this.date = date;
this.seqId = seqId;
this.status = status;
}
}
MapObject class
Note: I change you Map definition, since in your Json seems that could be multiple students for each DynamicName (look at DynamicName2 from your question), so I use Map<String,List<Student>> instead of Map<String,Student>:
public class MapObject{
public Map<String,List<Student>> queryStudent;
public MapObject(Map<String,List<Student>> value){
this.queryStudent = value;
}
}
MapModel class
public class MapModel {
public MapObject map;
}
Now create a Deserializer for your MapObject:
public class MapObjectDeserializer implements JsonDeserializer<MapObject> {
public MapObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Map<String,List<Student>> queryStudents = new HashMap<String,List<Student>>();
// for each DynamicElement...
for (Map.Entry<String,JsonElement> entry : json.getAsJsonObject().entrySet()) {
List<Student> students = new ArrayList<Student>();
// each dynamicElement has an Array so convert and add an student
// for each array entry
for(JsonElement elem : entry.getValue().getAsJsonArray()){
students.add(new Gson().fromJson(elem,Student.class));
}
// put the dinamic name and student on the map
queryStudents.put(entry.getKey(),students);
}
// finally create the mapObject
return new MapObject(queryStudents);
}
}
Finally register the Deserializer and parse your Json:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MapObject.class, new MapObjectDeserializer());
Gson gson = builder.create();
MapModel object = gson.fromJson(YourJson,MapModel.class);
DISCLAIMER: For fast prototyping I test this using groovy, I try to keep the Java syntax but I can forget something, anyway I think that this can put you on the right direction.
Hope it helps,
I'm using Jackson and RESTEasy to hook into an external API. The API mainly returns simple objects which I have managed to successfully populate into POJOs.
I'm hitting a problem where I get an array of objects back e.g.
[
{
"variable1": "someValue1",
"variable2": "someValue2",
"variable3": "someValue3"
}
{
"variable1": "someValue4",
"variable2": "someValue5",
"variable3": "someValue6"
}
{
"variable1": "someValue7",
"variable2": "someValue8",
"variable3": "someValue9"
}
]
I have 2 classes: one called VariableObject which looks like this:
public class VariableObject {
private String variable1;
private String variable2;
private String variable3;
}
and VariableResponse which looks like:
public class VariableResponse {
private List<VariableObject> variableObjects;
}
My client uses JAXRS Response class to read the entity into the class i.e
return response.readEntity(VariableResponse.class);
I get a stack trace which reads:
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of VariableResponse out of START_ARRAY token
I understand you can return these as a List of POJOs i.e List quite easily, but this is not what I want to do.
The question really is two parts:
a. Can I possibly populate the VariableResponse POJO using Jackson (some how) preferably without a customer deserialiser? Maybe some annotation exists (this would be ideal)?
b. Is there some way to detect if an Array is being retuned as the root JSON node in the response and then act accordingly?
Help greatly appreciated.
Your JSON is indeed an array of objects.
You can deserialize it with:
response.readEntity(new GenericType<List<VariableObject>>() {});
And then create a new instance of VariableResponse passing resulting List as a constructor parameter like this:
public class VariableResponse {
private final List<VariableObject> variableObjects;
public VariableResponse(List<VariableObject> variableObjects) {
this.variableObject = new ArrayList<>(variableObjects);
}
}
You might forget to add comma after each {..}. After correcting your JSON string, I converted it into ArrayList<VariableObject> using TypeReference and ObjectMapper.
sample code:
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
...
TypeReference<ArrayList<VariableObject>> typeRef = new TypeReference<ArrayList<VariableObject>>() {};
ObjectMapper mapper = new ObjectMapper();
try {
ArrayList<VariableObject> data = mapper.readValue(jsonString, typeRef);
for (VariableObject var: data) {
System.out.println(var.getVariable1()+","+var.getVariable2()+","+var.getVariable3());
}
} catch (Exception e) {
System.out.println("There might be some issue with the JSON string");
}
output:
someValue1,someValue2,someValue3
someValue4,someValue5,someValue6
someValue7,someValue8,someValue9
If you prefer your own response type direct.
Try just extending ArrayList?
public VariableResponse extends ArrayList<VariableObject> {
}
I'm using Gson to parse responses from a server on Android. Each response has some useless (to me) data on it that complicates my Gson models. Here is the general hierarchy of json returned:
response: {
date: 1406253006807,
otherUselessData1: "This is some useless data",
otherUselessData2: "This is some useless data",
usefulJsonObject: { <---- This is really the object that I care about
}
}
Everything above or at the same level as usefulJsonObject I could really do without. The useless data is returned for every request, and the actual response is embedded beneath as the usefulJsonObject. This wouldn't be a big problem but it's really cluttering up my gson model objects.
For example:
Let's say I have 3 requests I can make: A, B, and C. For each response it seems I need to make a minimum of 3 custom classes.
public class ResponseA {
#SerializedName("response") ResponseObjectA responseObject;
public static class ResponseObjectA {
#SerializedName("usefulJsonObject") UsefulObjectA usefulObject;
}
public static class UsefulObjectA {
}
}
I've tried a few solutions, but I haven't found anything elegant that wouldn't add an extra step to my process. I'm using retrofit to do my http requests and it's really nice that it just returns the fully parsed gson object to me. I've thought of other solutions like having the useful object just be a JsonElement and then doing a 2nd gson call after the first comes back. Again, not ideal.
I just wanted to know if I was missing something. Surely I'm not the only one who's encountered something like this, and so I thought I'd ask how other people would handle something like this.
It is initialization Instance value, not NULL value. Check my example.
Address.java
public class Address {
public Address(){
}
}
Person.java
public class Person {
private String name;
private String nrc;
private Address address;
public Person(String name, String nrc, Address address) {
this.name = name;
this.nrc = nrc;
this.address = address;
}
}
The following Json string is equalvent to
Person person = new Person("Zaw Than Oo", "11111", null);
{
"name": "Zaw Than Oo",
"nrc": "11111"
}
The following Json string is equalvent to
Person person = new Person("Zaw Than Oo", "11111", new Address());
{
"name": "Zaw Than Oo",
"nrc": "11111",
"address": {} <-- here use less object for you.
}
Even if you don't create new Instance, Other lib/api(you used) may be create that instance by Reflection.
Short to the Point
{
...
"xxx": {} --> new instance without data/value
...
}
{
...
--> null value
...
}
I never found an elegant way dealing with just Gson. I tried several options with Generics, all of which didn't work or left something to be desired.
Since I'm using Retrofit, I decided to override the GsonConverter, and just filter out the unnecessary information from all my requests. It ends up not being as flexible, as in I can't use the same Retrofit network interface for calls to other servers, but I'm not really doing that, and it also has the down side of having 2 rounds of json parsing calls (meh). You could probably do this more efficiently, but this is working for me for now.
public class CustomGsonConverter extends GsonConverter {
private Gson mGson;
public CustomGsonConverter(Gson gson) {
super(gson);
this.mGson = gson;
}
public CustomGsonConverter(Gson gson, String encoding) {
super(gson, encoding);
this.mGson = gson;
}
#Override public Object fromBody(TypedInput body, Type type) throws ConversionException {
try {
CustomResponse customResponse = mGson.fromJson(new InputStreamReader(body.in()), CustomResponse.class);
return mGson.fromJson(customResponse.responseObject.data, type);
} catch (IOException e) {
throw new ConversionException(e);
}
}
public static class CustomResponse {
#SerializedName("rsp") ResponseObject responseObject;
public static class ResponseObject {
// #SerializedName("date") long date;
#SerializedName("data") JsonElement data;
}
}
}
Maybe there is a better way that I'm just not realizing.
I am using google gson-2.2.1 library for parsing large response of JSON.
I have to parse a JSON response where structure may vary.
First case, when the response contains more than one team:
"Details":{
"Role":"abc",
"Team":[
{
"active":"yes",
"primary":"yes",
"content":"abc"
},
{
"active":"yes",
"primary":"yes",
"content":"xyz"
}
],
Second case, when only one team is passed:
"Details":{
"Role":"abc",
"Team":
{
"active":"yes",
"primary":"yes",
"content":"abc"
}
}
There are my base classes used for parsing:
class Details {
public String Role;
public ArrayList<PlayerTeams> Team = new ArrayList<PlayerTeams>();
PlayerTeams Team; // when JsonObject
}
class PlayerTeams {
public String active;
public String primary;
public String content;
}
The problem is that I can not use ArrayList<PlayerTeams> when I have only one of them and it's returned as JsonObject.
Gson can identify static format of JSON response. I can trace full response dynamically by checking if "Team" key is instance of JsonArray or JsonObject but it would be great if a better solution is available for that.
Edit :
If my response is more dynamic..
"Details":{
"Role":"abc",
"Team":
{
"active":"yes",
"primary":"yes",
"content":"abc"
"Test":
{
"key1":"value1",
"key2":"value2",
"key3":"value3"
}
}
}
In my edited question, I am facing problem while my response is more dynamic..Team and Test can be JsonArray or JsonObject.. It really harassing me because sometime Test object may array when more data, may object when single data, string when no data. There is no consistency in response.
You need a type adapter. This adapter would be able to distinguish which format is coming and instance the right object with the right values.
You can do this by:
implement your own type adapter by creating a class that implements JsonSerializer<List<Team>>, JsonDeserializer<List<Team>>, of course JsonSerializer is just needed in case you need to serialize it in that matter too.
Register the type adapter to you GsonBuilder like: new GsonBuilder().registerTypeAdapter(new TypeToken<List<Team>>() {}.getType(), new CoupleAdapter()).create()
The deserialize method could look like:
public List<Team> deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
throws com.google.gson.JsonParseException {
if (json.isJsonObject()) {
return Collections.singleton(context.deserialize(json, Team.class));
} else {
return context.deserialize(json, typeOfT);
}
}