简体   繁体   中英

How to generate java class from csv file

I have multiple csv files containing about 200 to 300 columns and I need to create pojos out of them with a mapping of one to one (column too java class field). Never mind the fact that is not recommended. If you know a tool or how to do this automatically please pitch in.

so you have a csv file, containing thousands of rows with hundreds of columns, the first row contains the header of the columns. SO what I need, based on the first row (header of column) to create a java class that contains those headers as class fields. Never mind the actual data. I just need a java class with those fields

There was a question regarding somewhat this post but this was asked about 3 years ago, so I guess is obsolete.

You can use Javassist to generate classes at runtime:

Code:

public static void main(String[] args) throws Exception {
    String[] fieldNames = null;
    Class<?> rowObjectClass = null;
    try(BufferedReader stream = new BufferedReader(new InputStreamReader(Program.class.getResourceAsStream("file.csv")))) {
        while(true) {
            String line = stream.readLine();
            if(line == null) {
                break;
            }
            if(line.isEmpty() || line.startsWith("#")) {
                continue;
            }
            if(rowObjectClass == null) {
                fieldNames = line.split(",");
                rowObjectClass = buildCSVClass(fieldNames);
            } else {
                String[] values = line.split(",");
                Object rowObject = rowObjectClass.newInstance();
                for (int i = 0; i < fieldNames.length; i++) {
                    Field f = rowObjectClass.getDeclaredField(fieldNames[i]);
                    f.setAccessible(true);
                    f.set(rowObject, values[i]);

                }
                System.out.println(reflectToString(rowObject));
            }
        }
    }
}

private static int counter = 0;
public static Class<?> buildCSVClass(String[] fieldNames) throws CannotCompileException, NotFoundException {
    ClassPool pool = ClassPool.getDefault();
    CtClass result = pool.makeClass("CSV_CLASS$" + (counter++));
    ClassFile classFile = result.getClassFile();
    ConstPool constPool = classFile.getConstPool();
    classFile.setSuperclass(Object.class.getName());
    for (String fieldName : fieldNames) {
        CtField field = new CtField(ClassPool.getDefault().get(String.class.getName()), fieldName, result);
        result.addField(field);
    }
    classFile.setVersionToJava5();
    return result.toClass();
}

public static String reflectToString(Object value) throws IllegalAccessException {
    StringBuilder result = new StringBuilder(value.getClass().getName());
    result.append("@").append(System.identityHashCode(value)).append(" {");
    for (Field f : value.getClass().getDeclaredFields()) {
        f.setAccessible(true);
        result.append("\n\t").append(f.getName()).append(" = ").append(f.get(value)).append(", ");
    }
    result.delete(result.length()-2, result.length());
    return result.append("\n}").toString();
}


Resources:

file.csv (classpath):

############
foo,bar
############
hello,world
cafe,babe


Output:

CSV_CLASS$0@1324706137 {
    foo = hello, 
    bar = world
}
CSV_CLASS$0@1373076110 {
    foo = cafe, 
    bar = babe
}

As per my undersatnding, you are trying to read a csv file with large range of columns, being treated it as a table for database

My solution is as follows

  • Use csvjdbc to query the data columns

This can be done by using the file as data source and csvjdbc driver, and using the Metadata, you can retrieve all the columns

  • Create a runtime POJO Class using tool Provider

This can be done and a refernce is at here

This version doesn't use any fancy class-generating code; instead, it outputs Java source-files (or more accurately, a single class file, with a static public inner subclass for each non-header row in the CSV).

For the following input (borrowed from Binkan):

############
foo,bar
############
he"l\nl"o,world
cafe,babe

The output would be:

public class Out {
    public static class Row1 {
        public String foo = "he\"l\\nl\"o";
        public String bar = "world";
    }
    public static class Row2 {
        public String foo = "cafe";
        public String bar = "babe";
    }
}

And here is the code; partially adapted from Binkan's as regards line-by-line reading:

public class T {

    public static void classesFromRows(String fileName, PrintWriter out, String classNamePrefix) throws Exception{
        try(BufferedReader stream = new BufferedReader(new FileReader(fileName))) {
            String line = null;
            String[] fields = null;
            int rowNum = 0;
            while ((line = stream.readLine()) != null) {
                if (line.isEmpty() || line.startsWith("#")) {
                    // do nothing
                } else if (fields == null) {
                    fields = line.split(",");
                } else {
                    rowNum ++;
                    String[] values = line.split(",");
                    out.println("\tpublic static class " + classNamePrefix + rowNum + " {");
                    for (int i=0; i<fields.length; i++) {
                        out.println("\t\tpublic String " + fields[i] + " = \"" 
                            + StringEscapeUtils.escapeJava(values[i]) + "\";");
                    }
                    out.println("\t}");
                }           
            }
        }
    }

    // args[0] = input csv; args[1] = output file
    public static void main(String[] args) throws Exception {       
        File outputFile = new File(args[1]);
        String outputClass = outputFile.getName().replace(".java", "");
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)));
        // missing: add a package here, if you want one
        out.println("public class " + outputClass + " {");
        classesFromRows(args[0], out, "Row");
        out.println("}");
        out.close();
    }
}

I have chosen to consider all data as strings (on the bright side, I am escaping them correctly using StringEscapeUtils ); with some more code, you could specify other types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM