Parsing json with gson and java - java

I am struggling to parse a json output with Java and gson, but I am really stuck.
I would appreciate any suugestion.
This is my sample JSON file:
{
"sportId": 29,
"last": 26142386,
"league": [
{
"id": 1833,
"events": [
{
"id": 383911973,
"starts": "2015-01-22T21:00:00Z",
"home": "America de Natal",
"away": "Barras",
"rotNum": "901",
"liveStatus": 0,
"status": "O",
"parlayRestriction": 0
},
{
"id": 383911974,
"starts": "2015-01-22T21:00:00Z",
"home": "Baraunas RN",
"away": "ASSU RN",
"rotNum": "904",
"liveStatus": 0,
"status": "O",
"parlayRestriction": 0
}
]
}
]
}
My target is to a make a 2-dimensional array (or something similar) of the form:
leagueId, eventId, home, away
------------------------------
1 1 a b
. . . .
. . . .
etc etc etc etc
in order to insert the data in a MYSQL table.
I have write the following classes:
public class Fixtures {
int last;
int sportId;
ArrayList<Leagues> league = new ArrayList<Leagues>();
public ArrayList<Leagues> getListOfLeagues() {
return league;
}
public int getSportId(){
return sportId;
}
public int getLast(){
return last;
}
}
public class Leagues {
int id;
ArrayList<Events> events;
public int getLeagueId(){
return id;
}
public ArrayList<Events> getListOfEvents() {
return events;
}
}
public class Events {
int id;
String home;
String away;
public int getEventId(){
return id;
}
public String getHome() {
return home;
}
public String getAway() {
return away;
}
}
and
Gson gson = new GsonBuilder().create();
Fixtures fixture = gson.fromJson(jsonsource, Fixtures.class);
System.out.println(fixture.getSportId());
System.out.println(fixture.getLast());
ArrayList<Leagues> Leagues = fixture.getListOfLeagues();
Dont know how to proceed :(

The real answer here is to not do it this way.
Have you looked at Hibernate? It's like Entity for C#. It allows you to interact with your relational database as an object oriented entity structure, which is how we're used to thinking about things.
Typically, when you have a set of data as input and need to put that data in a database, you need to make a few considerations:
Does my input properly represent how my data is stored?
Does my relational model (database) represent how my data is used?
If one or both of these is a "no", can I change either of them to make them true?
If your model is good and your input is good (which your input looks fine), then you should have no need to put your data into an intermediate layer, you should be able to loop over the applicable fields and put the data in your database. If you can't do that, I'd recommend restructuring your database. Again, I know this is kind of a sideways answer, but you did ask for suggestions :)

Try jackson to parse JSON to java object, you get some help from here where a similar JSON was parsed to couple of java objects.
JSON parsing example using jackson
Try it and let me know if you find any issue.

Ok, I figured out how to do the iteration:
for (Leagues leg : Leagues) {
System.out.println(leg.getLeagueId());
ArrayList<Events> Events = leg.getListOfEvents();
for (Events event : Events) {
System.out.println(event.getEventId());
System.out.println(event.getHome());
System.out.println(event.getAway());
System.out.println(event.getStarts());
}
}
Thanks all.

Related

Serializing JSON object containing nested objects with dynamic property names with Jackson

I have been struggling with this, and I can't seem to get it right. I have a Java Spring Boot project and I need to create an API that returns the following JSON in what I called AggregatedResponse:
{
"shipments": {
"987654321": ["BOX", "BOX", "PALLET"]
},
"track": {
"123456789": "COLLECTING"
},
"pricing": {
"NL": 14.242090605778
"CN": 20.503467806384
}
}
Each of the objects (shipments, track, pricing) need to be fetched from an external API.
This means that I need to create the AggregatedResponse and use a setter whenever I'm receiving the different data from the external APIs.
The number in the shipments (987654321) comes from the request param passed to the external API that retrieves shipments. The track number (123456789) also comes from an external API.
This is the Java structure I have so far:
public class AggregatedResponse {
private TrackResponse tracking;
private ShipmentsResponse shipments;
private PricingResponse pricing;
public ShipmentsResponse getShipments() {
return shipments;
}
public void setShipmentsResponse(ShipmentsResponse value) {
this.shipments = value;
}
public TrackResponse getTrackResponse() {
return tracking;
}
public void setTrackResponse(TrackResponse trackResponse) {
this.tracking = trackResponse;
}
public PricingResponse getPricing() {
return pricing;
}
public void setPricing(PricingResponse value) {
this.pricing = value;
}
}
The problem I have is that like I mentioned, the shipments and track JSON object have dynamic names, so I have tried different strategies for creating the TrackResponse and the ShipmentsResponse.
How could I do this?
Create a Map from the data instead of class so you can define the keys and serialize it.

creating a POJO containing only some elements from the response

I'm trying to read from a JSON response using a pojo. The response has many attributes but I only need few, I created the POJO with only those attributes, but when I'm trying to read it. it fails to parse it.
JSON response:
[
{
"attr_1":1,
"attr_2":2,
"attr_3":3,
"attr_4":4,
"attr_5":5,
},
{
"attr_1":10,
"attr_2":20,
"attr_3":30,
"attr_4":40,
"attr_5":50,
}
]
my POJO:
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyPOJO {
#JsonProperty("attr_2")
private int attr_2;
#JsonProperty("attr_4")
private int attr_4;
public int getattr_2() { return attr_2; }
public void setattr_2(int attr_2) { this.attr_2 = attr_2;}
public int getattr_4() { return attr_4; }
public void setattr_4(int attr_4) { this.attr_4 = attr_4;}
}
I only need attr_2 and attr_4, and not the others.
this is how I'm trying to read the response:
MyPOJO[] arr = response.readEntity(MyPOJO[].class);
but it fails at this step. do we really need to have all the attributes in my POJO as there are many and I need few attributes, don't want to have redundant code?
I was able to solve the issue. I created an empty constructor and it worked. previously I had a constructor with the two needed attributes only.

How to update array List of object at particular index in the collection in java

public Class Customer{
private long id;
private String name;
private String companyName;
private List<Environment> environment = new ArrayList<>();
}
public Class Environment{
private int clusterid;
private string clusterName
}
My Collection in Mongo DB
{
"id":1,
"name":"xyz",
"companyName":"abc",
"environment":[
{
"clusterid":2,
"clusterName":"qwe"
},
{
"clusterid":6,
"clusterName":nme"
}
]
}
want to update environment List of index 1 with returning whole environment List. How do I do this with spring boot? I want to update particular index of list fetching other too in the collection .
public int updateEnv(Customer customer) {
Query query = new Query();
query.addCriteria(Criteria.where("id").is(customer.getid()));
Update update = new Update();
update.set("environment", customer.getEnvironment());
return mongoUtil.update(query, update, Customer.class);
}
This query updating the whole environment List with the value in the list instead of at particular index. Please guide about positional operator .How to do this with positional operator in java
You should be able to just pass the index to the update query. So if you want to update/replace the element at index 1, you can do:
update.set("environment.1", customer.getEnvironment())
Try this updated query.
Updated Mongo Playground
db.collection.update({
id: 1/**customer id*/
},
{
"$set": {
"environment.$[element]": {
"clusterId": 4,
/**environment object with updated clusterId*/
"clusterName": "asd"/**environment object with updated clusterName*/
}
}
},
{
arrayFilters: [
{
"element.clusterid": 6/**clusterId of environment you have to update*/
}
]
})

Passing values from database in "allowableValues"?

I am using Swagger version 2 with Java Spring. I have declared a property and it works fine and it generates a drop down list of value I assigned.
#ApiParam(value = "Pass any one Shuttle provider ID from the list", allowableValues = "1,2,3,4,10")
private Long hotelId;
Now, I need a way to populate this list which is passed in allowableValues from my database as it could be random list as well as huge data. How can I assign list of values dynamically from database in this allowableValues?
This question is bit old, I too faced the same problem so thought of adding here which may help some one.
//For ApiModelProperty
#ApiModelProperty(required = true, allowableValues = "dynamicEnum(AddressType)")
#JsonProperty("type")
private String type;
Created a component which implements ModelPropertyBuilderPlugin
#Component
#Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1)
public class ApiModelPropertyPropertyBuilderCustom implements ModelPropertyBuilderPlugin {
private final DescriptionResolver descriptions;
#Autowired
public ApiModelPropertyPropertyBuilderCustom(DescriptionResolver descriptions) {
this.descriptions = descriptions;
}
public void apply(ModelPropertyContext context) {
try {
AllowableListValues allowableListValues = (AllowableListValues) FieldUtils.readField(context.getBuilder(),
"allowableValues", true);
if(allowableListValues!=null) {
String allowableValuesString = allowableListValues.getValues().get(0);
if (allowableValuesString.contains("dynamicEnum")) {
String yourOwnStringOrDatabaseTable = allowableValuesString.substring(allowableValuesString.indexOf("(")+1, allowableValuesString.indexOf(")"));
//Logic to Generate dynamic values and create a list out of it and then create AllowableListValues object
context.getBuilder().allowableValues(allowableValues);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean supports(DocumentationType delimiter) {
return SwaggerPluginSupport.pluginDoesApply(delimiter);
}
}
Similary for ApiParam we can create component which will implement ParameterBuilderPlugin
#Override
public void apply(ParameterContext context) {
#SuppressWarnings("Guava") final Optional<ApiParam> apiParam =
context.resolvedMethodParameter().findAnnotation(ApiParam.class);
if (apiParam.isPresent()) {
final String allowableValuesString = apiParam.get().allowableValues();
//Your logic here
context.parameterBuilder().allowableValues(allowableValues);
}
}
You need to create constructor in SwaggerConfiguration class.
#Autowire service and withdraw data you need from database
assign this to final variable
assign this final variable to allowableValues in annotation
enjoy not efficient api
private final String allowableValues;
public SwaggerConfiguration() {
List<YourEntitiy> list = someService.findAll();
//code to get every value you need and add create comma separated String
StringJoiner stringJoiner = new StringJoiner(",");
stringJoiner.add(list.get(0).getValue());
this.allowableValues = stringJoiner.toString();
}
#ApiParam(allowableValues = allowableValues)
But I think it's bad idea getting all ids from database just to create allowable values. Just validate in api method if that id exist and/or Create new api to get ids from database, use pagination from Spring Data project, like PageImpl<> javadocs

How to insert POJO into Angular's model?

I'm used to see in MVC Pattern view, controller and model separated and now in many How To I can see model implemented in controller and for me this practice doesn't respect MVC Pattern.
In my case, what I want is for example :
a POJO Car :
public class Car
{
private int price;
private int doors;
public Car (int px, int dr)
{
this.price = px;
this.doors = dr;
}
}
And after instanciation in my java programme
Car car = new Car(1000, 4);
Now, how can I to put this object into Angular's model please ?
Thanks in advance.
I usually use the following pattern
angular.module('yourServiceName.car.model', [])
.factory('Car', function() {
function Car(car) {
/* extend with lodash.
* Since this is a POJO, don't transform anything you dont need.
*/
_.assign(this, car, this);
}
Car.Enums = {SOME:1, ENUM:2, YOU:3, MIGHT:4, NEED:5};
Car.prototype.method = function() {
/* some model specific method.
* don't throw REST or UI things here tho.
*/
}
Car.create = {
fromJSON: function(json) {
/* only use this for JSON missing transformations, like
* 'Y'|'N' to true|false
* dateString to Date instance
*/
json.startDate = Date.parse(json.startDate); or something.
// I want to see 'Car' in my debug window, instead of 'Object'
return new Car(json);
}
}
return Car;
});
Then on your API service
angular.module('yourService.car.rest', [
'yourService.car.model'
])
.factory('carApi', function(baseURL, Car) {
var path = baseURL+'/car'
var Routes = {
CREATE : path,
LIST : path+'/%s',
DETAILS: path+'/%d'
};
function getCar(id, params) {
// this should blowup if id is not a number
var url = sprintf(Routes.DETAILS, id);
return $http.get(url, params).then(function(response.data) {
// if now JSON transformations are done
// return new Car(response.data);
return Car.create.fromJSON(response.data);
});
}
function listCars(ids, params) {
ids = ids || [];
var _ids = ids.join(',');
var url = sprintf(Routes.LIST, _ids);
return $http.get(url, params).then(function(response) {
return _.map(response.data, Car.create.fromJSON);
});
}
function createCar(oCar) {
/* Hungarian notation indicates I expect an instance of 'Car'
* And not just any object
*/
$http.post(Routes.CREATE, {data: oCar});
}
return {list:listCars, get:getCar, create:createCar};
});
So finally in your controller, you would have something like
angular.module('yourProject.ui.car.list', [
'yourServiceName.car.model',
'yourServiceName.car.rest'
])
.controller('ListCarsController', function ListCarsCtrlr(carsApi, Car) {
$scope.ids = [1, 2, 3];
$scope.load = function() {
var params = {}; // anything else you need to pass
carsApi.list(ids, params).then(function(cars) {
$scope.cars = cars; // all of these are now instanceof Car
})
}
});
Your controller ends up as simple as this:
You can even take it up a nodge if you need Viewmodel
angular.module('yourProject.ui.car.list.viewmodel', [
'yourService.car.model'
])
.factory('CarItemViewmodel', function CarItemVM() {
function CarItemViewmodel(oCar) {
// do some flattening or something you can unit test
this.price = oCar.additionalAttributes.somethingDeep.price;
this.ammount = oCar.someOtherStuff[0].quantity;
};
return CarItemViewmodel;
});
MVC patter of angularjs means that all layer(M,V,C) are in client side.
In this pattern, Server side normally return simple json file which are requested by ajax wheter you implement your server side code with MVC pattern or not.
Therefore If you prefer to use POJO on your server side code, I suggest to conver POJO to json format and serve it as json file.
In the client angularjs code, you can convert json to javascript simple object and use it as model.
You don't. And you can't.
You can make a web service in Java. You can make Angular to call that web service. But you can't push data from Java into "Angular's model", because that's not how the web works.
override the tostring method of your Car class
public String toString(){
return new JSONObject(this).toString();
}
And you can put that object in json and return it as a json
Car car = new Car(1000, 4);
JSONObject jsonReturn = new JSONObject();
jsonReturn.put("car ", car );

Categories

Resources