I have a GenericRecord, and want to iterate over the entire collection of key/values. The record is a java data structure that is the equivalent of a plain json string. Eg:
{"key1":"val1","key2":val2",...} but is quite long.
The problem is, I dont know how many key,vals are inside it.
I've tried:
AvroKeyValue<String,String> kv = new AvroKeyValue<>(record);
Iterator<String,String> iterator = new AvroKeyValue.Iterator<String,String>(kv);
But this does not work.
The apache docs about it are here:
http://avro.apache.org/docs/1.7.0/api/java/org/apache/avro/hadoop/io/AvroKeyValue.Iterator.html
Use the GenericRecord's schema to list the available fields
for (Field field : record.getSchema().getFields()) {
String fieldKey = field.name();
System.out.println(fieldKey + " : " + record.get(fieldKey));
}
You can get the number of fields of a GenericRecord with:
record.getSchema().getFields().size();
Related
I want to read a .json using library json-simple, my json file is:
{
"Subjects": {
"subject1": "MIS",
"subject2": "DBMS",
"subject3": "UML"
}
}
And my code is:
import java.io.*;
import java.util.*;
import org.json.simple.*;
import org.json.simple.parser.*;
public class JSONReadFromTheFileTest {
public static void main(String[] args) {
JSONParser parser = new JSONParser();
try{
Object obj = parser.parse(new FileReader("/Users/User/Desktop/course.json"));
JSONObject jsonObject = (JSONObject)obj;
JSONArray subjects = (JSONArray)jsonObject.get("Subjects");
Iterator iterator = subjects.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}catch(Exception e){
e.printStackTrace();
}
}
}
I would like to get in console:
subject1: MIS
subject2: DBMS
subject3: UML
But instead of that, I just get the next error:
java.lang.ClassCastException: org.json.simple.JSONObject cannot be cast to org.json.simple.JSONArray
at project.Main(Main.java:11)
But I searched in internet, and I found that if I change sintaxys of the .json in the next way:
{
"Subjects": [
"subject1: MIS",
"subject2: DBMS",
"subject3: UML"
]
}
I get in console what I want:
subject1: MIS
subject2: DBMS
subject3: UML
And you may think my problem is solved, but not yet, because I want to read the json file in the first way.
I hope someone can help me. Thanks in advance.
The first example shows a Subjects key containing a single object with several properties (subject1, subject2, etc).
Consider those properties like the member variables of a class.
In order to let you better understand if the class is Person those variables could be name and surname.
What you try to achieve in your code is extracting a JSONArray from the JSON you are providing.
Going back to the example for Person the array could be - sorry for the silly example - an Array containing phone numbers.
So what you are expecting is that one of the member properties of the class is an array.
This is not possible in the first example because the first example does not contain a json array.
This line extracts the whole json object:
JSONObject jsonObject = (JSONObject)obj;
This one tries to get an array out but no array is there in the first example:
JSONArray subjects = (JSONArray)jsonObject.get("Subjects");
Square brackets represent an array, which you've casted the getter into.
The second json shown is more correct for the code you've written, however, arrays cannot hold key-value pairs, so that's why you've made second JSON have an array of strings
To parse the first file, you'd need to start with
JSONObject subjects = (JSONObject)jsonObject.get("Subjects")
If you have full control over the file, I'd suggest just storing ["MIS", "DBMS", "UML"] then write a simple loop
for (int i = 0; i < jsonArray.length; i++) {
System.out.printf("subject%d: %s%n", i+1, jsonArray.get(i));
}
To make your code work with your json, you should not use JSONArray for "Subjects" but instead JSONObject. The reason is that [ and ] indicates beginning and ending of array element in json which is represented by JSONArray. If you have { and } element then its object represented by JSONObject. zz So replace this:
JSONArray subjects = (JSONArray)jsonObject.get("Subjects");
Iterator iterator = subjects.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
with following (I have not compiled it):
JSONObject subjects = (JSONObject)jsonObject.get("Subjects");
for(Iterator iterator = subjects.keySet().iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
System.out.println(key + ": " + subjects.get(key));
}
As others mentioned you should replace JSONArray with JSONObject in your code. But I would suggest to switch to different JSON library all together. I would recommend to use Json-Jackson library. Also, there is another library that provides a wrapper over Json-Jackson library. It has JsonUtils class that can simply parse your JSON in one line. Just read first your Json from file into a String jsonString and do this.
Map<String, Object> myMap = JsonUtils.readObjectFromJsonString(jsonString, Map.class);
You will get a Map with one key "Subjects" that will have a value of a Map with your 3 keys and values:
subject1: MIS
subject2: DBMS
subject3: UML
Here is the JavaDoc for the JsonUtils class. The library could be found as Maven artifact and on Github (including source code and Javadoc).
I would like to edit a yaml in java , ( I'm editing BungeeCord config file to create a system that launches instance of bungeecord with a defined by user port ) but in a precise way , i need to write exactly this in the yaml file :
listeners:
- query_port: 25577
motd: '&1Another Bungee server'
tab_list: GLOBAL_PING
query_enabled: false
proxy_protocol: false
ping_passthrough: false
priorities:
- lobby
bind_local_address: true
host: 0.0.0.0:25577
max_players: 1
tab_size: 60
force_default_server: false
I did something very similar but there is a vertical bar that prevents BungeeCord from reading the file :
public class ProxyYaml {
HashMap<String, Object> entries = new HashMap<String, Object>();
public ProxyYaml() {
entries.put("query_port", 25577);
entries.put("motd", "Hey Guys");
entries.put("tab_list", "GLOBAL_PING");
entries.put("query_enabled", false);
entries.put("proxy_protocol", false);
entries.put("ping_passthrough", false);
entries.put("priorities", Arrays.asList("lobby"));
entries.put("bind_local_address", true);
entries.put("host", "0.0.0.0:25577");
entries.put("max_players", 1);
entries.put("tab_size", 60);
entries.put("force_default_server", false);
}
public ArrayList<String> getProperties() {
ArrayList<String> finalString = new ArrayList<String>();
for(String entry : entries.keySet()) {
finalString.add(entry + ": " + entries.get(entry).toString());
}
return finalString;
}
}
( I'm using SimpleYaml api but I can change the api if needed )
File propsProxyFile = new File(path + "config.yml");
YamlFile propsProxyYaml = new YamlFile(propsProxyFile);
try {
propsProxyYaml.load(propsProxyFile);
propsProxyYaml.set("listeners", Arrays.asList(new ProxyYaml().getProperties()));
propsProxyYaml.save(propsProxyFile);
} catch (IOException | InvalidConfigurationException e) {
System.out.println(MainNetwork.logo + "Can't load proxy properties file");
return;
}
There is the code output ( with the vertical bar ) :
listeners:
- |
query_port: 25577
motd: '&1Another Bungee server'
tab_list: GLOBAL_PING
query_enabled: false
proxy_protocol: false
ping_passthrough: false
priorities:
- lobby
bind_local_address: true
host: 0.0.0.0:25577
max_players: 1
tab_size: 60
force_default_server: false
What should I do please ?
The pipe character (|) starts a YAML block scalar. It means that all the following lines are a literal string and not subject to further YAML parsing.
There are lots of strange things happening in your code, let's go over them:
public ArrayList<String> getProperties() {
ArrayList<String> finalString = new ArrayList<String>();
for(String entry : entries.keySet()) {
finalString.add(entry + ": " + entries.get(entry).toString());
}
return finalString;
}
You are manually transforming a mapping into a list of strings here. Why do you do that? You expect the final YAML file to contain the key-value pairs as mapping, so you should not transform them into a list of strings.
Let's discuss what happens here with a quick example:
Assume we have this java Map:
Map<String, String> value = Map.of("foo", "bar");
If we directly serialize this to YAML, we would get
foo: bar
but if we pipe it through your method, we'll get
- "foo: bar"
i.e. a sequence of one scalar value – because we manually transformed the mapping entry into a string! This is not what you want.
propsProxyYaml.set("listeners", Arrays.asList(new ProxyYaml().getProperties()));
You call Arrays.asList on the return value of getProperties() which is of type ArrayList<String> so asList will return a value of type List<ArrayList<String>>, which has a single entry that is the list you built. It is unclear why you call Arrays.asList unless you want to have a list of lists. According to the desired YAML output, this is not what you want.
Now let's discuss what the set method does. I don't really know SimpleYAML and frankly, its documentation is horrible as it basically only consists of the autogenerated API docs. The first parameter of the method is named path, which implies that it is not a simple mapping key.
What apparently happens is that the List<ArrayList<String>> value is transformed into a YAML sequence with one scalar value, and that scalar value contains all the string values you produced, separated by newlines. Without proper documentation, it is impossible to say whether this is expected behavior or a bug. In any case, it makes no sense.
Now the actual YAML contains a mapping at its root with one entry, whose key is the scalar listeners. Its value is a list that contains another mapping. This means, the type you actually want to serialize is
Map<String, List<Map<String, Object>>>
I suggest that you simply build a value of this type and use the SnakeYAML API, which does have proper documentation on how its serialization system works. SimpleYAML uses SnakeYAML under the hood anyway, and there seems to be no reason to use a poorly documented API with surprising behavior instead of a well-documented one.
You can also create a custom Java class instead of using Maps. Then the keys would become class fields.
I have list of words which I need to load to ArrayList< String >
prefix.properties
vocab\: = http://myweb.in/myvocab#
hydra\: = http://www.w3.org/ns/hydra/core#
schema\: = http://schema.org/
"vocab:" is actually "vocab:" .Slash(\) is used to read colon(:) character because it is special character.
Dictionary.java
public class Dictionary {
public static ArrayList<String> prefix = new ArrayList<>();
static {
Properties properties = new Properties();
InputStream input = null;
input = ClassLoader.getSystemResourceAsStream("prefix.properties");
System.out.println(input!=null);
try {
properties.load(input);
} catch (IOException e) {
e.printStackTrace();
}
Set<Map.Entry<Object, Object>> entries = properties.entrySet();
for(Map.Entry<Object, Object> E : entries)
{
prefix.add(E.getKey().toString());
prefix.add(E.getValue().toString());
}
}
}
In Dictionary.java , ArrayList prefix will have
prefix = [
"vocab:",
"http://myweb.in/myvocab#",
"hydra:",
"http://www.w3.org/ns/hydra/core#",
"schema:",
"http://schema.org/"
]
I am querying some data in another class.
For eg:
public class QueryClass
{
public ArrayList<String> queryResult(String findKey)
{
ArrayList<String> result = new ArrayList<String>();
ArrayList<String> prefix = Dictionary.prefix;
Iterator<String> iterator = prefix.iterator();
while (iterator.hasNext())
{
String currentKey = iterator.next()+findKey;
/**
Here my logic to search data with this currentKey
*/
}
return result;
}
}
Problem :
I want to avoid this method to load from .properties file because there is possibility of odd number of elements can be present while .properties file provide (key,value) pair way to store data.
Reason why I have to load from separate file ? Because In future I will have to add more keywords/String thats why I put it in prefix.properties file.
Is there any alternative way to do this?
Do not re-invent the wheel.
If you can define the file format, then just go for java properties.
You see, the Properties class has a method getProperty(String, String) where the second argument can be used to pass a default value for example. That method could be used in order to fetch keys that don't come with values.
I would be really careful about inventing your own format; instead I would look into ways of re-using what is already there. Writing code is similar to building roads: people forget that each new road that is built translates to maintenance efforts in the future.
Besides: you add string values to a list of strings by calling list.add(strValue). That is all that is to that.
Edit on your comment: when "java properties" are not what you are looking for; then consider using other formats. For example you could be persisting your data in some JSON based format. And then just go for some existing JSON parser. Actually, your data almost looks like JSON already.
I'm not sure why you need to use ArrayList but if you want to pass these property keys/values, there are 2 better ways:
Use Properties itself.
Convert to HashMap.
I have a case where I need to merge multiple JSONs objects into one JSON.
A single response looks like this:
{"name":"MyName"}
Multiple merged JSON looks like this:
["{\"name\":\"name\"}","{\"name\":\"MyName\"}"]
The problem here is that the child JSONs that I want to include can come either from a Java object or are available as String itself.
MyRequest request = new MyRequest();
request.setName("name");
String singleJson = new Gson().toJson(request);
String fromSomePlaceElse = "{\"name\":\"MyName\"}";;
List<String> list = Lists.newArrayList(singleJson,fromSomePlaceElse);
System.out.println(new Gson().toJson(list));
The above gives me the following output:
["{\"name\":\"name\"}","{\"name\":\"MyName\"}"]
instead of:
[{"name":"MyName"}, {"name":"MyName"}]
I don't want to parse the already existing JSON and do the following:
List<MyRequest> list2 = Lists.newArrayList(request, new Gson().fromJson(fromSomePlaceElse, MyRequest.class));
System.out.println(new Gson().toJson(list2));
Can this be done using Gson ?
Just print it.
List<String> list = Lists.newArrayList(singleJson,fromSomePlaceElse);
System.out.println(list);
Then you can get
[{"name":"name"}, {"name":"MyName"}]
if you want json in form of string,you can directly use ---
new Gson().toJson(yourList, new TypeToken<List<JsonObject>>(){}.getType())
Try the given library to merge any amount of JSON-objects at once. The result can be returned as String or JsonObject (GSON). Please reference the code in this answer.
I am using file properties file and loop through that file.
Properties Config= new Properties();
Config.load(new FileInputStream("c:\\Config.properties"));
Enumeration e = Config.propertyNames();
while (e.hasMoreElements())
{ String key = (String) e.nextElement();
System.out.println(key + " -- " + Config.getProperty(key));
}
My Input in C:\Config.properties is
Input
fun1= abc
fun2=pqr
fun3 mno
Output
fun2 -- pqr
fun1 -- abc
fun3 -- mno
How can i get this what exactly in the Config file.
That's not possible using java.util.Properties as it extends java.util.Hashtable which is by nature unordered.
Your best bet is reading and parsing it yourself using for example a BufferedReader or a Scanner.
I however wonder why ordering is that important. There may be alternatives which I can only suggest if you elaborate the functional requirement behind this all in detail. Based on the given example, the closest what I can suggest you is the following:
List<String> funs = new ArrayList<String>();
for (int i = 1; i < Integer.MAX_VALUE; i++) {
String fun = config.getProperty("fun" + i);
if (fun == null) break;
funs.add(fun);
}
// ...
Properties is not an ordered map so you might want to create a SortedMap from the loaded properties. This guarantees that the keys are naturally ordered. But i assume you want the order to be the one that you specify in the properties file. There is no way to do it automatically. You need to code it yourself.
As BalusC suggested read line by line from beginning using file API, create a Pair/Tuple object and insert it in the List object or add it to SortedMap based upon your usage requirement
I would be shocked if there isn't a library that already does this. Try Apache Configuration, for example.