Menu

#54 Reflection-based mapping with spaces in column name not working

Outstanding
closed
nobody
None
1
2014-08-18
2014-08-18
Joost T
No

Finding a property based on columnname doesn't work when there is a space in the column name.

Lets say I have a column name "My Columnname", the ReflectionUtils of SuperCSV will look for a setter named "setMy Columnname", which is not possible in the java I am using.

org.supercsv.exception.SuperCsvReflectionException: unable to find method setMy Columnname(java.lang.String) in class com.example.SomeClass - check that the corresponding nameMapping element matches the field name in the bean, and the cell processor returns a type compatible with the field
context=null
    at org.supercsv.util.ReflectionUtils.findSetter(ReflectionUtils.java:185)
    at org.supercsv.util.MethodCache.getSetMethod(MethodCache.java:96)
    at org.supercsv.io.CsvBeanReader.populateBean(CsvBeanReader.java:154)
    at org.supercsv.io.CsvBeanReader.readIntoBean(CsvBeanReader.java:264)
    at org.supercsv.io.CsvBeanReader.read(CsvBeanReader.java:173)

Please trim spaces so I can use a method named "setMyColumnname".

Discussion

  • James Bassett

    James Bassett - 2014-08-18
    • status: open --> closed
     
  • James Bassett

    James Bassett - 2014-08-18

    Hi,

    Column names (i.e. headers) are totally independent of the field mapping used by CsvBeanReader. You don't have to use the same array for the header and for the field mapping passed to CsvBeanReader.read(). Most of the time you can, but if your headers don't match the bean's field names (as in your example), then you have to use different arrays.

    Please see this example (while it's using CsvBeanWriter, the same principal applies).

    Your code should look something like this:

    // skip the header - you don't need it
    // (you can remove this line if your file doesn't have one)
    beanReader.getHeader(true);
    
    // the field name corresponding to the CSV column
    String[] fieldMapping = new String[]{"myColumn"};
    
    MyBean bean;
    while( (bean = beanReader.read(MyBean.class, fieldMapping)) != null ) {
        // TODO do something
    }
    
     
  • Joost T

    Joost T - 2014-08-18

    I don't like manually configuring my header-names in the code. They are already hard-coded in the CSV files (out of my control) and in my POJO's and I don't feel like maintaining a three-double administration.

    I am currently using the following snippet, which formats the column-names to something java should accept.

    private String[] formatHeaders(String[] header)
    {
      for (int i = 0; i < header.length; i++)
      {
         // Remove characters that are invalid in Java method/property names
         header[i] = StringUtils.remove(header[i], ' ');
         header[i] = StringUtils.remove(header[i], '.');
         header[i] = StringUtils.remove(header[i], '(');
         header[i] = StringUtils.remove(header[i], ')');
         header[i] = StringUtils.remove(header[i], '-');
      }
      return header;
    }
    
    public Set<E> read() throws IOException
    {
      Set<E> csvObjects = new HashSet<E>();
    
      try (ICsvBeanReader beanReader = new CsvBeanReader(getFileReader(), getCsvPreferences());)
      {
         // Trim the spaces or SuperCSV will look for setters _with_ spaces or dots in the name
         String[] headers = formatHeaders(beanReader.getHeader(true));
    
         E csvObject;
         while ((csvObject = beanReader.read(clazz, headers)) != null)
         {
            csvObject.setLineNumber(beanReader.getRowNumber());
            csvObjects.add(csvObject);
         }
      }
    
      return csvObjects;
    }
    

    now, this is only tested for my specific csv files, so there are probably plenty of other characters that the formatHeaders() method should filter. I think the ReflectionUtils-class of SuperCSV should be able to handle this on its own

     

Log in to post a comment.