How to read JSON file in reactive way using spring webflux? - java

I am trying to read file from classpath in a reactive way using spring webflux. I am able to read the file. But I am not able to parse into an Foo object.
I am trying the following way, but not sure how to convert to an FOO class.
public Flux<Object> readFile() {
Flux<DataBuffer> readFile1 = DataBufferUtils.read("classpath:test.json", new DefaultDataBufferFactory(), 4096);
return new Jackson2JsonDecoder().decode(readFile1,
ResolvableType.forType(List.class,Foo.class), null, Collections.emptyMap());
}
Help appreciated.

I think you are doing it correctly but you unfortunately must cast the Object back into the correct type. This is safe to do because the JSON decoding will fail if it was unable to construct a list of Foo:
public Flux<Foo> readFile() {
ResolvableType type = ResolvableType.forType(List.class,Foo.class);
Flux<DataBuffer> data = DataBufferUtils.read("classpath:test.json", new DefaultDataBufferFactory(), 4096);
return new Jackson2JsonDecoder().decode(data, type, null, null)
.map(Foo.class::cast);
}

You can use jackson ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
Student student = mapper.readValue(jsonString, Student.class);
And before that, you should read the file and use FileReader and readLines() to parse line by line.
[UPDATE]
Ok, for reading file, reactive means, reading file in a stream, and whenever a line is read, process this line. From this point, the BufferReader.readLines will be fine. But if you really want to use reactive way, you can use:
package com.test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class TestReadFile {
public static void main(String args[]) {
String fileName = "c://lines.txt";
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(parseLine);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Related

how to add data to XML files in java

how can i add data to an xml file and append to it ohter data if it exists ?
i tried the following but this code only creates one node of values and does not append to the file. it always removes the existing one and add the new one to it.
import java.beans.XMLEncoder;
import java.beans.XMLDecoder;
import java.io.*;
public class Main {
public static void main(String[] args) {
Question quest = new Question("Mouhib 9a7boun ?", "EYY");
try {
FileOutputStream fos = new FileOutputStream(new File("./quest.xml"));
XMLEncoder encoder = new XMLEncoder(fos);
encoder.writeObject(quest);
encoder.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you want to append addtional data to an existing file you can use FileOutputStream(File file, boolean append).
BUT this will not lead to a valid xml-file.
You can use XML DOM editing methods:
XML DOM Add Nodes

Custom Framework for Writing a Test that Reads a CSV File into a HashMap

I am trying to complete a lab where the teacher has asked us to write a test that can read a csv file into a hashmap. He gave us two files one called 'ConfigurationProvider.java' and another called basses.csv to use to write a data driven TestNG case.
ConfigurationProvider.java looks like this
package framework;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;
public class ConfigurationProvider {
public HashMap<String, String> getPropertiesFromResourceFile(String fileName) throws Exception {
InputStream inputStream = null;
Properties properties = new Properties();
try {
inputStream = getClass().getClassLoader().getResourceAsStream(fileName);
if(inputStream == null) {
throw new RuntimeException(fileName + " was not found in the Resources folder.");
}
properties.load(inputStream);
}
finally {
inputStream.close();
}
HashMap<String, String> propertyValuesByKey = new HashMap<String, String>();
for (String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
propertyValuesByKey.put(key, value);
}
return propertyValuesByKey;
}
}
and basses.csv looks like this
Make,Model,StringCount
Warwick,Corvette,5
Warwick,Thumb,5
Warwick,Streamer,5
Fender,Precision,4
Fender,Jazz,4
Yamaha,BB500,5
So far I have written the test as follows
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import framework.ConfigurationProvider;
public class BassesProvider {
#Test(dataProvider = "bassProvider")
public void canPrintMap(String make, String model) {
System.out.println(make + ":" + model);
}
#DataProvider(name = "bassProvider")
public Object[][] getData() throws IOException {
String FILE_PATH =
"C:\\Users\\name\\git\\practice\\automation\\src\\test\\resources\\basses.csv";
ConfigurationProvider basses = new ConfigurationProvider();
try {
basses.getPropertiesFromResourceFile(FILE_PATH);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Object[][] data = new Object[2][7];
data[0][0] = basses;
return data;
}
}
I am getting the error: java.lang.NullPointerException: Cannot invoke "java.io.InputStream.close()" because "inputStream" is null, etc... and I'm not sure what changes to make or how to proceed further.
I'm not sure what changes to make or how to proceed further.
First you need to work out why the code is throwing an NPE.
Look carefully at the stacktrace.
Work out where the NPE is thrown.
Work out where the null comes from.
Hint 1: carefully read the javadoc for the method that is setting the variable that contains the null.
Now my understanding is that your actual task is to write unit tests. And (without giving the game away) the reasons you are getting an NPE are a combination of a bug in the code you are testing and a flaw in the way that you have (ummm) set up the test environment.
Hint 2: The ConfigurationProvider code that you are testing is NOT designed to load data from a file in the file system. See Hint 1.

Converting myClass.ChatColor objects to and from .json files result in undesired leading `Â` characters

I'm storing ChatColor objects stored in a class object. After successfully converting them to json using the Gson api, I want to be able to instantiate ChatColor objects in memory from this stored json file.
Using the code below, I get ChatColor objects who's toString methods return §6. they should be returning the same but minus the leading  character
To make this question easier to read I've reduced the examples down to a single ChatColor object per Theme object.
Theme.java
package core.data.objects;
import java.util.Map;
import net.md_5.bungee.api.ChatColor;
public class Theme {
private ChatColor primary, secondary, tertiary, clear, faded, succeed, fail;
public Theme(Map<String, ChatColor> thisMap) {
this.primary = thisMap.get("primary");
}
public ChatColor getPrimary() { return primary; }
public void setPrimary(ChatColor primary) { this.primary = primary; }
}
ThemeManager.java
package core.data;
import core.data.objects.Theme;
import java.io.*;
import java.util.Map;
import java.util.HashMap;
import com.google.gson.Gson;
import net.md_5.bungee.api.ChatColor;
public class ThemeManager {
public static Theme currentTheme;
public static void load() throws IOException {
try {
currentTheme = getThemeFromJSON(FileManager.defaultThemeFile);
System.out.println(ChatColor.GOLD);
System.out.println(currentTheme.getPrimary());
} catch (Exception e) {
currentTheme = createDefaultTheme();
System.out.println("WARN getThemeFromJSON Exception");
throw new IOException(e.getMessage());
}
}
public static Theme createDefaultTheme() {
Map<String, ChatColor> thisMap = new HashMap<>();
thisMap.putIfAbsent("primary", ChatColor.GOLD);
return new Theme(thisMap);
}
public static void writeThemeToJSON(Theme thisTheme, File thisFile) throws IOException {
Gson gson = new Gson();
Writer writer = new FileWriter(thisFile, false);
gson.toJson(thisTheme, writer);
writer.flush(); writer.close();
}
public static Theme getThemeFromJSON(File thisFile) throws FileNotFoundException {
Gson gson = new Gson();
Reader reader = new FileReader(thisFile);
return gson.fromJson(reader, Theme.class);
}
}
Console output of ThemeManager.load()
[20:20:56 INFO]: §6
[20:20:56 INFO]: §6
Example of saved .json file
{
"primary": {
"toString": "§6",
"name": "gold",
"ordinal": 6,
"color": {
"value": -22016,
"falpha": 0.0
}
}
}
The  comes out of nowhere!
Solution credit: #dave_thompson_085
The project (and the .json file) are encoded in UTF-8, but I was not reading the file using UTF-8 encoding. Apparently that is not the default encoding of a FileReader object.
By changing this:
public static Theme getThemeFromJSON(File thisFile) throws FileNotFoundException {
Gson gson = new Gson();
Reader reader = new FileReader(thisFile);
return gson.fromJson(reader, Theme.class);
}
to this:
public static Theme getThemeFromJSON(File thisFile) throws FileNotFoundException {
Gson gson = new Gson();
Reader reader = new InputStreamReader (
new FileInputStream (thisFile), StandardCharsets.UTF_8);
return gson.fromJson(reader, Theme.class);
}
, the stdout lines from ThemeManager.load() are now both showing §6 as expected.
However, note that when using aThemeObject.getPrimary(), the returned ChatColor object was not able to be used in place of regular calls to ChatColor.COLOR.
Trying to do so would simply result in "null" appearing in the displayed text in-game.
To fix this, I modified the get methods to:
public ChatColor getPrimary() {
return ChatColor.getByChar(primary.toString().charAt(1));
}
char at index 1 is the color code used by the getByChar method to return a clone chatcolor object.
This will prevent using custom falpha values and custom color values in the theme.json file, but ensures the resulting ChatColor object from calling Theme.getPrimary() can always be used in place of a regular call to ChatColor.COLOR

Using builder to create nested XML

I'm using the Jackson set of classes to read in a CSV file, and convert it to xml, but need some advice on how to add a nested value.
The code I'm using is:
package reader;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class Mustang
{
public static void main(String[] args) throws Exception
{
// Define the input file
File input = new File("c:\\temp\\all_idocs.csv");
// Define the output file
File output = new File("c:\\temp\\all_idocs.xml");
System.out.println("INFO: Commencing Conversion");
List<Map<?, ?>> data = readObjectsFromCsv(input); // readObjectsFromCSV(input
// file name)
System.out.println(readObjectsFromCsv(input));
writeAsXml(data, output); // writeAsXml function, to output location
System.out.println("INFO: Conversion Complete");
}
public static List<Map<?, ?>> readObjectsFromCsv(File file)
throws IOException
{
CsvSchema schema = CsvSchema.builder()
.addColumn("A0001")
.addColumn("A0186")
.addColumn("A0187")
.addColumn("A0352")
.addColumn("A0539")
.addColumn("A0963")
.addColumn("A1046")
.addColumn("A0792")
.addColumn("A0218")
.addColumn("A0584")
.addColumn("A0016")
.addColumn("A0017")
.addColumn("A0478")
.addColumn("A0051")
.addColumn("A0052")
.addColumn("A0053")
.addColumn("A0059")
.addColumn("A0440")
.addColumn("A0054")
.addColumn("A0055")
.addColumn("A0056")
.addColumn("A0057")
.addColumn("A0058")
.addColumn("A1128")
.addColumn("A0003")
.addColumn("A0069")
.addColumn("A0070")
.addColumn("A0074")
.addColumn("A0073")
.addColumn("A0071")
.addColumn("A0110")
.addColumn("A0109")
.addColumn("A0108")
.build();
CsvMapper csvMapper = new CsvMapper();
MappingIterator<Map<?, ?>> mappingIterator = csvMapper
.reader(Map.class).with(schema).readValues(file); // Change the "with()" to pull in the schema
return mappingIterator.readAll();
}
public static void writeAsXml(List<Map<?, ?>> data, File file)
throws IOException
{
XmlMapper mapper = new XmlMapper();
mapper.writeValue(file, data);
}
}
If I run this against a CSV file, I get output similar to this:
<item>
<A0001>J1000097</A0001>
<A0186>5028197000004</A0186>
<A0187>1</A0187>
<A0352></A0352>
<A0539>00</A0539>
<A0963>20050209</A0963>
</item>
I want to see if it's possible to indent/nest some of these attributes, to produce something like this:
<item>
<A0001>J1000097</A0001>
<A0186>5028197000004</A0186>
<A0187>
<A0352>12</A0352>
<A0539>00</A0539>
</A0187>
<A0963>20050209</A0963>
</item>
I'm assuming I must have to do something within the builder section of the code, but as I'm new to using it, I can't fathom out how.
In this case you may want to process Map after reading it from CSV, but before writing it as XML. You can then add a wrapper around values you want to group. That is, something like:
Map<?,?> value = ... ; // individual row
Map<String,Object> wrapped = new LinkedHashMap<>();
wrapped.put("A0352", value.remove("A0352"));
wrapped.put("A0539", value.remove("A0539"));
value.put("A0187", wrapped);
another possibility would be to use value conversion between Map, and POJO type that uses #JsonUnwrapped to handle grouping.
Conversion itself may be done using:
MyPOJO value = mapper.convertValue(map, MyPOJO.class); // and/or reverse
but this approach may become more complicated.

how to access a method from private static class

im trying to put all stopwords on a hashset, i dont want to add it one by one so im trying to put in a txt file and have my scanner scan it. the problem is i think my code does not reach my scanner here is my code:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
public class StopWords {
public static final Set<String> stopWords = new HashSet<String>();
private static class scan {
public scan()throws IOException {
Scanner s = null;
try{
s = new Scanner(new BufferedReader(new FileReader("stopwords.txt")));
while (s.hasNext()) {
//System.out.println(s.next());
stopWords.add(s.next());
}
}finally{
if (s != null) {
s.close();
}
}
}
}
}
im running my main on other class and im just calling this class. thanks in advance
Make a wrapper for it in enclosing class.
Something like:
public void doScan() {
try {
scan.scan();
catch (IOException e) {};
}
in StopWords class.
This way you could call doScan() on instance of StopWords. You could also make it static.
And I agree that you should follow naming convections of Java language (wikipedia.org).
Just want to add a couple tricks you might consider:
First - you could store your stopwords in a properties file, then use java.util.Properties.load to pull the data in.
Second - you can put your stopwords file on your classpath, and bundle up the stopwords file with the rest of your code in a jar for delivery.
You wind up with something like this:
final Properties stopProps = new java.util.Properties();
stopProps.load( new InputStreamReader( this.class.getClassLoader().getResourceAsStream( "mycode/stopWords.properties", "UTF-8" ) );
...
Good luck!

Categories

Resources