Get the data from the pojo classes of the JSON file - java

I have the following JSON array as file in my Jersey project in src/main/resources/routes.txt. I want to convert it to Java object to get the time in the case of mon-fri or sat or sun. I have generated the classes below with the help of this link. How can I get the time from the ArrivalTime class with this generated structure? Should I put all these generated classes as inner classes of the root class or separately?
I appreciate any help.
JSON simple:
[{
"route": 1,
"info": {
"stops": {
"arrival_time": {"mon-fri": ["04:24","05:10","05:40"],
"sat": ["05:34","05:55","06:15"],
"sun": ["07:00","08:00","05:40"]
},
"stops_name": "Tension Way"
},
"direction": "Surrey Quays"
}
}]
Generated classes:
public class Root {
private Integer route;
private Info info;
}
public class Info {
private Stops stops;
private String direction;
}
public class Stops {
private ArrivalTime arrivalTime;
private String stopsName;
}
public class ArrivalTime {
private List<String> monFri = new ArrayList<String>();
private List<String> sat = new ArrayList<String>();
private List<String> sun = new ArrayList<String>();
}
Code:
ObjectMapper mapper = new ObjectMapper();
FileReader fileReader;
try {
fileReader = new FileReader("src/main/resources");
try {
Root readValue = mapper.readValue(fileReader, Root.class);
readValue.getInfo();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

List<String> monFri = readValue().getInfo().getStops().getArrivalTime().getMonFri();
That's the structure of the JSON object, and is also the structure of the Java object mapped to the JSON.
The classes should be top-level classes, or static nested classes, but not inner classes.

Related

Updating Json file when String ist not present in list

I am coding a Discord Giveaway Bot with Java. I am saving all the details of the Giveaway to a JSON file. Now I want to read the entries list and if the Users ID is not in the list I want to add it and save the file.
Here is the Giveaway Class:
public class Giveaway {
private String prize;
private long time;
private Integer winners;
private List<String> entries;
public Giveaway(String prize, Integer winners, long time, List<String> entries) {
this.prize = prize;
this.winners = winners;
this.time = time;
this.entries = entries;
}
public Giveaway() {}
public String getPrize() {
return prize;
}
public void setPrize(String prize) {
this.prize = prize;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public Integer getWinners() {
return winners;
}
public void setWinners(Integer winners) {
this.winners = winners;
}
public List<String> getEntries() {
return entries;
}
public void setEntries(List<String> entries) {
this.entries = entries;
}
}
When the GW is created the JSON looks like this:
{
"prize": "Discord Nitro",
"time": 1641732935,
"winners": 2,
"entries": []
}
Then when the user clicks a button it should read the list look if the ID is in the list and if not add the id. But when I save the list the whole JSON file changes.
How I read it out and save it:
public class ButtonClick extends ListenerAdapter {
private static Reader reader;
private static Giveaway giveaway = new Giveaway();
public void onButtonClick(ButtonClickEvent event) {
event.deferEdit().queue();
try {
reader = Files.newBufferedReader(Path.of(GiveawayStats.getGiveawayStats().getAbsolutePath()));
} catch (IOException e) {
e.printStackTrace();
}
if (event.getButton().getId().equals("gwEnter")) {
JsonParser parser = new JsonParser();
JsonObject obj = parser.parse(reader).getAsJsonObject();
JsonArray jsonEntries = obj.get("entries").getAsJsonArray();
long time = obj.get("time").getAsLong();
List<String> entries = new ArrayList<>();
for (JsonElement entrie : jsonEntries) {
entries.add(entrie.toString());
}
if (entries.contains(event.getMember().getId())) {
event.getChannel().sendMessage("Already in!").queue();
} else {
entries.add(event.getUser().getId().strip());
printToJson(entries);
}
}
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void printToJson(List<String> entries) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setVersion(2.0);
Gson gson = gsonBuilder.setPrettyPrinting().create();
giveaway.setEntries(entries);
try (Writer writer = new FileWriter(GiveawayStats.getGiveawayStats().getPath())) {
gson.toJson(giveaway, writer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
After the print so JSON the file looks like this:
{
"time": 0,
"entries": [
"695629580014321747"
]
}
And when I click the Button again it looks like this:
{
"time": 0,
"entries": [
"\"695629580014321747\"",
"695629580014321747"
]
}
So why is my IF condition not working?
You are using entrie.toString() which gives you the string that is used for console output. You should be using entrie.getAsString() instead.
Furthermore, you are also using a lot of deprecated things with JsonParser which should be replaced. new JsonParser().parse(...) should be replaced by JsonParser.parseReader(...).
Above all that, it is highly recommended using a database for this kind of task. Something such as SQLite or Redis would be much better at handling concurrent changes and redundancy. Or at least, you should use a try-with-resources for your reader.
try (Reader reader = ...) {
JsonElement json = JsonParser.parseReader(reader).getAsJsonObject();
...
}

How can I iterate through JSON objects using Jackson?

I ultimately want to create inverted indexes using my JSON dataset. I know how to parse through one JSON object but how can I iterate through many? Here is what I have working:
File1:
{
"doc_id": "2324jos",
"screen_name": "twitter_user101",
"tweet_text": "Its a beautiful day to be productive",
"hashtags": "[]",
"links": "[]",
"place_type": "city",
"place_name": "Evergreen Park",
"created_at": "2019-02-08 22:24:03"
}
My code:
public class ParseJson {
public static void main(String[] args) throws Exception {
// this is the key object to convert JSON to Java
Tweet tweet;
ObjectMapper mapper = new ObjectMapper();
try {
File json = new File("test.json");
tweet = mapper.readValue(json, Tweet.class);
System.out.println("Java object created from JSON String :");
System.out.println(tweet);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public class Tweet {
public String doc_id;
public String screen_name;
public String tweet_text;
public String hashtags;
public String links;
public String place_type;
public String place_name;
public String created_at;
public Tweet() {
}
public Tweet(String doc_id, String screen_name, String tweet_text, String hashtags, String links, String place_type, String place_name, String created_at) {
this.doc_id = doc_id;
this.screen_name = screen_name;
this.tweet_text = tweet_text;
this.hashtags = hashtags;
this.links = links;
this.place_name = place_name;
this.place_type = place_type;
this.created_at = created_at;
}
#Override
public String toString() {
return doc_id + screen_name + tweet_text;
}
}
Now, I want to iterate through this JSON file which has 2 JSON objects in an array:
File2:
[
{
"doc_id": "2324jos",
"screen_name": "b'LIBBYRULZ'",
"tweet_text": "#ABC ya'll be lying",
"hashtags": "[]",
"links": "[]",
"place_type": "city",
"place_name": "Evergreen Park",
"created_at": "2019-02-08 22:24:03"
},
{
"doc_id": "8982hol",
"screen_name": "b'eddylee_1'",
"tweet_text": "Hungry for money",
"hashtags": "[]",
"links": "[]",
"place_type": "city",
"place_name": "Manhattan",
"created_at": "2/7/2019 17:01"
}
]
How can I adjust my above code using Jackson to do so where the doc_id is the unique key? I want to be able to return all the data in each JSON object for each doc_id.
To parse an array of JSON objects using Jackson:
Tweet[] tweets = mapper.readValue(json, Tweet[].class);
should do the trick. See below:
public class ParseJson {
public static void main(String[] args) throws Exception {
Tweet[] tweets;
ObjectMapper mapper = new ObjectMapper();
try {
File json = new File("test.json");
tweets = mapper.readValue(json, Tweet[].class);
System.out.println("Java object created from JSON String :");
Arrays.asList(tweets).forEach(System.out::println); // Prints each element in the array
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
You could try to put it in a list so you can iterate on it:
List<Tweet> data = mapper.readValue(json, new TypeReference<List<Tweet>>(){});
I would suggest using the TypeFactory to create a CollectionType and use it to parse the JSON as List<Tweet>.
CollectionType tweetListType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, Tweet.class);
List<Tweet> tweets = mapper.readValue(json, tweetListType);
tweets.forEach(System.out::println);
Here is the complete example you shared:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ParseJson {
public static void main(String[] args) {
// this is the key object to convert JSON to Java
ObjectMapper mapper = new ObjectMapper();
try {
File json = new File("test.json");
CollectionType tweetListType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, Tweet.class);
List<Tweet> tweets = mapper.readValue(json, tweetListType);
System.out.println("Java objects created from JSON String:");
tweets.forEach(System.out::println);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

Instantiate objects by configuration file on java

I have this object:
public class TheObjectToInstantiate{
public String Name;
public String Surname;
public TheObjectToInstantiate(){
}
}
I want to instantiate an array of TheObjectToInstantiate[] with configuration file:
TheObjectToInstantiate1.Name="Pippo"
TheObjectToInstantiate1.Surname="PippoSurname"
TheObjectToInstantiate2.Name="Pluto"
TheObjectToInstantiate2.Surname="PlutoSurname"
I've tried with
public ConfigReader(){
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream("configuration.prop");
prop.load(input);
Enumeration<?> e = prop.propertyNames();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
String value = prop.getProperty(key);
......
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
scanning all properties and instatiate object manually.
There are ways or open source wrapper to do this without manually compare all properties?
Thanks
It's easier to use json files and deserialize them with libraries like Jackson. You may also check http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson
and How to use Jackson to deserialise an array of objects
public class TheObjectToInstantiate {
public String Name;
public String Surname;
public TheObjectToInstantiate(){}
}
public class JacksonExample {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
try {
// Convert JSON string from file to Object
TheObjectToInstantiate object = mapper.readValue(new File("G:\\myobject.json"), TheObjectToInstantiate.class);
} catch (IOException e) {
e.printStackTrace();
}
}
json file would be like this:
{
"Name" : "foo",
"Surname" : "bar"
}
you can also deserialize a list of objects:
List<TheObjectToInstantiate> myObjects = mapper.readValue(new File("G:\\myobjectlist.json"), new TypeReference<List<TheObjectToInstantiate>>(){});
[{
"Name" : "foo1",
"Surname" : "bar1"
},
{
"Name" : "foo2",
"Surname" : "bar2"
}]
It also supports more complex structures like nested objects or a List or array of other objects inside your primary object.

jsonschema2pojo not generating pojo classes from json string

I was following the link Generate Java class from JSON? to create the POJO classes from json string (and not from schema). I am using jsonschema2pojo jar of version 0.4.10 but could not able to generate the POJO class.
My code is as below,
public class App
{
public static void main( String[] args )
{
JCodeModel codeModel = new JCodeModel();
try {
URL source = new URL("file:///C://Users//...//accession.json");
new SchemaMapper().generate(codeModel, "Accession", "com.test", source);
File dir = new File("D://test");
if(dir.exists()){
System.out.println("dir available");
codeModel.build(dir);
}else{
System.out.println("dir not available");
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
So accession.json has json string which need to be converted into POJO. Can anybody please help me here.
I had a similar experience using the command-line tool. In my case, it was the result of not correctly specifying the source type (JSONSCHEMA or JSON; default: JSONSCHEMA).
I think your problem is similar: You're using the default (no-args) constructor for SchemaMapper. The following steps should solve the problem:
Subclass org.jsonschema2pojo.DefaultGenerationConfig, overriding getSourceType() to return SourceType.JSON
Use an instance of that subclass for the SchemaMapper(RuleFactory ruleFactory, SchemaGenerator schemaGenerator) constructor (instead of the no-args constructor).
Once I faced the same problem and then I resolved this.
In your code you are using Default Configuration which takes Source Type Jason Schema.
But when You are giving input Jason you have to set this return type in this way :
SourceType.JSON in your Configuration.
class App
{
public static void main( String[] args )
{
JCodeModel codeModel = new JCodeModel();
try {
URL source= new URL("file:///D:/temp.json");
GenerationConfig config = new DefaultGenerationConfig() {
#Override
public boolean isGenerateBuilders() {
return true;
}
public SourceType getSourceType(){
return SourceType.JSON;
}
};
SchemaMapper mapper =new SchemaMapper(new RuleFactory(config, new GsonAnnotator(), new SchemaStore()), new SchemaGenerator());
mapper.generate(codeModel, "Accession", "com.test", source);
File dir = new File("D://");
if(dir.exists()){
System.out.println("dir available");
codeModel.build(dir);
}else{
System.out.println("dir not available");
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I hope It will help you..
Good Luck !!
I also struggled a bit with this. I did the following in the end:
Created my own GenerationConfig, overriding getSourceType:
static class MyConfig extends DefaultGenerationConfig {
#Override
public SourceType getSourceType() {
return SourceType.JSON;
}
}
I then initialised the build process as follows:
private void parseFileExample() {
URL source = new URL("file:/tmp/input/blah.json");
JCodeModel codeModel = new JCodeModel();
MyConfig generationConfig = new MyConfig();
RuleFactory ruleFactory = new RuleFactory(generationConfig, new GsonAnnotator(), new SchemaStore());
SchemaGenerator generator = new SchemaGenerator();
SchemaMapper mapper = new SchemaMapper(ruleFactory, generator);
mapper.generate(codeModel, "MyClass", "com.drakedroid", source);
codeModel.build(new File("/tmp/output/"));
}
The trick here was, to use an URL. The mapper.generate didn't work when I passed in just a string.
Thanks #Kapil, your answer helped me.
This program allows us to generate POJO classes according to predefined JSON.
We can also use it at runtime, where JSON response is not known, write the JSON response to the file and read it accordingly using the following code.
public class JSONExample {
public static void main(String... args) {
JCodeModel codeModel = new JCodeModel();
try
{
// In sample.json I have already pasted a JSON
File file=new File("//root//AndroidStudioProjects//MyApplication//sample.json");
URL source = file.toURI().toURL();
GenerationConfig config = new DefaultGenerationConfig() {
#Override
public boolean isGenerateBuilders()
{
return true;
}
public SourceType getSourceType()
{
return SourceType.JSON;
}
};
SchemaMapper mapper = new SchemaMapper(new RuleFactory(config, new Jackson2Annotator(), new SchemaStore()), new SchemaGenerator());
try {
// The ClassName is the main class that will contain references to other generated class files
// com.example is the package name
mapper.generate(codeModel, "ClassName", "com.example", source);
} catch (IOException e) {
e.printStackTrace();
}
try {
// Directory where classes will be genetrated
File file1=new File("//root//AndroidStudioProjects//MyApplication//");
if (file1.exists())
{
System.out.println("dir available");
codeModel.build(file1);
}
else
{
System.out.println("dir not available");
}
System.out.println(""+file1+" Exists "+file1.exists());
} catch (IOException e) {
e.printStackTrace();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}

How to write a unit test for an XML parser I wrote in Java

The context is as follows:
I've got objects that represent Tweets (from Twitter). Each object has an id, a date and the id of the original tweet (if there was one).
I receive a file of tweets (where each tweet is in the format of 05/04/2014 12:00:00, tweetID, originalID and is in its' own line) and I want to save them as an XML file where each field has its' own tag.
I want to then be able to read the file and return a list of Tweet objects corresponding to the Tweets from the XML file.
After writing the XML parser that does this I want to test that it works correctly. I've got no idea how to test this.
The XML Parser:
public class TweetToXMLConverter implements TweetImporterExporter {
//there is a single file used for the tweets database
static final String xmlPath = "src/main/resources/tweetsDataBase.xml";
//some "defines", as we like to call them ;)
static final String DB_HEADER = "tweetDataBase";
static final String TWEET_HEADER = "tweet";
static final String TWEET_ID_FIELD = "id";
static final String TWEET_ORIGIN_ID_FIELD = "original tweet";
static final String TWEET_DATE_FIELD = "tweet date";
static File xmlFile;
static boolean initialized = false;
#Override
public void createDB() {
try {
Element tweetDB = new Element(DB_HEADER);
Document doc = new Document(tweetDB);
doc.setRootElement(tweetDB);
XMLOutputter xmlOutput = new XMLOutputter();
// display nice nice? WTF does that chinese whacko want?
xmlOutput.setFormat(Format.getPrettyFormat());
xmlOutput.output(doc, new FileWriter(xmlPath));
xmlFile = new File(xmlPath);
initialized = true;
} catch (IOException io) {
System.out.println(io.getMessage());
}
}
#Override
public void addTweet(Tweet tweet) {
if (!initialized) {
//TODO throw an exception? should not come to pass!
return;
}
SAXBuilder builder = new SAXBuilder();
try {
Document document = (Document) builder.build(xmlFile);
Element newTweet = new Element(TWEET_HEADER);
newTweet.setAttribute(new Attribute(TWEET_ID_FIELD, tweet.getTweetID()));
newTweet.setAttribute(new Attribute(TWEET_DATE_FIELD, tweet.getDate().toString()));
if (tweet.isRetweet())
newTweet.addContent(new Element(TWEET_ORIGIN_ID_FIELD).setText(tweet.getOriginalTweet()));
document.getRootElement().addContent(newTweet);
} catch (IOException io) {
System.out.println(io.getMessage());
} catch (JDOMException jdomex) {
System.out.println(jdomex.getMessage());
}
}
//break glass in case of emergency
#Override
public void addListOfTweets(List<Tweet> list) {
for (Tweet t : list) {
addTweet(t);
}
}
#Override
public List<Tweet> getListOfTweets() {
if (!initialized) {
//TODO throw an exception? should not come to pass!
return null;
}
try {
SAXBuilder builder = new SAXBuilder();
Document document;
document = (Document) builder.build(xmlFile);
List<Tweet> $ = new ArrayList<Tweet>();
for (Object o : document.getRootElement().getChildren(TWEET_HEADER)) {
Element rawTweet = (Element) o;
String id = rawTweet.getAttributeValue(TWEET_ID_FIELD);
String original = rawTweet.getChildText(TWEET_ORIGIN_ID_FIELD);
Date date = new Date(rawTweet.getAttributeValue(TWEET_DATE_FIELD));
$.add(new Tweet(id, original, date));
}
return $;
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Some usage:
private TweetImporterExporter converter;
List<Tweet> tweetList = converter.getListOfTweets();
for (String tweetString : lines)
converter.addTweet(new Tweet(tweetString));
How can I make sure the the XML file I read (that contains tweets) corresponds to the file I receive (in the form stated above)?
How can I make sure the tweets I add to the file correspond to the ones I tried to add?
Assuming that you have the following model:
public class Tweet {
private Long id;
private Date date;
private Long originalTweetid;
//getters and seters
}
The process would be the following:
create an isntance of TweetToXMLConverter
create a list of Tweet instances that you expect to receive after parsing the file
feed the converter the list you generated
compare the list received by parsing the list and the list you initiated at the start of the test
public class MainTest {
private TweetToXMLConverter converter;
private List<Tweet> tweets;
#Before
public void setup() {
Tweet tweet = new Tweet(1, "05/04/2014 12:00:00", 2);
Tweet tweet2 = new Tweet(2, "06/04/2014 12:00:00", 1);
Tweet tweet3 = new Tweet(3, "07/04/2014 12:00:00", 2);
tweets.add(tweet);
tweets.add(tweet2);
tweets.add(tweet3);
converter = new TweetToXMLConverter();
converter.addListOfTweets(tweets);
}
#Test
public void testParse() {
List<Tweet> parsedTweets = converter.getListOfTweets();
Assert.assertEquals(parsedTweets.size(), tweets.size());
for (int i=0; i<parsedTweets.size(); i++) {
//assuming that both lists are sorted
Assert.assertEquals(parsedTweets.get(i), tweets.get(i));
};
}
}
I am using JUnit for the actual testing.

Categories

Resources