I'm using java generics to read a CSV file and create the respective object. I'm making it generic to accept any CSV file and map it to a class.
The first line in my CSV as the class name, then I will read the remaining lines and build an object for each line.
I'm using the CSVReader to help me doing it. But I get compilation errors (I marked them in the code).
Here's my method:
public String importFromCsvFile(File f) throws IOException, ClassNotFoundException
{
FileReader fr = new FileReader(f);
BufferedReader reader = new BufferedReader(fr);
String className = reader.readLine();
//Java reflection to get the Class Object.
Class BeanClass = Class.forName(className);
// Reader reader = new FileReader("persons.csv");
ValueProcessorProvider provider = new ValueProcessorProvider();
CSVEntryParser<BeanClass> entryParser = new AnnotationEntryParser<BeanClass>(BeanClass.class, provider); // BeanClass, cannot find symbol
CSVReader<BeanClass> csvPersonReader = new CSVReaderBuilder<BeanClass>(reader).entryParser(entryParser).build(); // BeanClass, cannot find symbol
List<BeanClass> beanClassList = csvPersonReader.readAll(); // BeanClass, cannot find symbol
System.out.println("First line: " + className);
return "";
}
I'm still building up my method but with this compiling errors I can not move on. Does anyone knows how to fix them?
Again, BeanClass can be any data class I've, so it has to be generic.
Thanks!
You're confusing static class names, known at compile time (like String, or ValueProcessorProvider) with variables referencing a class, only known at runtime. It would be easier to distinguish the two if you respected the Java naming conventions: class names start with upperccase latters, and variables with lowercase letters. So the code should be
FileReader fr = new FileReader(f);
BufferedReader reader = new BufferedReader(fr);
String className = reader.readLine();
//Java reflection to get the Class Object.
Class beanClass = Class.forName(className);
ValueProcessorProvider provider = new ValueProcessorProvider();
CSVEntryParser<beanClass> entryParser = new AnnotationEntryParser<beanClass>(beanClass.class, provider); // BeanClass, cannot find symbol
CSVReader<beanClass> csvPersonReader = new CSVReaderBuilder<beanClass>(reader).entryParser(entryParser).build(); // beanClass, cannot find symbol
List<beanClass> beanClassList = csvPersonReader.readAll(); // BeanClass, cannot find symbol
System.out.println("First line: " + className);
return "";
Now you can immediately see that you're using a variable, beanClass, in places where only literal class names, known at compile-time, can be used: what you must have between <> is a literal class name, not a variable, since it's used by the compiler to ensure type safety. I haven't checked that the following code compiles, but it should be closer than your attempt:
FileReader fr = new FileReader(f);
BufferedReader reader = new BufferedReader(fr);
String className = reader.readLine();
//Java reflection to get the Class Object.
Class<?> beanClass = Class.forName(className);
ValueProcessorProvider provider = new ValueProcessorProvider();
CSVEntryParser<?> entryParser = new AnnotationEntryParser<>(beanClass, provider);
CSVReader<?> csvPersonReader = new CSVReaderBuilder<>(reader).entryParser(entryParser).build();
List<?> beanClassList = csvPersonReader.readAll();
System.out.println("First line: " + className);
return "";
Looking to the class I think that BeanClass is no real class. If a class does not exist, compiler cannot compile it. You shall provide your class (bean) to use. You shall implement
public class BeanClass {
#MapToColumn(column=0)
private String firstColumn;
See http://code.google.com/p/jcsv/wiki/ValueProcessorExample.
Related
i'm having some trouble with reading from a text file back and writing back to an array list. I was wondering if you could tell me where I'm going wrong? Thanks.
accountArrayList = new ArrayList<BankAccount>();
private void fileIn()
{
try
{
createTestAccounts();
//Scanner input = new Scanner(new FileReader(bankFile));
JOptionPane.showMessageDialog(null, "File: " + bankFile + " has been opened for importing");
BufferedReader reader = new BufferedReader(new FileReader("bankFile.txt"));
String account = reader.readLine();
while(account !=null) {
accountArrayList.add(account); // - add a new account to the text file, but exception show that String cannot be converted to Bank Account
account = reader.readLine();
}
reader.close();
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "not found");
}
}
You are adding a String, but the list.add method expects an object of type BankAccount.
You'll have to find a way to turn that String into an Object of that type , then add the latter. Maybe there is a fromString() factory method? Or a Constructor that takes an initialization - String ?
If there is a constructor then it should look like
accountArrayList.add(new BankAccount(account));
To read all lines you may use (if your file is in UTF-8):
List<String> allLines = Files.readAllLines("bankFile.txt", StandardCharsets.UTF_8);
But as it was mentioned in the other comments you will need to transform a String into a BankAccount
BankAccount ba = new BankAccount(account);
accountArrayList.add(ba);
You're going to need something like this...depending on what your BankAccount class is exactly.
Assuming you have a String constructor for BankAccount, something like this:
public BankAccount(String account) {
this.account = account;
}
You can use Apache commons-io and java 8 to get a one-liner!
List<BankAccount> accounts = FileUtils.readLines(new File(filename))
.stream().map(BankAccount::new).collect(Collectors.toList());
The arraylist expects an BankAccount object, instead you are reading from a file, so the arraylist should be String.
ArrayList<String> accountArrayList = new ArrayList<>();
For the while loop condition, personally, i always use, but you can do it like that too.
while((account = reader.readLine()) != null){
accountArrayList.add(account);
}
I'm trying to build up a generic method that parses a CSV file into an Object.
I think I'm quite close to reach the objective but I'm a bit stuck with java generics, I'm still learning it.
Now I'm stuck on my while cycle where I create the objects. I'm using jCSV to do the parsing for me. I'm following their documentation tutorial here.
I can't figure out how to set the beanClass bc = it.next(); because beanClass does not exist as a class on my project, compilation error: cannot find symbol - class beanClass
How can I fix this?
I know I could simply do a List<?> beanClassList = csvFileReader.readAll();
but the problem is that on the first line of each CSV file I've the class name to where that data belongs to. I get this exception, which makes sense:
Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: "Car"
My CSV files are something like this:
ClassName
value,value,value,value,value
value,value,value,value,value
...
Here's my code:
public String importFromCsvFile(File f) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
{
FileReader fr = new FileReader(f);
BufferedReader buffReader = new BufferedReader(fr);
String className = buffReader.readLine();
buffReader.close();
//Java reflection to get the Class Object.
Class beanClass = Class.forName("model." + className);
Object beanObject = beanClass.newInstance();
Reader reader = new FileReader(f);
ValueProcessorProvider provider = new ValueProcessorProvider();
CSVEntryParser<?> entryParser = new AnnotationEntryParser<>(beanClass, provider);
CSVReader<?> csvFileReader= new CSVReaderBuilder<>(reader).entryParser((CSVEntryParser<Object>) entryParser).build();
Iterator<?> it = csvFileReader.iterator();
while (it.hasNext()) {
beanClass bc = it.next(); // here is the compilation error
}
}
Here's a CSV file example:
Car
1,BMW,Z3,2000,20-AC-57
2,Mercedes,C4,2010,23-32-VJ
3,Alfa Romeo,A3,1992,XX-XX-XX
you are nearly there.
public String importFromCsvFile(File f) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
{
FileReader fr = new FileReader(f);
BufferedReader buffReader = new BufferedReader(fr);
String className = buffReader.readLine();
buffReader.close(); // you can also not close it and use buffReader as your reader for the CSV
//Java reflection to get the Class Object.
Class beanClass = Class.forName("model." + className);
Object beanObject = beanClass.newInstance(); // this is never needed
Reader reader = new FileReader(f); // use buffReader instead of creating a new one
ValueProcessorProvider provider = new ValueProcessorProvider();
CSVEntryParser<?> entryParser = new AnnotationEntryParser<>(beanClass, provider);
CSVReader<?> csvFileReader= new CSVReaderBuilder<>(reader).entryParser((CSVEntryParser<Object>) entryParser).build();
Iterator<?> it = csvFileReader.iterator();
while (it.hasNext()) {
Object obj = it.next(); // obj is an instance of Car with your data
boolean isCar = obj instanceof Car; // will be true
}
}
Because you are using , as separator you should consider using UK_DEFAULT as Strategy for the Reader or defining your own (the default separator is ;).
You should also either continue using the BufferedReader or specify skipHeader in the Strategy - else you Car will be treated as entry which is probably not what you want.
As per your comments Please have a look at sample code that reads data from CSV file and store in a map as key-value pair.
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
BufferedReader reader = new BufferedReader(new FileReader(new File("resources/abc.csv")));
String header = reader.readLine();
String[] keys = header.split(",");
String line = null;
while ((line = reader.readLine()) != null) {
Map<String, String> map = new HashMap<String, String>();
String[] values = line.split(",");
for (int i = 0; i < keys.length; i++) {
map.put(keys[i], values[i]);
}
list.add(map);
}
reader.close();
for(Map<String, String> map:list){
for(String key:map.keySet()){
System.out.println(key+":"+map.get(key));
}
System.out.println();
}
CSV:
ID,NAME,MODEL,YEAR,NUMBER
1,BMW,Z3,2000,20-AC-57
2,Mercedes,C4,2010,23-32-VJ
3,Alfa Romeo,A3,1992,XX-XX-XX
With generics, types are specified at compile time (and checked by the compiler). In your case, types are only specified in the CSV file and thus unknown at compile time. So generics is not a tool you can use in this case.
What exactly would you want to accomplish with generics? What would you like the compiler to check?
What you can do is create an instance of the class (you will need a full name including package) using Class.forName(name).newInstance() and use reflection to set some properties. But at compile time you'll only know the result is an Object.
I have a Vehicle class which contains all information about Vehicle objects including get and set methods. There is also a Showroom class which maintains a list of all of the Vehicle objects, with methods to add/delete and scroll through the list.
In my main (a seperate class called VehicleDriverClass) I am trying to use I/O to write Vehicle data to a file and read in Vehicle data from a file. I can write to a file fine. I am using notepad and so a .txt file to read from. The problem I am having is with how to terminate the end of a line when reading from the file. Here is the constructor for the Vehicle class, so you know the paramaters.
public Vehicle(String man, String mod, String VIN, String dateOfMan, char taxBand, int costOfVehicle)
{
this.manufacturer = man;
this.model = mod;
this.VIN = VIN;
this.dateOfManufacture = dateOfMan;
this.taxBand = taxBand;
this.costOfVehicle = costOfVehicle;
}
This is what I have for the Input method at the moment (without trying to create the oject, just reading from file). The Showroom s being passed to it is for use later, when I create the vehicle object and add it to the showroom.
// code replaced below.
With this implementation when the dataFromFile is outputted to the console it is all on one line, rather than on new lines. Does readline() not terminate the line when '\n' is read in?
Here is how my data is stored in the input file.
Fordtest\n Focus\n frank\n ioCheck\n 09/01/1989\n 23/11/2013\n true\n d\n 1995\n
So for now, how do I get the line to terminate? So that I can then implement the creation of an object from this.
EDIT: I/O is working now. I am now having trouble with the constructor for my Vehicle object needing a the data types char and int for the last two variables. With the current method they are in a string array.
I have removed the code from above and added the new implementation below.public static void
addNewVehicleFromFile(Showroom s)
{
String dataFromFile;
String[] tokens = null;
try
{
File fileReader = new File("AddNewVehicleFromFile.txt");
FileReader fr = new FileReader(fileReader);
BufferedReader br = new BufferedReader(fr);
while ((dataFromFile = br.readLine()) != null)
{
tokens = dataFromFile.split("~");
}
System.out.println(Arrays.toString(tokens));
Vehicle inputVehicle = new Vehicle(tokens[0], tokens[1], tokens[2], tokens[3],
tokens[4], tokens[5]);
/*
Erorr above here with these two. token[4] should be a char and [5] an int
*/
s.addVehicle(inputVehicle);
System.out.println("addNewVehicleFromFile Complete");
}
catch (FileNotFoundException fnfe)
{
System.out.println("File not found exception: " + fnfe.toString());
}
catch (IOException ioe)
{
System.out.println("I/O exception: " + ioe.toString());
}
}
Should I be writing my own toChar and toInt methods to call for these two variables? Or parsing to int or similar.
I think you'll do better if you change your input data format. This is what XML and JSON were born for. If you must persist with your current arrangement, change the delimiter between data elements to something like a tilde '~' instead of \n.
So your input looks like this:
Fordtest~Focus~frank~ioCheck~09/01/1989~23/11/2013~true~d~1995
It's easy to parse now:
String [] tokens = data.split("~");
Write yourself some factory methods to create Vehicles:
public class VehicleFactory {
private static final VehicleFactory INSTANCE= new VehicleFactory();
private VehicleFactory() {}
public static VehicleFactory getInstance() { return INSTANCE; }
public static Vehicle createVehicle(String data) {
Vehicle value = null;
String [] tokens = data.split("~");
if ((tokens != null) && (tokens.length > X)) {
// Map String to int or Date here
value = new Vehicle(tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
}
return value;
}
public static List<Vehicle> createVehicles(File f) {
List<Vehicle> values = new ArrayList<Vehicle>();
// implementation left for you
return values;
}
}
readLine() terminates the line when a character matching the Java syntax of \n is read. In most text editors, this is a newline. To express a newline in a Java string, use \n in the source code, but when creating the file by hand, use:
Fordtest
Focus
frank
ioCheck
09/01/1989
23/11/2013
true
d1995
i have an issue with the understanding the arraylist which contain the objects from different classes. I have 6 objects. All of objects have 2 attributes in common.(ID,Type)
Every object has its own attributes. I created mainObject class with 2 atr (ID,Type). The other objects extends the mainObject so they have
class mainClass{
this.id=id;
this.type=type;
}
class extendedClass extends mainClass{
super(ID,Type);
this.atr1=atr1;
}
class extendedClass2 extends mainClass{
super(ID,type);
this.atr2=atr2;
this.atr3=atr3;
}
I read the informations from file.
FileInputStream fstream = new FileInputStream("data.txt");
// Get the object of DataInputStream
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
// Read File Line By Line
while ((strLine = br.readLine()) != null) {
// Print the content on the console
String s[] = strLine.split("\\|");
mainClass myObj = new mainClass(s[0], s[1]);
ArrayList<mainClass> items = new ArrayList<mainClass>();
items.add(myObj);
I need all objects to be readed from file line by line and store them in the array list.
How should i do this? I tried the ArrayList<Object> list = new ArrayList<Object>, but its not working. The point is read all the objects from file, sort them due to chosen attribute(id,type).
You are correct that you need a list of mainClass:
ArrayList<mainClass> items = new ArrayList<mainClass>();
However you should put this line before the while loop, not inside it.
ArrayList<mainClass> items = new ArrayList<mainClass>();
while ((strLine = br.readLine()) != null) {
// etc...
items.add(myObj);
}
I wrote a flesch reading program that uses another class. I was under the impression that simply having the two classes saved in the same folder would enable one to access the other but I am getting errors. Any ideas.
The error I am getting is:
Flesch.java:36: cannot find symbol
symbol : method getSyllableCt()
location: class Flesch
sllyablesCt = getSyllableCt();
flesh is here:
public class Flesch{
public static void main(String args[])throws Exception{
int syllablesCt,
wordCt,
sentenceCt;
double flesch;
String listStr;
StringBuffer sb = new StringBuffer();
String inputFile = JOptionPane.showInputDialog("What file do you want to sort?");
BufferedReader inFile = new BufferedReader(new FileReader(inputFile));
sb.append(inFile.readLine());
//listStr = inFile.readLine();
while (inFile.readLine() != null){
sb.append(inFile.readLine());
//listStr = inFile.readLine();
}
Sentence sentence = new Sentence(sb);
wordCt = getWordCt();
sentenceCt = getSentenceCt();
System.out.println("The sentence count is" + sentenceCt);
System.out.println("The word count is" + wordCt());
Word word = new Word(getWords());
sllyablesCt = getSyllableCt();
System.out.println("The syllable count is" + syllablesCt);
flesch = (.39 * wordCt / sentenceCt) + (11.8 * syllablesCt / wordCt) - 15.59;
System.out.println("The Flesch Readability of this document is" + flesch);
inFile.close();
}
}
If the methods live in another class they need to either be (a) referenced as static methods, or (b) called on an instance of the class.
// Static method
int syllableCount = TheOtherClassName.getSyllableCt();
// Instance method
TheOtherClassName otherClass = new TheOtherClassName();
int syllableCount = otherClass.getSyllableCt();
However it's not clear where the methods in question live, or how they're getting their data.
if the method is in another class, you need to be make the class static.
ClassName.getSyllableCt();
sllyablesCt = getSyllableCt();
Your code has a typo. That variable doesn't exist. Change it to
syllablesCt = getSyllableCt();