I am trying to process the JSON output from https://api.exchangeratesapi.io/latest in my Android app, which is returned in this format:
{
"rates": {
"CAD": 1.5613,
"HKD": 8.9041,
...
"KRW": 1374.71,
"MYR": 4.8304
},
"base": "EUR",
"date": "2020-03-09"
}
I would like to use GSON to process this JSON, so I have added a class ExchangeRates to recieve the data:
class ExchangeRates {
private String base;
private String date;
}
These commands load the JSON into my ExchangeRates class:
Gson gson = new Gson();
ExchangeRates mExchangeRates = gson.fromJson(result, ExchangeRates.class);
However, I cannot figure out how to load the associative array of exchange rates into the class in a scalable manner. I know I could add a static list of the currencies, but I want the code to be able to automatically handle additional currencies if they are added at a later date.
It turned out to be very simple, and yes, #ya379, a HashMap was part of the answer. Given a HashMap data type, GSON will translate the associative array part of the JSON directly to a HashMap:
class ExchangeRates {
private String base;
private String date;
private HashMap<String, Double> rates;
}
Related
I am using a DynamoDB-table with DynamoDBAttributeType.M maps nested in one another. The field of my table I'm having problems with looks like this:
"Data": {
"EnglishName": "Balcony",
"High": {
"Status": true,
"Triggered": true,
"Value": 5
},
"Low": {
"Status": true,
"Triggered": false,
"Value": 1
},
"TagName": "tag1"
}
all the keys of the map are Strings and some of the values are Strings and some are maps. In my Java code that data is represented by a class, which is an attribute of another class, which represents whole table. Attributes 'Low' and 'High' are also represented by Java class and attributes of data class.
I have tried to map it to Java object using many ways, mostly by DynamoDBTypeConverter. Hardest part is that I can't find any information about this with Google. I only found one example of converter class where attribute type is S not M.
I keep on getting error:
could not unconvert attribute
How this can be done?
Finally I have a functioning solution. Basically the answer is to use Map<String, Attributevalue> and desired object type in DynamoDBTypeConverter like this:
public class DataConverter implements DynamoDBTypeConverter<Map<String, AttributeValue>, Data> {
#Override
public Map<String, AttributeValue> convert(Data data) {
ObjectMapper mapper = new ObjectMapper();
Item item = new Item()
.withString("englishName", data.getEnglishName())
.withMap("high", mapper.convertValue(data.getHigh(), Map.class))
.withMap("low", mapper.convertValue(data.getLow(), Map.class))
.withString("tagName", data.getTagName());
return ItemUtils.toAttributeValues(item);
}
#Override
public Data unconvert(Map<String, AttributeValue> data) {
Data tagData = new Data();
try {
ObjectMapper mapper = new ObjectMapper();
String item = ItemUtils.toItem(data).toJSON();
JsonNode json = mapper.readTree(item);
tagData = mapper.convertValue(json, Data.class);
} catch (JsonProcessingException ex) {
Logger.getLogger(TagDataConverter.class.getName()).log(Level.SEVERE, null, ex);
}
return tagData;
}
I also needed to write type converters to attributes that are objects and annotate them in class:
public class Data {
private String tagName;
private String englishName;
#DynamoDBTypeConverted(converter = AlertConverter.class)
private Alert low;
#DynamoDBTypeConverted(converter = AlertConverter.class)
private Alert high;
The AlertConverter.class is an ordinary DynamoDBTypeConverter that takes in <String, Alert>.
Have you tried using a tool like Gson? If you're getting back the DynamoDB response as a JSON string, try this:
Gson gson = new Gson();
Data data = gson.fromJson(jsonString, Data.class);
I am currently trying to load an indefinite amount of variables from a JSON array, and have no idea how to do this.
My JSON file is as follows:
{"commands": [
{"cmd": "hello", "params": "%u", "output": "hello %s!"},
{"cmd": "ping", "params": "", "output": "pong!"},
{"cmd": "test", "params": "%ul", "output": "test %s.."}
]}
I am using the GSON library from Google.
Would I have to manually parse each command, or is there a way to achieve this with gson.fromJson()?
You can use a wrapper object containing an array or a collection of Command objects as a model for the deserialization process:
Command.java
public class Command{
private String cmd;
private String params;
private String output;
// Getters and setters
}
CommandWrapper.java
public class CommandWrapper{
private List<Command> commands;
// Getters and setters
}
And then in your class you can deserialize the JSON this way:
Gson gson = new Gson();
CommandWrapper wrapper = gson.fromJson(myInputJson, CommandWrapper.class);
And get your commands as a list.
If the number is really indefinite; you might want to look into creating a Java8 stream from your input; as streams can be (theoretically) without an end.
But probably you should simply return a List of some specific class of yours that nicely "wraps" around the JSON data in your file.
{
"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 am trying to parse this JSON which is coming as the response to a REST API call. Can you please help me parsing it as key value pairs?
The object names are not present. There is nesting as well. There seems to be no new line between records.
The aim is to extract this data and load it into a database.
[
{
"cc_emails":["feedback#xyz.com"],
"fwd_emails":[],
"reply_cc_emails":["feedback#xyz.com"],
"fr_escalated":false,
"spam":false,
"email_config_id":6000038087,
"group_id":6000110481,
"priority":1,
"requester_id":6010410791,
"responder_id":6002817857,
"source":1,
"company_id":null,
"status":2,
"subject":"fare",
"to_emails":["feedback#xyz.com"],
"product_id":null,
"id":45043,
"type":null,
"due_by":"2016-03-12T08:58:02Z",
"fr_due_by":"2016-03-08T08:58:02Z",
"is_escalated":false,
"description":"Dear xyze Team,\r\n\r\nWhy r u increased fair again and againasas0mail.gmail.com</a>.<br>\n",
"custom_fields":
{
"category":null,
"issue":null,
"route_id":null,
"phone_number":null,
"department":null,
"booking_id":null
},
"created_at":"2016-03-07T08:58:02Z",
"updated_at":"2016-03-07T08:58:03Z",
// ...... repeat
}
]
The best way to do this would be to use http://www.jsonschema2pojo.org/
Enter your json there
Change source type to JSON
set the correct class name and package.
The resulting pojo can be directly mapped from the json
If you are using resttemplate to hit the api then you can use getForObject to automatically set the pojo from the output.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject-java.lang.String-java.lang.Class-java.lang.Object...-
Using gson you can do this quite simply.
Do a class to match the fields in the json something like:
public class Example {
private List<String> cc_emails;
private List<String> fwd_emails;
private List<String> reply_cc_emails;
private Boolean fr_escalated;
private Boolean spam;
private Integer email_config_id;
...
private CustomFields custom_fields;
private String created_at;
private String updated_at;
}
Then you need to do another to map the custom fields
public class CustomFields {
private String category;
...
}
And using json you can parse it like this:
Type type = new TypeToken<Collection<Example>>(){}.getType();
new Gson().fromJson(json,type);
You have to exaplain to Gson it's a list, if it was a single object it would be this:
new Gson().fromJson(json,Example.class);
This is the aproach I usually take, also in the dates java.sql.Timestamp class might also parse it, you would need to try it though.
You can use Gson (https://github.com/google/gson) or Jackson (https://github.com/FasterXML/jackson) and deserialize it to a Map.
I know how to deserialize normal JSON object with "Gson" library but I am facing problem to deserialize an JSON array with several JSON object and arrays. I am trying to get the time in the arrival_time JSON object in this simple below but I don't know how to structure my class to accomplish that. Can someone explain me how to do that?
Simple:
[{"route": 1,
"info": [
{"direction": "Surrey Quays"},
{"stops": [{"stops_name": " Tenison Way"},
{"arrival_time":{
"mon-fri": [ "05:38", "06:07","06:37"],
"sat": ["05:34","06:01","06:31"],
"son": ["06:02","06:34","07:04"]
}
}
]
}
]
}]
You can parse this Json using following structure:
class ArrivalTime {
public List<String> mon_fri;
public List<String> sat;
public List<String> son;
}
class Stop {
public String stop_name;
public ArrivalTime arrival_time;
}
class Info {
public String direction;
public List<Stop> stops;
}
class RouteInfo {
public Integer route;
public List<Info> info;
}
and then use it like this:
Gson gson = new Gson();
RouteInfo[] routes = gson.fromJson(/* your json string*/, RouteInfo[].class);
Arrival times will be available at something like this (it is ugly but I just want you to present the sample structure for this json string):
System.out.println(routes[0].info.get(1).stops.get(1).arrival_time.sat.get(0));
To learn the structure you could use a javascript object or a online builder.
http://www.jsonschema2pojo.org/