Search code examples
javacode-generationjavassistunivocity

Univocity - Is it possible to parse a file to a runtime generated bean/class?


I am using univocity to parse some files to javabeans. These beans are compiled classes. However I wish to generate these classes during runtime and then parse the files to the at runtime generated classes.

Full code is here: gist

A snippet of the code that uses the Univocity library:

private static void parseBean(final Class<?> dynamicClass) throws FileNotFoundException {
        @SuppressWarnings("unchecked")
        final BeanListProcessor<?> rowProcessor = new BeanListProcessor<Class<?>>((Class<Class<?>>) dynamicClass);

        final CsvParserSettings parserSettings = new CsvParserSettings();
        parserSettings.setProcessor(rowProcessor);
        parserSettings.setHeaderExtractionEnabled(false);
        parserSettings.getFormat().setDelimiter('|');
        parserSettings.setEmptyValue("");
        parserSettings.setNullValue("");

        final CsvParser parser = new CsvParser(parserSettings);
        parser.parse(new FileReader("src/main/resources/person.csv"));

        final List<?> beans = rowProcessor.getBeans();
        for (final Object domain : beans) {
            final Domain domainImpl = (Domain) domain;
            System.out.println("Person id is: " + domainImpl.getIdentifier());
            System.out.println("Person name is: " + domainImpl.getColumnByIndex(1));
            System.out.println();
        }
    }

The file looks like this:

0|Eric
1|Maria

All the values seems to be null, so something is going wrong when parsing the file and mapping it to the bean...

Person id is: null
Person name is: null 

Is it possible to parse files to runtime generated beans/classes using the Univocity library?


Solution

  • The problem here is that your code is not generating the @Parsed annotations correctly. Check this:

        Object o = dynamicClass.newInstance();
        Field f = dynamicClass.getDeclaredField("id");
        f.setAccessible(true);
        java.lang.annotation.Annotation[] annotations = f.getAnnotations();
        System.out.println(Arrays.toString(annotations));
    

    You will get an empty annotation array. I've fixed your code to generate the annotations properly:

    Change your addAnnotation method to this:

    private static void addAnnotation(final CtClass clazz, final String fieldName, final String annotationName, String member, int memberValue) throws Exception {
        final ClassFile cfile = clazz.getClassFile();
        final ConstPool cpool = cfile.getConstPool();
        final CtField cfield = clazz.getField(fieldName);
    
        final AnnotationsAttribute attr = new AnnotationsAttribute(cpool, AnnotationsAttribute.visibleTag);
        final Annotation annot = new Annotation(annotationName, cpool);
        annot.addMemberValue(member, new IntegerMemberValue(cpool, memberValue));
        attr.addAnnotation(annot);
        cfield.getFieldInfo().addAttribute(attr);
    }
    

    And call it like this:

    addAnnotation(cc, "id", "com.univocity.parsers.annotations.Parsed","index", 0);
    

    With this change, I can parse a sample input such as this:

    parser.parse(new StringReader("0|John|12-04-1986"));
    

    And will get the following output:

    Person id is: 0
    Person name is: John
    

    Hope this helps.