Related
I want to parse a JSON using Java and I managed to do this for the case when I get a response with values from the GET call. My problem comes when the response comes with no values because I get the exception: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of com.footbal.dtoStatistics.Statistics out of START_ARRAY token
at
[Source: (String)"{"api":{"results":0,"statistics":[]}}"; line: 1, column: 34] (through reference chain: com.footbal.dtoStatistics.StatisticsResponse["api"]->com.footbal.dtoStatistics.Api["statistics"])
My JSON without values looks like this:
{
"api": {
"results": 0,
"statistics": []
}
}
My Json with values for which the parsing works looks like this:
{
"api": {
"results": 16,
"statistics": {
"Shots on Goal": {
"home": "3",
"away": "9"
},
"Shots off Goal": {
"home": "5",
"away": "3"
},
"Total Shots": {
"home": "11",
"away": "16"
},
"Blocked Shots": {
"home": "3",
"away": "4"
},
"Shots insidebox": {
"home": "4",
"away": "14"
},
"Shots outsidebox": {
"home": "7",
"away": "2"
},
"Fouls": {
"home": "10",
"away": "13"
},
"Corner Kicks": {
"home": "7",
"away": "4"
},
"Offsides": {
"home": "2",
"away": "1"
},
"Ball Possession": {
"home": "55%",
"away": "45%"
},
"Yellow Cards": {
"home": "0",
"away": "2"
},
"Red Cards": {
"home": null,
"away": null
},
"Goalkeeper Saves": {
"home": "7",
"away": "1"
},
"Total passes": {
"home": "543",
"away": "436"
},
"Passes accurate": {
"home": "449",
"away": "355"
},
"Passes %": {
"home": "83%",
"away": "81%"
}
}
}
}
And the classes I used for the parsing are:
public class StatisticsResponse {
Api api;
public Api getApi() {
return api;
}
public void setApi(Api api) {
this.api = api;
}
}
public class Api {
int results;
Statistics statistics;
public int getResults() {
return results;
}
public void setResults(int results) {
this.results = results;
}
public Statistics getStatistics() {
return statistics;
}
public void setStatistics(Statistics statistics) {
this.statistics = statistics;
}
}
#JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.ANY,
getterVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.NONE)
public class Statistics {
#JsonProperty ("Shots on Goal")
Stats ShotsonGoal;
#JsonProperty ("Shots off Goal")
Stats ShotsoffGoal;
#JsonProperty ("Total Shots")
Stats TotalShots;
#JsonProperty ("Blocked Shots")
Stats BlockedShots;
#JsonProperty ("Shots insidebox")
Stats Shotsinsidebox;
#JsonProperty ("Shots outsidebox")
Stats Shotsoutsidebox;
Stats Fouls;
#JsonProperty ("Corner Kicks")
Stats CornerKicks;
Stats Offsides;
#JsonProperty ("Ball Possession")
StatsPercent BallPossesion;
#JsonProperty ("Yellow Cards")
Stats YellowCards;
#JsonProperty ("Red Cards")
Stats RedCards;
#JsonProperty ("Goalkeeper Saves")
Stats GoalkeeperSaves;
#JsonProperty ("Total passes")
Stats Totalpasses;
#JsonProperty ("Passes accurate")
Stats Passesaccurate;
#JsonProperty("Passes %")
StatsPercent Passes;
public Stats getShotsonGoal() {
return ShotsonGoal;
}
public void setShotsonGoal(Stats shotsonGoal) {
ShotsonGoal = shotsonGoal;
}
public Stats getShotsoffGoal() {
return ShotsoffGoal;
}
public void setShotsoffGoal(Stats shotsoffGoal) {
ShotsoffGoal = shotsoffGoal;
}
public Stats getTotalShots() {
return TotalShots;
}
public void setTotalShots(Stats totalShots) {
TotalShots = totalShots;
}
public Stats getBlockedShots() {
return BlockedShots;
}
public void setBlockedShots(Stats blockedShots) {
BlockedShots = blockedShots;
}
public Stats getShotsinsidebox() {
return Shotsinsidebox;
}
public void setShotsinsidebox(Stats shotsinsidebox) {
Shotsinsidebox = shotsinsidebox;
}
public Stats getShotsoutsidebox() {
return Shotsoutsidebox;
}
public void setShotsoutsidebox(Stats shotsoutsidebox) {
Shotsoutsidebox = shotsoutsidebox;
}
public Stats getFouls() {
return Fouls;
}
public void setFouls(Stats fouls) {
Fouls = fouls;
}
public Stats getCornerKicks() {
return CornerKicks;
}
public void setCornerKicks(Stats cornerKicks) {
CornerKicks = cornerKicks;
}
public Stats getOffsides() {
return Offsides;
}
public void setOffsides(Stats offsides) {
Offsides = offsides;
}
public StatsPercent getBallPossesion() {
return BallPossesion;
}
public void setBallPossesion(StatsPercent ballPossesion) {
BallPossesion = ballPossesion;
}
public Stats getYellowCards() {
return YellowCards;
}
public void setYellowCards(Stats yellowCards) {
YellowCards = yellowCards;
}
public Stats getRedCards() {
return RedCards;
}
public void setRedCards(Stats redCards) {
RedCards = redCards;
}
public Stats getGoalkeeperSaves() {
return GoalkeeperSaves;
}
public void setGoalkeeperSaves(Stats goalkeeperSaves) {
GoalkeeperSaves = goalkeeperSaves;
}
public Stats getTotalpasses() {
return Totalpasses;
}
public void setTotalpasses(Stats totalpasses) {
Totalpasses = totalpasses;
}
public Stats getPassesaccurate() {
return Passesaccurate;
}
public void setPassesaccurate(Stats passesaccurate) {
Passesaccurate = passesaccurate;
}
public StatsPercent getPasses() {
return Passes;
}
public void setPasses(StatsPercent passes) {
Passes = passes;
}
}
try {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
StatisticsResponse apiResponse = mapper.readValue(statisticsResponse, StatisticsResponse.class);
statisticsList = apiResponse.getApi().getStatistics();
Why would it work for the case with values and for the case when I get no values it fails? I cannot see what I did wrong.
Can anyone help me with this parsing?
In your case, Json with values and without values are different. Without values, your JSON is having Statistics as a List. While the other case, it is not a List. Your classes satisfy the second case where there are values. When there are no values, class Api should contain List<Statistics> instead of Statistics.
Ideally, try to follow same structure for both cases. If Statistics never will be list, then change:
{
"api": {
"results": 0,
"statistics": []
}
}
to
{
"api": {
"results": 0,
"statistics": {}
}
}
Else if Statistics will return List, change
{
"api": {
"results": 16,
"statistics": {
"Shots on Goal": {
"home": "3",
"away": "9"
},
"Shots off Goal": {
"home": "5",
"away": "3"
},...
}}}
to
{
"api": {
"results": 16,
"statistics": [{
"Shots on Goal": {
"home": "3",
"away": "9"
},
"Shots off Goal": {
"home": "5",
"away": "3"
},...
}]
}}
A solution to this issue is quite simple: change type of statistics to Object and update getter/setter and untyped mapping will work fine.
class Api {
int results;
Object statistics;
public int getResults() {
return results;
}
public void setResults(int results) {
this.results = results;
}
public Object getStatistics() {
return statistics;
}
public void setStatistics(Object statistics) {
this.statistics = statistics;
}
}
Test code produces expected output:
String emptyStats = "{\n" +
" \"api\": {\n" +
" \"results\": 0,\n" +
" \"statistics\": []\n" +
" }\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//StatisticsResponse apiResponse = mapper.readValue(json, StatisticsResponse.class);
StatisticsResponse apiResponse = mapper.readValue(emptyStats, StatisticsResponse.class);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(apiResponse);
System.out.println(json);
// ----------------
{
"api" : {
"results" : 0,
"statistics" : [ ]
}
}
I have some data which stored on Firebase by using timestamp as its key value,
but I cannot get all of them by sorting it with orderByKey as expected: returning value do not back in ascending order.
My JSON structure looks like:
{
"1476986154" : {
"Cons" : {
"Black" : 91.531099,
"Cancel" : 98.832554,
"Happy" : 97.104925,
"Pair" : 95.515542
},
"Fairy" : {
"Apple" : {
"Chair" : {
"Area" : 1,
"Count" : 96,
"Teen" : 0.162139,
"Score" : 95.16093
},
"Fake" : {
"Area" : 3,
"Count" : 98,
"Teen" : 0.683259,
"Score" : 98.249105
}
},
"Dark" : {
"Lake" : {
"Read" : {
"Height" : 0,
"Width" : 0,
"X" : 0,
"Y" : 0
}
},
"Red" : {
"Read" : {
"Height" : 0,
"Width" : 0,
"X" : 0,
"Y" : 0
}
}
}
},
"PhotoName" : "oo",
"Versions" : {
"Library" : "5.5.6.6"
}
},
"1477280739" : {
"Cons" : {
"Black" : 96.389055,
"Cancel" : 98.265668,
"Happy" : 93.661556,
"Pair" : 91.361142
},
"Fairy" : {
"Apple" : {
"Chair" : {
"Area" : 1,
"Count" : 100,
"Teen" : 0.171286,
"Score" : 90.849593
},
"Fake" : {
"Area" : 3,
"Count" : 99,
"Teen" : 0.200965,
"Score" : 92.367154
}
},
"Dark" : {
"Lake" : {
"Read" : {
"Height" : 0,
"Width" : 0,
"X" : 0,
"Y" : 0
}
},
"Red" : {
"Read" : {
"Height" : 0,
"Width" : 0,
"X" : 0,
"Y" : 0
}
}
},
},
"Name" : "pp",
"Versions" : {
"Library" : "5.5.6.6"
}
}
}
It returns me the largest one first(1490034200), then from smallest to second-largest value(from 1476510510 to 1488805137).
Which confused me since I need to know if the callback is going to the last now.
Code is here: I just query for last data before query for all data with same ValueEventListener:
DatabaseReference.orderByKey().limitToLast(recordQty).addValueEventListener(valueEventListener);
//...
DatabaseReference.orderByKey().addValueEventListener(valueEventListener);
Can anyone understand why this attempt not work?
Here's how my listener looks:
private class ValueEventOnChangeListener implements ValueEventListener {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (mDataArrayList == null) {
mDataArrayList = new ArrayList<>();
} else {
mDataArrayList.clear();
}
getDataChange(dataSnapshot);
if (mListener != null) {
mListener.success(mDataArrayList);
}
}
private void getDataChange(DataSnapshot dataSnapshot){
try {
if (mSubDataType == null){
for (DataSnapshot data : dataSnapshot.getChildren()){
long timestamp = Long.parseLong(data.getKey());
mDataArrayList.add(timestamp);
}
}
}
catch (Exception e){
Log.e(TAG, "onDataChange Exception: " + e.toString());
}
}
}
I can't reproduce the problem.
If I run this snippet of code:
myRef.orderByKey().addValueEventListener(new ValueEventListener() {
public ArrayList<Long> mDataArrayList;
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (mDataArrayList == null) {
mDataArrayList = new ArrayList<>();
} else {
mDataArrayList.clear();
}
getDataChange(dataSnapshot);
System.out.println(mDataArrayList);
}
private void getDataChange(DataSnapshot dataSnapshot){
try {
for (DataSnapshot data : dataSnapshot.getChildren()){
long timestamp = Long.parseLong(data.getKey());
mDataArrayList.add(timestamp);
}
}
catch (Exception e){
System.err.println("onDataChange Exception: " + e.toString());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
With this JSON:
{ "1476986154" : true, "1477280739" : true }
It prints:
[1476986154, 1477280739]
Which seems the correct order to me since 1476986154 < 1477280739.
I have a special need where in I need to query elastic search for a field say F1.
F1 is not there in all documents . My search should be for missing F1 documents and F1 with some value.
F1 is missing or F1 = 'A1'
I am not sure if this is possible in elastic search. Here is my query and I know that is not right query. Would appreciate somebody could correct it or the Java program.
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"must": [
{
"bool": {
"should": {
"terms": {
"F1": [
"Some Value"
]
}
}
}
},
{
"missing": {
"field": "F1"
}
}
]
}
}
}
}
}
This is my java code building the query.
public QueryBuilder getQueryBuilder() {
QueryBuilder qb;
//what do we want to return if there is no request? Nothing or all.
if (filters == null || filters.isEmpty()) {
qb = QueryBuilders.matchAllQuery();
} //build our filtered query using given filters in our request
else {
Set<String> keys = filters.keySet();
BoolFilterBuilder boolFilterBuilder = FilterBuilders.boolFilter();
for (String key : keys) {
Set<Object> values = filters.get(key);
if (values == null || values.toString().isEmpty()) {
continue; //Ignore nothing to do.
}
if (key.equalsIgnoreCase(Constants.MISSING_FILTER)) {
Iterator i = values.iterator();
while (i.hasNext()) {
boolFilterBuilder.must(FilterBuilders.missingFilter((String) i.next()));
}
} else {
boolFilterBuilder.must(buildShouldQuery(key, values));
}
}
qb = QueryBuilders.filteredQuery(createSearchQueryBuilder(), boolFilterBuilder);
}
return qb;
}
Try whit this.
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"should": [
{ "terms": { "F1": ["Some Value"] },
{ "missing": { "field": "F1" } }
]
}
}
}
}
}
I am getting json response in this format.
{
"apiGroups":
{
"Affiliate":
{
"listingsAvailable":
{
"Beauty_Personal_Care":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:586:821655440?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
"Eyewear":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:473:662748456716?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
"Real_Estate":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:897:673143570606?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
"Jewellery":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:6:315773046?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
"Furniture":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:580:1894930153?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
"Tweens_Boys":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:814:934253466?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
"Automobiles":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:1145:639299259208?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
"Home_Improvement":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:864:624389489778?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
"The_Designer_Studio":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:924:655684426383?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
"Fashion_Jewellery":
{
"listingVersions":
{
"v1":
{
"get": "http://affiliate-feeds.snapdeal.com/feed/api/category/v1:1113:672114192240?expiresAt=1446085800024&signature=civtucyhsbufsjzjvqfa"
}
}
},
I need to get categories like beauty personal care, eye ware and their respective urls in get field.How can i loop through this and get the.So far i tried like this and dont no how to proceed next.Can anybody give me suggestions how to parse this json?
json = jParser.getJSONFromUrl(response);
JSONObject api = json.getJSONObject("apiGroups");
JSONObject affiliate = api.getJSONObject("Affiliate");
JSONObject list = affiliate.getJSONObject("listingsAvailable");
You can read the documentation about the JSONObject class in Android.
In this documentation, you will find the method keys that will "Returns an iterator of the String names in this object."
So you just have to call this method and use the iterator.
Iterator<String> keysIterator = jsonObject.keys();
String key;
while (keysIterator.hasNext()) {
key = keysIterator.next();
//use the key to retrieve the data form jsonObject
}
However, if you are the one generating this json, you may consider changing it a bit. The data in the listingsAvailable should probably be in an array.
Here is the object I try to deserialize:
public class DomaineBO {
private String nom;
private Set<String> codesQC;
private Set<String> codesSql;
...
Here are my JSon data:
[
{
"id":30,
"nom":"Usafe",
"gere":true,
"codesQC":[
{
"id":40,
"nom":"ServicesTransversaux",
"nomHTML":"ServicesTransversaux"
},
{
"id":41,
"nom":"%22Services%20Transversaux%22",
"nomHTML":"\"Services Transversaux\""
}
],
"codesSql":[
{
"id":61,
"nom":"USAF"
}
]
},
{
"id":33,
"nom":"Epublishing",
"gere":true,
"codesQC":[
{
"id":45,
"nom":"ServicesDocumentaires",
"nomHTML":"ServicesDocumentaires"
}
],
"codesSql":[
{
"id":64,
"nom":"EDIT"
}
]
},
{
"id":25,
"nom":"Commons",
"gere":true,
"codesQC":[
{
"id":34,
"nom":"Commons",
"nomHTML":"Commons"
}
],
"codesSql":[
{
"id":82,
"nom":"COM"
}
]
},
{
"id":22,
"nom":"Finance",
"gere":true,
"codesQC":[
{
"id":27,
"nom":"%22Refonte%20Contentieux%22",
"nomHTML":"\"Refonte Contentieux\""
},
{
"id":28,
"nom":"Finance",
"nomHTML":"Finance"
},
{
"id":29,
"nom":"%22Refonte%20Finance%20Client%22",
"nomHTML":"\"Refonte Finance Client\""
}
],
"codesSql":[
{
"id":45,
"nom":"FINA"
}
]
},
{
"id":32,
"nom":"Inconnu",
"gere":true,
"codesQC":[
],
"codesSql":[
]
},
{
"id":31,
"nom":"Marketing",
"gere":true,
"codesQC":[
{
"id":42,
"nom":"Marketing_ActionsCom",
"nomHTML":"Marketing_ActionsCom"
},
{
"id":44,
"nom":"Vente",
"nomHTML":"Vente"
},
{
"id":43,
"nom":"Marketing_Produits",
"nomHTML":"Marketing_Produits"
}
],
"codesSql":[
{
"id":63,
"nom":"MARK"
}
]
},
{
"id":26,
"nom":"Facturation",
"gere":true,
"codesQC":[
{
"id":35,
"nom":"Facturation",
"nomHTML":"Facturation"
}
],
"codesSql":[
{
"id":54,
"nom":"FACT"
}
]
},
{
"id":24,
"nom":"Sinistre",
"gere":true,
"codesQC":[
{
"id":32,
"nom":"Sinistre",
"nomHTML":"Sinistre"
},
{
"id":33,
"nom":"Entreprise",
"nomHTML":"Entreprise"
}
],
"codesSql":[
{
"id":47,
"nom":"SINI"
}
]
},
{
"id":23,
"nom":"Partenaire",
"gere":true,
"codesQC":[
{
"id":31,
"nom":"Partenaire",
"nomHTML":"Partenaire"
},
{
"id":30,
"nom":"Partenaires",
"nomHTML":"Partenaires"
}
],
"codesSql":[
{
"id":46,
"nom":"PART"
}
]
},
{
"id":1,
"nom":"Contrat",
"gere":true,
"codesQC":[
{
"id":24,
"nom":"Contrat",
"nomHTML":"Contrat"
}
],
"codesSql":[
{
"id":42,
"nom":"CONT"
}
]
},
{
"id":29,
"nom":"Services Transverses",
"gere":true,
"codesQC":[
{
"id":39,
"nom":"%22Services%20Transversaux%22",
"nomHTML":"\"Services Transversaux\""
},
{
"id":38,
"nom":"ServicesTransversaux",
"nomHTML":"ServicesTransversaux"
}
],
"codesSql":[
{
"id":58,
"nom":"SECU"
},
{
"id":57,
"nom":"DMS"
},
{
"id":60,
"nom":"INDE"
},
{
"id":59,
"nom":"JBPM"
}
]
},
{
"id":28,
"nom":"Flux de données",
"gere":true,
"codesQC":[
{
"id":37,
"nom":"%22Flux%20de%20donn%C3%A9es%22",
"nomHTML":"\"Flux de données\""
}
],
"codesSql":[
{
"id":81,
"nom":"FLUX"
}
]
},
{
"id":27,
"nom":"Reprise",
"gere":true,
"codesQC":[
{
"id":36,
"nom":"Reprise",
"nomHTML":"Reprise"
}
],
"codesSql":[
{
"id":55,
"nom":"FINA"
}
]
},
{
"id":21,
"nom":"Batch",
"gere":true,
"codesQC":[
{
"id":25,
"nom":"Batch",
"nomHTML":"Batch"
}
],
"codesSql":[
{
"id":44,
"nom":"BATCH"
}
]
}
]
And here is how I try to convert them:
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
DomaineBO[] infos = (DomaineBO[]) gson.fromJson(getJSonResponse(url), clazz);
Arrays.asList(infos);
When I am at the operation to convert it in my class DomaineBO, I get the JsonSyntaxException with the message Expected a string but was BEGIN_OBJECT at line 1 column 51 path $[0].codesQC[0]
I supect it is because of the attributes that are Sets of Strings.
I could try to make it with arrays but I wanted to know if there is a better way?
It is because in code you have set of String. Make class CodeQC with fields id, nom, nomHTML and change
Set<String> codesQC
to
Set<CodeQC> codesQC