Group List of Objects to Create an Extended Object List - java

I have these sample records from database which is a result of group by query:
[
{
"name": "Troy",
"acct": 1123,
"type": " Savings",
"total": 50
},
{
"name": "Larry",
"acct": 4233,
"type": " Savings",
"total": 200
},
{
"name": "Troy",
"acct": 1123,
"type": " Current",
"total": 120
},
{
"name": "Larry",
"acct": 4233,
"type": " Current",
"total": 220
}
]
Now, i need to create a report that looks like so:
[
{
"name": "Troy",
"acct": 1123,
"totalSavings": 50,
"totalCurrent": 120
},
{
"name": "Larry",
"acct": 4233,
"totalSavings": 200,
"totalCurrent": 220
}
]
.
public class DbTrans {
private String name;
private String acct;
private String type;
private double total;
// getters and setters
...
}
I have tried using some lambda techniques like the one below, but i'm still not getting close to the solution i desire.
Map<String, List<DbTrans>> collect = transList.stream().collect(
Collectors.groupingBy(f -> f.getType()));

First of all the response Dto is not the same as the request Dto, what I suggest is to create a new Response class lests call it:
public class DbTransResponse {
private String name;
private String acct;
private double totalSavings;
private double totalCurrent;
// getters and setters
}
then the result can be like so :
List<DbTransResponse> result = transList.stream()
.collect(Collectors.groupingBy(DbTrans::getAcct))
.values().stream()
.map(trans -> new DbTransResponse(
trans.get(0).getName(),
trans.get(0).getAcct(),
trans.get(0).getTotal(),
trans.get(1).getTotal()
)).collect(Collectors.toList());
I consider that the list should contain two entries of each name so the you can get totalSavings from the first entry trans.get(0).getTotal() and totalCurrent from the second trans.get(1).getTotal().
If you are not sure you can use conditions to fill your object for example you can check if there are two elements if not set a default value.
Ideone demo
Outputs
DbTransResponse{name='Larry', acct='4233', totalSavings=200.0, totalCurrent=220.0}
DbTransResponse{name='Troy', acct='1123', totalSavings=50.0, totalCurrent=120.0}

you can use Collectors::toMap for this purpose (with a single collect operation)
Map<Integer, DbTransResponse> collect = transList.stream()
.collect(Collectors.toMap(DbTrans::getAcct,
DbTransResponse::new,
DbTransResponse::merge));
Collection<DbTransResponse> result = collect.values();
here is merge method in DbTransResponse class
static DbTransResponse merge(DbTransResponse r1, DbTransResponse r2) {
return new DbTransResponse(
r1.name, r1.acct,
r1.totalSavings + r2.totalSavings,
r1.totalCurrent + r2.totalCurrent
);
}
and an additional constructor for DbTransResponse class, though you can move this logic to a method
DbTransResponse(DbTrans dbTrans) {
this.name = dbTrans.getName();
this.acct = dbTrans.getAcct();
this.totalSavings = "Savings".equals(dbTrans.getType()) ? dbTrans.getTotal() : 0;
this.totalCurrent = "Current".equals(dbTrans.getType()) ? dbTrans.getTotal() : 0;
}
demo

Related

Ruducing a List of objects using Stream.reduce()

I have a list of objects, and I need to group objects having status equal to my customizedStatusto a single customized one with count = sumOfSameObjectsCount .
We have class MyObject
class MyObject {
Integer id;
String name;
String status;
Long count;
//constructor with attributes
//getters
//setters
}
Suggested implementation :
List<MyObject> resultList = listOfObjects.stream()
.collect(Collectors.groupingBy(MyObject::getStatus))
.entrySet().stream()
.map(e -> e.getValue().stream()
.reduce((partialResult,nextElem) ->
{
LOGGER.info("ahaaaa! inside your reduce block ");
if(partialResult.getStatus().equals(customizedStatus)) {
LOGGER.info("equal to my customizedStatus");
return new MyObject(customizedId, customizedName, customizedStatus, partialResult.getCount()+nextElem.getCount());
} else {
LOGGER.info("not equal to my customizedStatus");
return new MyObject(partialResult.getId(), partialResult.getName(), partialResult.getStatus(), partialResult.getCount());
}
}
)
)
.map(f -> f.get())
.collect(Collectors.toList());
Things work like a charm in case there are multiple objects with status equal to my customizedStatus.
Input :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": ZZ,
"name": "nameZZ",
"status": "customizedStatus",
"count": countZZ
},
{
"id": ZZz,
"name": "nameZZz",
"status": "customizedStatus",
"count": countZZz
}
]
Output :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": customizedId,
"name": "customizedName",
"status": "customizedStatus",
"count": countZZ+countZZz
}
]
In case there is one object with status equal to my customizedStatus, need to be customized it too, unfortunately reduce block is being skipped !
Input :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": ZZ,
"name": "nameZZ",
"status": "customizedStatus",
"count": countZZ
}
]
Output :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": ZZ,
"name": "nameZZ",
"status": "customizedStatus",
"count": countZZ
}
]
Expected output :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": customizedId,
"name": "customizedName",
"status": "customizedStatus",
"count": countZZ
}
]
It seems like reduce is executed in case there is multiple objects with same status, if there isn't reduce not being executed at all ! Any thoughts to get the expected output using groupBy and reduce ?
Update
The resulting type is not correct. Because you didn't provide the identity within the reduce() it will return an Optional<Object>, but not an object.
For the same reason (because you are using a flavor of reduce() that doesn't expect identity), the accumulator will have no impact on a single element. A quote from the documentation:
Performs a reduction on the elements of this stream, using an
associative accumulation function, and returns an Optional describing
the reduced value, if any. This is equivalent to:
boolean foundAny = false;
T result = null;
for (T element : this stream) {
if (!foundAny) {
foundAny = true;
result = element;
}
else
result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();
The first encountered stream element would become a partial result and there's no more elements, it would be wrapped by the optional as is and returned.
A possible remedy is to introduce the identity:
public static final Integer customizedId = 99;
public static final String customizedName = "customizedName";
public static final String customizedStatus = "customizedStatus";
public static void main(String[] args) {
List<MyObject> listOfObjects =
List.of(new MyObject(1, "nameXX", "statusXX", 1L),
new MyObject(2, "nameYY", "statusYY", 1L),
new MyObject(3, "nameZZz", "customizedStatus", 3L));
List<MyObject> result =
listOfObjects.stream()
.collect(Collectors.groupingBy(MyObject::getStatus))
.entrySet().stream()
.map(e -> e.getValue().stream()
.reduce(getIdentity(e), (partialResult, nextElem) -> accumulate(partialResult, nextElem)) )
.collect(Collectors.toList());
result.forEach(System.out::println);
}
public static MyObject getIdentity(Map.Entry<String, List<MyObject>> entry) {
return entry.getKey().equals(customizedStatus) ?
new MyObject(customizedId, customizedName, customizedStatus, 0L) :
entry.getValue().iterator().next();
}
public static MyObject accumulate(MyObject result, MyObject next) {
return result.getStatus().equals(customizedStatus) ?
new MyObject(customizedId, customizedName, customizedStatus, result.getCount() + next.getCount()) :
new MyObject(result.getId(), result.getName(), result.getStatus(), result.getCount());
}
Output:
MyObject{id=2, name='nameYY', status='statusYY', count=1}
MyObject{id=1, name='nameXX', status='statusXX', count=1}
MyObject{id=99, name='customizedName', status='customizedStatus', count=3}
You can play around with this Online demo
But keep in mind that it's not the brightest idea to try to crap a lot of conditional logic into stream because it becomes more difficult to read.
Solutions provided below were written before the question was updated, and the problem was clarified. Although, they don't target this specific problem, someone might benefit from them and for that reason I'll preserve them.
Reducing the list into a single object
Is there any solution to make it pass by reduce even listOfObjects entries are different by status ?
In case if you want to reduce a list of objects into a single object with a predefined id, name and status, there's no need to create an intermediate map with Collectors.groupingBy().
If you want to utilize reduce() operation for that, you can accumulate count and then create a resulting object based on it:
That's how it might look like (the type of dummy object was changed to MyObject to avoid confusion with java.lang.Object):
final Integer customizedId = // intializing the resulting id
final String customizedName = // intializing the resulting name
final String customizedStatus = // intializing the resulting status
List<MyObject> listOfObjects = // intializing the source list
MyObject resultingObject = listOfObjects.stream()
.map(MyObject::getCount)
.reduce(Long::sum)
.map(count -> new MyObject(customizedId, customizedName, customizedStatus, 0L))
.orElseThrow(); // or .orElse(() -> new MyObject(customizedId, customizedName, customizedStatus, 0L));
Another way of achieving it is to make use of the fact that MyObject is mutable and utilize it as a container inside the collect() operation:
MyObject resultingObject = listOfObjects.stream()
.collect(() -> new MyObject(customizedId, customizedName, customizedStatus, 0L),
(MyObject result, MyObject next) -> result.setCount(result.getCount() + next.getCount()),
(left, right) -> left.setCount(left.getCount() + right.getCount()));

Run a series of forumulae against key/value pairs stored in a java.util.List

Say I have a List containing components like the following:
[
{
"id": 1,
"name": "Displacement",
"value": 200
},
{
"id": 2,
"name":"Time",
"value": 120
},
{
"id":3,
"name":"Mass",
"value": 233
},
{
"id":4,
"name": "Acceleration",
"value": 9.81
},
{
"id": 5,
"name":"Speed of Light",
"value": 300000000
}
]
Each component is an object of the following class:
class Component {
Integer id;
String name;
Long value;
// necessary getters and setters
}
I need to get the following metrics from the above List:
Velocity (Displacement/Time), Force (Mass * Acceleration) and Energy (Mass * Speed of Light^2)
What is the most of doing this? I could stream the list and filter for the necessary components like so:
Double calculateVelocity() {
Component displacement = list.stream().filter(c -> c.getName().equals("Displacement")).findFirst().orElseThrow(//throw err);
Component time = list.stream().filter(c -> c.getName().equals("Time")).findFirst().orElseThrow(//throw err);
return displacement.value / time.value;
} // repeat for other metrics
This would be tedious as the final implementation would have quite a lot more metrics to calculate at a time. Is there any better way?
Thanks

How to get response in a hashmap

this is the response for a particular query.So i need to take each of the values for checking the value.But I am confused to take each of the values in hashmap.For each values like great ,bad the number of persons increase.So how can i get it in a hashmap.
{
"Great": [
{
"name": "angitha",
"number": "2",
"value": "nice"
},
{
"name": "shiva",
"number": "53",
"value": "it"
}
],
"Okay": [
{
"name": "anita",
"number": "2",
"value": "nice"
},
{
"name": "hansika",
"number": "21",
"value": "nice"
},
{
"name": "angitha",
"number": "24",
"value": "wow"
],
"Bad": [
{
"name": "varun",
"number": "266",
"value": "niceee"
}
]
}
I tried this.The feedback size is getting as three(great,okay,bad...).But the values are not getting..Getting null.And I am new to java hashmap.
public void comments() throws Exception {
Map feedback = value.getBody().jsonPath().get();
for (int i = 0; i < feedback.size(); i++) {
List comments = (List) feedback.get(i);
for (int j = 0; j< comments.size(); i++) {
Map commentseaching = (Map) comments.get(i);
Assert.assertTrue(!commentseaching.get("name").toString().isEmpty());
Assert.assertEquals(commentseach.get("value").toString());
Assert.assertTrue(!commentseaching.get("number").toString().isEmpty());
}
}
}
My code
This code works perfectly.But here I am taking the values based on get("great") like that.Is there any otherway to reduce the repeation.
public void comments() throws Exception{
Map feedback = value.getBody().jsonPath().get();
List comments = (List) feedbackComments.get("Great");
for(int i=0; i<comments.size();i++){
Map commentseaching = (Map) comments.get(i);
Assert.assertTrue(!commentseaching.get("name").toString().isEmpty());
Assert.assertEquals(commentseaching.get("value").toString());
Assert.assertTrue(!commentseaching.get("number").toString().isEmpty());
}
comments=(List) feedbackComments.get("Okay");
for(int i=0; i<comments.size();i++){
Map commentseaching = (Map) comments.get(i);
Assert.assertTrue(!commentseaching.get("name").toString().isEmpty());
Assert.assertEquals(commentseaching.get("value").toString());
Assert.assertTrue(!commentseaching.get("number").toString().isEmpty());
}
comments=(List) feedbackComments.get("Bad");
for(int i=0; i<comments.size();i++){
Map commentseaching = (Map) comments.get(i);
Assert.assertTrue(!commentseaching.get("name").toString().isEmpty());
Assert.assertEquals(commentseaching.get("value").toString());
Assert.assertTrue(!commentseaching.get("number").toString().isEmpty());
}
}
Another approach use this Gson lib in order to easy implement your JSON object
Step 1: you have to create the models for each Root attribute like BAD,Great and Ok
ex:
public class Great{
private String name;
private int number;
private String value;
}
Step 2: you will need to create Some of arrayList of that model like
ArrayList<Great>greatList=new ArrayList()
ArrayList<Bad>badList=new ArrayList()
ArrayList<Ok>okList=new ArrayList()
Step 3: encode json into Java object like this
greatList = gson.fromJson((myJsonResponse.getJSONArray("great")).toString(), new TypeToken<List<Great>>(){}.getType());
okList = gson.fromJson((myJsonResponse.getJSONArray("ok")).toString(), new TypeToken<List<Ok>>(){}.getType());
badList = gson.fromJson((myJsonResponse.getJSONArray("bad")).toString(), new TypeToken<List<Bad>>(){}.getType());
this will produce 3 mapped ArrayList of java object you can now use them as java object
However you have a same syntax with all json attributes so i would prefer to use the same class with publication
for ex:
public class GeneralClass{
private String name;
private int number;
private String value;
}
and then serialize te json object into arrayList of GeneralClass with changing the name of the list only for ex:
ArrayList<GeneralClass>badList =new ArrayList();
ArrayList<GeneralClass>okList =new ArrayList();
ArrayList<GeneralClass>greatList =new ArrayList();

OneToMany Mapping POJO to JSON Spring

I use PostgreSQL and I have these tables, address and company with relation OneToMany on address to company. I want to retrieve a list of addresses which each of them contains a list of companies. I implemented the join between these two tables and I retrieved the data below:
When execute this query:
select ad.id,ad.geolocation, ca.id, ca.name_en, ca.name_el from
address as ad right join company_address as ca on (ad.id = ca.address_id);
I retrieved this table and I want to map it in JSON format as below:
1;"0101000020E6100000C006335CD3043840504BBDB89EC14140"; 6; "Petros";
1;"0101000020E6100000C006335CD3043840504BBDB89EC14140"; 12; "Shop3";
1;"0101000020E6100000C006335CD3043840504BBDB89EC14140"; 13; "Shop3";
7;"0101000020E6100000A03418D984063840D8DD978E94C14140"; 7; "Mike";
7;"0101000020E6100000A03418D984063840D8DD978E94C14140"; 14; "Shop5";
7;"0101000020E6100000A03418D984063840D8DD978E94C14140"; 15; "Shiop8";
9;"0101000020E6100000804127840E163840CC28965B5AC64140"; 10; "Shop2";
9;"0101000020E6100000804127840E163840CC28965B5AC64140"; 11; "Shop3";
Do you know how can convert the results in the format below using an elegant way?
POJO:
private Long id;
private Geolocation geolocation;
private List<ShopObj> shops;
ShopObj Class:
class ShopObj{
private Long id;
private String nameEn;
}
Json Data:
{
"code": "200",
"data": [
{
"id": 1,
"geolocation": "0101000020E6100000C006335CD3043840504BBDB89EC14140",
"shops": [
{
"id": 6,
"nameEn": "Petros"
},
{
"id": 12,
"nameEn": "Shop3"
},
{
"id": 13,
"nameEn": "Shop3"
}
]
},
{
"id": 7,
"geolocation": "0101000020E6100000A03418D984063840D8DD978E94C14140",
"shops": [
{
"id": 7,
"nameEn": "Mike"
},
{
"id": 14,
"nameEn": "Shop5"
},
{
"id": 15,
"nameEn": "Shiop8"
}
]
},
{
"id": 9,
"geolocation": "0101000020E6100000804127840E163840CC28965B5AC64140",
"shops": [
{
"id": 10,
"nameEn": "Shop2"
},
{
"id": 11,
"nameEn": "Shop3"
}
]
}
]
}
Sure.
Create an empty Map<Long, POJO>, containing the POJOs as values, and their ID as keys
Iterate throug your rows.
For each row, get the POJO ID, and get the corresponding POJO from the map. If it's not in the map yet, create the POJO and add it to the map
create a Shop for the current row, and add the shop to the list of shops of the POJOs obtained/created at the previous step
At the end, the values() of the map is the Collection<POJO> that you want to serialize to JSON.
I implemented the code below and worked for my case, but do you know if is there and auto way to map my data?
List<ProductTest> productTests = productRepository.getProductTest();
Map<Long, ProductT> products = new HashMap<Long, ProductT>();
for (ProductTest pt : productTests) {
ProductT productT = products.get(pt.getId());
if (productT == null) {
productT = new ProductT(pt.getId(), pt.getNameEl(), new ArrayList<MediaT>());
products.put(pt.getId(), productT);
}
MediaT mediaT = new MediaT(pt.getMediaId(), pt.getMultimediaPath());
productT.getMediaList().add(mediaT);
}
return products.values();

Expected BEGIN_OBJECT but was STRING - json without key

I'm generally a beginner in Android and json, and I'm stuck on one part and need some help. I'm trying to use Rotten Tomatoes json. I managed read almost everything, except the part where there isn't key in json. Here is the json:
{
"movies": [{
"id": "771359313",
"title": "Dumb and Dumber To",
"year": 2014,
"mpaa_rating": "PG-13",
"runtime": 109,
"critics_consensus": "",
"release_dates": {
"theater": "2014-11-14"
},
"ratings": {
"critics_rating": "Rotten",
"critics_score": 25,
"audience_rating": "Spilled",
"audience_score": 54
},
"synopsis": "Jim Carrey and Jeff Daniels reprise their signature roles as Lloyd and Harry in the sequel to the smash hit that took the physical comedy and kicked it in the nuts: Dumb and Dumber To. The original film's directors, Peter and Bobby Farrelly, take Lloyd and Harry on a road trip to find a child Harry never knew he had and the responsibility neither should ever, ever be given. The Farrelly brothers produce Dumb and Dumber To alongside Riza Aziz and Joey McFarland of Red Granite Pictures. They are joined by fellow producers Charles B. Wessler and Bradley Thomas. Universal Pictures will distribute the film in the United States, Canada and select international territories.(C) Universal",
"posters": {
"thumbnail": "http://content6.flixster.com/movie/11/17/88/11178864_tmb.jpg",
"profile": "http://content6.flixster.com/movie/11/17/88/11178864_tmb.jpg",
"detailed": "http://content6.flixster.com/movie/11/17/88/11178864_tmb.jpg",
"original": "http://content6.flixster.com/movie/11/17/88/11178864_tmb.jpg"
},
"abridged_cast": [{
"name": "Jim Carrey",
"id": "162659418",
"characters": ["Lloyd Christmas"]
}, {
"name": "Jeff Daniels",
"id": "162654392",
"characters": ["Harry Dunne"]
}, {
"name": "Kathleen Turner",
"id": "162658757",
"characters": ["Fraida Felcher"]
}, {
"name": "Rob Riggle",
"id": "770750133",
"characters": ["Travis/Captain Lippincott"]
}, {
"name": "Jennifer Lawrence",
"id": "770800260",
"characters": ["Young Fraida Felcher"]
}],
"alternate_ids": {
"imdb": "2096672"
},
"links": {
"self": "http://api.rottentomatoes.com/api/public/v1.0/movies/771359313.json",
"alternate": "http://www.rottentomatoes.com/m/dumb_and_dumber_to/",
"cast": "http://api.rottentomatoes.com/api/public/v1.0/movies/771359313/cast.json",
"reviews": "http://api.rottentomatoes.com/api/public/v1.0/movies/771359313/reviews.json",
"similar": "http://api.rottentomatoes.com/api/public/v1.0/movies/771359313/similar.json"
}
}, {
"id": "771355766",
"title": "Big Hero 6",
"year": 2014,
"mpaa_rating": "PG",
"runtime": 93,
"critics_consensus": "",
"release_dates": {
"theater": "2014-11-07"
},
"ratings": {
"critics_rating": "Certified Fresh",
"critics_score": 89,
"audience_rating": "Upright",
"audience_score": 94
},
"synopsis": "With all the heart and humor audiences expect from Walt Disney Animation Studios, \"Big Hero 6\" is an action-packed comedy-adventure about robotics prodigy Hiro Hamada, who learns to harness his genius-thanks to his brilliant brother Tadashi and their like-minded friends: adrenaline junkie Go Go Tamago, neatnik Wasabi, chemistry whiz Honey Lemon and fanboy Fred. When a devastating turn of events catapults them into the midst of a dangerous plot unfolding in the streets of San Fransokyo, Hiro turns to his closest companion-a robot named Baymax-and transforms the group into a band of high-tech heroes determined to solve the mystery. (C) Disney",
"posters": {
"thumbnail": "http://content7.flixster.com/movie/11/17/85/11178581_tmb.jpg",
"profile": "http://content7.flixster.com/movie/11/17/85/11178581_tmb.jpg",
"detailed": "http://content7.flixster.com/movie/11/17/85/11178581_tmb.jpg",
"original": "http://content7.flixster.com/movie/11/17/85/11178581_tmb.jpg"
},
"abridged_cast": [{
"name": "Ryan Potter",
"id": "771360315",
"characters": ["Hiro Hamada"]
}, {
"name": "Scott Adsit",
"id": "406975480",
"characters": ["Baymax"]
}, {
"name": "T.J. Miller",
"id": "770690115",
"characters": ["Fred"]
}, {
"name": "Jamie Chung",
"id": "770694653",
"characters": ["Go Go Tomago"]
}, {
"name": "Damon Wayans Jr.",
"id": "770822247",
"characters": ["Wasabi"]
}],
"alternate_ids": {
"imdb": "2245084"
},
"links": {
"self": "http://api.rottentomatoes.com/api/public/v1.0/movies/771355766.json",
"alternate": "http://www.rottentomatoes.com/m/big_hero_6/",
"cast": "http://api.rottentomatoes.com/api/public/v1.0/movies/771355766/cast.json",
"reviews": "http://api.rottentomatoes.com/api/public/v1.0/movies/771355766/reviews.json",
"similar": "http://api.rottentomatoes.com/api/public/v1.0/movies/771355766/similar.json"
}
}],
"links": {
"self": "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json?limit=2&country=us",
"alternate": "http://www.rottentomatoes.com/movie/box-office/"
},
"link_template": "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json?limit={num-results}&country={country-code}"
}
Now, I managed to get name, id, but not the characters. Here are some parts of the code how I got it to work:
public class Movie {
String actor_name;
public Movie(String response, int index) {
Gson gson = new Gson();
MoviesContainer movie = gson.fromJson(response.trim(), MoviesContainer.class);
List < MovieData > movies = movie.movie
AbridgedCastData[] aCast = gson.fromJson(gson.toJson(movies.get(index).abridged_cast), AbridgedCastData[].class);
actor_name = aCast[0].name;
}
}
class MovieData {
Object abridged_cast;
}
class MoviesContainer {
public List < MovieData > movies;
}
class AbridgedCastData {
String name;
String id;
Object characters;
}
I'm using directly index for testing purposes, so actor_name works perfectly.
I tried like this :
CharactersData[] character = gson.fromJson(gson.toJson(aCast[0].characters), CharactersData[].class);
But I'm getting error:
Expected BEGIN_OBJECT but was STRING
I searched everywhere but I can't find how to access characters. How to get for example character Lloyd Christmas? Thanks in advance.
First of all your JSON file is not valid. It should begin with { and end with }. You can check with an online validator such as JSONLint. That's why you get this error.
Secondly if you look at the structure of the file, you see that there is an an array called abridged_cast which contains some objects (which you defined fine in your AbridgedCastData class).
So the final structure could be:
class A {
//contains a list of objects B or an array of objects B
}
class B {
//name
//id
//characters (list of Strings or String array)
}
We are almost done!
When you don't specify a SerializedName annotation, the parser requires that the field name of the attribute you want to serialize must be the same as in the JSON file (otherwise you will end up with a non-initialized value). Since that's not the case you need to add a #SerializedName("abridged_cast") annotation.
Finally you end up with:
public class Test {
public static void main(String[] args) throws FileNotFoundException {
BufferedReader br = new BufferedReader(new FileReader("myJson.json"));
Gson gson = new Gson();
MoviesContainer movie = gson.fromJson(br, MoviesContainer.class);
List<AbridgedCastData> movies = movie.movies;
System.out.println(movies);
}
}
class MoviesContainer {
#SerializedName("abridged_cast")
public List<AbridgedCastData> movies;
}
class AbridgedCastData {
String name;
String id;
List<String> characters;
#Override
public String toString() {
return "AbridgedCastData [name=" + name + ", id=" + id
+ ", characters=" + characters + "]";
}
}
Which outputs:
[AbridgedCastData [name=Jim Carrey, id=162659418, characters=[Lloyd Christmas]], AbridgedCastData [name=Jeff Daniels, id=162654392, characters=[Harry Dunne]], AbridgedCastData [name=Kathleen Turner, id=162658757, characters=[Fraida Felcher]], AbridgedCastData [name=Rob Riggle, id=770750133, characters=[Travis/Captain Lippincott]], AbridgedCastData [name=Jennifer Lawrence, id=770800260, characters=[Young Fraida Felcher]]]
you could change your response and then parse it.
response = "{" + response + "}" ;
// now parse json

Categories

Resources