Parsing the openweatherMap json file - java

I am working on a project,which requires to get weather information and so i used openweathermap api. My program worked and i got information from "main" and "wind" ,but i also need to get description from the main weather set.The problem is that the weather set is a list in the json file and i am unable to cast it to map.The example json file which i am trying to parse is http://api.openweathermap.org/data/2.5/weather?q=London
JSON:
{
"coord":{
"lon":-0.13,
"lat":51.51
},
"weather":[
{
"id":803,
"main":"Clouds",
"description":"broken clouds",
"icon":"04n"
}
],
"base":"stations",
"main":{
"temp":43.56,
"pressure":1004,
"humidity":87,
"temp_min":41,
"temp_max":46.4
},
"visibility":10000,
"wind":{
"speed":11.41,
"deg":80
},
"rain":{
},
"clouds":{
"all":75
},
"dt":1573350303,
"sys":{
"type":1,
"id":1414,
"country":"GB",
"sunrise":1573369754,
"sunset":1573402780
},
"timezone":0,
"id":2643743,
"name":"London",
"cod":200
}
When we look at the file,we notice that there is an [] bracket inside the weather set which is creating problems in my project.I tried to look up on how to cast list to map and tried playing with my code ,but didn't help.The commented code in the file are things which i have tried while trying to make it work.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.*;
import com.google.gson.reflect.*;
import java.util.List;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class PlantWateringApp {
public static Map<String, Object> jsonToMap(String str) {
Map<String, Object> map = new Gson().fromJson(str, new TypeToken<HashMap<String, Object>>() {
}.getType());
return map;
}
public static void main(String[] args) {
String LOCATION = "delhi,india";
String result = "{\"coord\":{\"lon\":77.22,\"lat\":28.65},\"weather\":[{\"id\":711,\"main\":\"Smoke\",\"description\":\"smoke\",\"icon\":\"50d\"}],\"base\":\"stations\",\"main\":{\"temp\":72.32,\"pressure\":1015,\"humidity\":59,\"temp_min\":64.4,\"temp_max\":77},\"visibility\":1000,\"wind\":{\"speed\":3.36,\"deg\":270},\"clouds\":{\"all\":0},\"dt\":1573351180,\"sys\":{\"type\":1,\"id\":9165,\"country\":\"IN\",\"sunrise\":1573348168,\"sunset\":1573387234},\"timezone\":19800,\"id\":1273294,\"name\":\"Delhi\",\"cod\":200}";
System.out.println(result);
Map<String, Object> respMap = jsonToMap(result.toString());
Map<String, Object> mainMap = jsonToMap(respMap.get("main").toString());
Map<String, Object> windMap = jsonToMap(respMap.get("wind").toString());
// Type listType = new TypeToken<List<Map<String,String>>>()
// {}.getType();
// List<Map<String,String>> weatherMap = new
// Gson().fromJson(respMap.get("description").toString(),listType);
// Map<String, Object> name = (Map<String, Object>)
// respMap.get("description");
// Map<String, Object > weatherMap = jsonToMap
// (respMap.get("description").toString());
System.out.println("Location: " + LOCATION);
System.out.println("Current Temperature: " + mainMap.get("temp"));
System.out.println("Current Humidity: " + mainMap.get("humidity"));
System.out.println("Max: " + mainMap.get("temp_min"));
System.out.println("Min: " + mainMap.get("temp_max"));
System.out.println("Wind Speed: " + windMap.get("speed"));
System.out.println("Wind Angle: " + windMap.get("deg"));
}
}
I tried to do the same way as i did for main and wind : Map weatherMap = jsonToMap (respMap.get("weather").toString()); .But i got errors:
////java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 3 path $[0]
So i tried to not convert json to Map rather directly use map like Map weatherMap = (Map) respMap.get("weather"); but i got
////java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.Map
For this,i tried to cast list to map using
List<Map<String,String>> weatherMap = new Gson().fromJson(respMap.get("weather").toString(),listType);
But this says:
//String cannot be converted to int
I am really confused on what to do in this situation.I am unable to figure out how to deal with [] in the json file.

As this data is provided as a List and you are trying to convert it into the Map. That is not right. You need to get it (weather) as a list of Map and then need to treat each element as Map. Here is an example how to get it as a Map
///...
//// other code
///...
Map<String, Object > respMap = jsonToMap (result.toString());
// don't need to convert from string to map again and again
Map<String, Object > mainMap = (Map<String, Object >)respMap.get("main");
Map<String, Object > windMap = (Map<String, Object >)respMap.get("wind");
// fist get weather as list
List<Map<String, Object >> weather = (List<Map<String, Object>>) (respMap.get("weather"));
//...
System.out.println("Wind Speed: " + windMap.get("speed") );
System.out.println("Wind Angle: " + windMap.get("deg") );
// weather as list
System.out.println("Weather: "+ weather);
// assuming weather contains at-least 1 element.
Map<String, Object> weatherMap = weather.get(0);
System.out.println("Weather as map: "+ weatherMap);
Casting it to list.
List<Map<String, Object >> weather = (List<Map<String, Object>>) (respMap.get("weather"));
Then treat each element as Map:
// assuming weather contains at-least 1 element.
Map<String, Object> weatherMap = weather.get(0);
Hope this helps.

Make life simple and use real types.
import java.util.List;
import com.google.gson.Gson;
public class PlantWateringApp {
class Weather_2_5 {
List<Weather> weather;
}
class Weather {
Integer id;
String main;
String description;
String icon;
}
public static void main(String[] args) {
String result = "{\"coord\":{\"lon\":77.22,\"lat\":28.65},\"weather\":[{\"id\":711,\"main\":\"Smoke\",\"description\":\"smoke\",\"icon\":\"50d\"}],\"base\":\"stations\",\"main\":{\"temp\":72.32,\"pressure\":1015,\"humidity\":59,\"temp_min\":64.4,\"temp_max\":77},\"visibility\":1000,\"wind\":{\"speed\":3.36,\"deg\":270},\"clouds\":{\"all\":0},\"dt\":1573351180,\"sys\":{\"type\":1,\"id\":9165,\"country\":\"IN\",\"sunrise\":1573348168,\"sunset\":1573387234},\"timezone\":19800,\"id\":1273294,\"name\":\"Delhi\",\"cod\":200}";
//System.out.println(result);
Gson G = new Gson();
Weather_2_5 obj = G.fromJson(result, Weather_2_5.class);
for (int idx = 0; idx < obj.weather.size(); idx++) {
System.out.println(obj.weather.get(idx).description);
}
}
}

Instead of writing it all from the beginning you could use:
https://github.com/xSAVIKx/openweathermap-java-api
I think this example is closest to what you are trying to do:
https://github.com/xSAVIKx/openweathermap-java-api/blob/development/api-examples/src/main/java/org/openweathermap/api/example/CurrentWeatherOneLocationExample.java

Related

Convert JSON record to LinkedHashMap<String,String> using Jackson API

I have a JSON file(it contains an array of JSON objects.)
I am trying to read it object by object.
Each object I need to convert it to a LinkedHashMap<String,String> where both the key and value are strings. Note that even if the JSON objects contain a non-string value(Integer/Boolean), I want my LinkedHashMap to contain a string.
This is my JSON file (films.json):
[
{
"name": "Fight Club",
"year": 1999,
}
]
Now, this has 1 object. I want to convert it to a LinkedHashMap<String,String>.
So for the above example, my LinkedHashMap should contain(for the 1st JSON object) :
"name" : "Fight CLub"
"year" : "1999"
Notice how the year is String in the LinkedHashMap and not Integer.
This is what I tried.
Map<String, Object> myLinkedHashMap;
JsonParser jsonParser = new JsonFactory().createParser(new File("films.json"));
jsonParser = new JsonFactory().createParser(new File(filePath));
jsonParser.nextToken();
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
while(jsonParser.nextToken() != JsonToken.END_ARRAY){
myLinkedHashMap = mapper.readValue(jsonParser, LinkedHashMap.class);
}
The variable myLinkedHashMap will contain a key/value pair for an object in my JSON file.
But the problem is that for 'year' of the JSON file, I am getting Integer in the LinkedHashMap as the JSON file also contains Integer.
Instead, I want the Integer as String in the LinkedHashMap.
Please help me get String in the LinkedHashMap instead of Integer.
Note: The solution should be generic to other data types also.
So if the JSON object contains boolean true, then my LinkedHashMap should contain "true".
You can construct map type using TypeFactory and constructMapType method to tell exactly what do you need from readValue method. See below example:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.util.Assert;
import java.io.File;
import java.util.LinkedHashMap;
public class JsonMapApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
JsonParser jsonParser = mapper.getFactory().createParser(jsonFile);
jsonParser.nextToken();
MapType mapType = mapper.getTypeFactory().constructMapType(LinkedHashMap.class, String.class, String.class);
while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
LinkedHashMap<String, String> map = mapper.readValue(jsonParser, mapType);
map.forEach((k, v) -> {
Assert.isInstanceOf(String.class, v);
System.out.println(k + " -> " + v + " (" + v.getClass().getName() + ")");
});
}
}
}
Above code prints:
name -> Fight Club (java.lang.String)
year -> 1999 (java.lang.String)
Change
Map<String, Object> myLinkedHashMap;
to
Map<String, String> myLinkedHashMap;

Properties file to complex JSON string [Java/Spring]

I'm creating a Spring application on backend and my main goal is to manage properties (add/update/delete) in *.properties file. I want to convert this file to JSON and then manipulate it from UI application.
Is there any possibility to convert structure like this:
a.x=1
a.y=2
b.z=3
To JSON like this:
{
"a": {
"x": 1,
"y": 2
},
"b": {
"z": 3
}
}
I found solution to use GSON library, but it creates for me flat structure, not hierarchical, code I used:
Properties props = new Properties();
try (FileInputStream in = new FileInputStream(classPathResource.getFile())) {
props.load(in);
}
String json = new GsonBuilder().enableComplexMapKeySerialization().create().toJson(props);
Is here someone who was facing same problem and maybe found a working project for this? Maybe GSON library can do that?
This solution does involve loads of work, but you will get what you want to achieve using the below code, basically, the idea is to split the key based on the single dot and then create a JsonObject if the same first key is found.
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Properties;
import org.json.JSONObject;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class SOTest {
public static void main(String[] args) throws IOException {
JSONObject jsonObject = new JSONObject();
FileReader fileReader = new FileReader(new File("C:\\Usrc\\main\\java\\Sample.properties"));
Properties properties = new Properties();
properties.load(fileReader);
Iterator<Entry<Object, Object>> iterator = properties.entrySet().iterator();
while (iterator.hasNext()) {
Entry<Object, Object> entry = iterator.next();
String value = (String) entry.getKey();
String[] values = value.split("\\.");
JSONObject opt = jsonObject.optJSONObject(values[0]);
if(opt!=null) {
opt.put(values[1],entry.getValue());
}else {
JSONObject object = new JSONObject();
object.put(values[1], entry.getValue());
jsonObject.put(values[0], object);
}
}
System.out.println(jsonObject.toString());
}
}
Output
{"a":{"x":"1","y":"3"},"b":{"z":"10"}}

Expected BEGIN_OBJECT but was STRING in Gson

Hi I am try to parse some JSON by GSON which used number as the key.
I reference the post but it give some error and I don't know why.
How to convert json objects with number as field key in Java?
I also see the post but still cannot solve my problem.
"Expected BEGIN_OBJECT but was STRING at line 1 column 1"
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Gson gson = new Gson();
Type type = new TypeToken<HashMap<String, HashMap<String, String>>>() {}.getType();
Map<String, Map<String, String>> map = gson.fromJson("./src/main/resources/input.json", type);
}
}
The json file is
{
"1":{"id":"1"}
}
The fromJson method doesn't receive a filename, it receives an actual JSON: look at the docs here
But there is an overload that receives a Reader instead:
try (FileReader reader = new FileReader("./src/main/resources/input.json"))
{
map = gson.fromJson(reader, type)
}
catch (...) { ... }

Adding user to yml file as Block mapping nested in a block sequence, using SnakeYAML Java

I am working with Elastic Search, i came across a plugin called ReadOnlyRest plugin for Auth purpose. To set up this plugin we need to add user to Elastic search yml.
So i searched how to add "key : value" pair data to yml using Java. Came across SnakeYAML to add data.
I am able to send the data of user from Java.
Java code.
package com.test.elasticsearch;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
public class YAMLSample {
protected static Logger logger = Logger.getLogger(YAMLSample.class);
final String fileName = "/home/Installation/elasticsearch-2.3.1/config/elasticsearch.yml";
public void writeToYML() throws IOException {
logger.debug("Write to YML");
Map<String, Object> data = new HashMap<String, Object>();
data.put("name", "user5");
data.put("type", "allow");
data.put("auth_key", "user5:user5");
data.put("kibana_access", "ro");
data.put("indices", new String[] { ".kibana*", "abc", "def" });
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
list.add(data);
DumperOptions options = new DumperOptions();
options.setIndent(5);
Yaml yaml = new Yaml(options);
FileWriter writer = new FileWriter(fileName, true);
yaml.dump(list, writer);
logger.debug("DONE!");
}
public static void main(String[] args) throws IOException {
// new YAMLSample().readYML();
new YAMLSample().writeToYML();
}
}
Output from the above code is:
- name: user5
indices: [.kibana*, abc, def]
kibana_access: ro
type: allow
auth_key: user5:user5
But, expected output is:
- name: user5
indices: [.kibana*, abc, def]
kibana_access: ro
type: allow
auth_key: user5:user5
the "Hyphen-minus" should have just one space and before the "Hyphen-minus" there should be 4 spaces.
I mean to say i am expecting this to appear as Array of Users. else than "Hyphen-minus" then few spaces.
Please assist me with finding out the solution.
I've modified your code and got the expected result. Below is how the code look like:
public class YAMLSample {
final String fileName = "/tmp/rest.yml";
public void writeToYML() throws IOException {
log( "Write to YML" );
Map<String, Object> user = new HashMap<>();
user.put( "name", "user5" );
user.put( "type", "allow" );
user.put( "auth_key", "user5:user5" );
user.put( "kibana_access", "ro" );
user.put( "indices", new String[] { ".kibana*", "abc", "def" } );
Map<String, Object> user2 = new HashMap<>();
user2.put("name", "user2");
user2.put("type", "allow");
user2.put("auth_key", "user2:user2");
user2.put("kibana_access", "ro");
user2.put("indices", new String[] { ".kibana*", "abc", "def" });
List<Map<String, Object>> list = new ArrayList<>();
list.add(user);
list.add(user2);
Map<String, List<Map<String, Object>>> config = new HashMap<>();
config.put( "access_control_rules", list );
DumperOptions options = new DumperOptions();
options.setIndent( 6 );
options.setIndicatorIndent( 4 );
options.setDefaultFlowStyle(DumperOptions.FlowStyle.AUTO);
Yaml yaml = new Yaml(options);
FileWriter writer = new FileWriter(fileName, true);
yaml.dump( config, writer );
log( "DONE!" );
}
public static void main(String[] args) throws IOException {
new YAMLSample().writeToYML();
}
public void log(String str) {
System.out.println(str);
}
}
Basically I added this two options to your Dumper
options.setIndicatorIndent(4);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.AUTO);
and updated from 5 to 6 the options.setIndent(6);

How to get results with IndexTank?

I'm using IndexTank with the Java client, but I can't seem to access the results:
SearchResults results = index.search(Query.forString(keywords));
for (Map<String, Object> document : results.results) {
System.out.println("doc id: " + document.get("docid"));
The last line fails with: Type mismatch: cannot convert from Object to String
Does anyone know why I get this error? Thanks.
What you have looks fine. Are you sure you're importing all of the right classes? This works for me:
import java.util.HashMap;
import java.util.Map;
import com.flaptor.indextank.apiclient.Index;
import com.flaptor.indextank.apiclient.IndexTankClient;
import com.flaptor.indextank.apiclient.IndexTankClient.Query;
import com.flaptor.indextank.apiclient.IndexTankClient.SearchResults;
public class IndexTankExample {
public static void main(String[] args) throws Exception {
IndexTankClient client = new IndexTankClient("<PRIVATE URL>");
Index index = client.getIndex("test");
Map<String, String> fields = new HashMap<String, String>();
fields.put("text", "foo bar baz");
index.addDocument("1", fields);
SearchResults results = index.search(Query.forString("bar"));
for (Map<String, Object> document : results.results) {
System.out.println("doc id: " + document.get("docid"));
}
}
}

Categories