Menu

#92 Multiple column names

wont-fix
None
5
2017-12-30
2017-12-04
No

Hello,
we have to define multiple names for one column (one word: customers :D ), so I would like to see the feature to define multiple column names in the annotations. I would suggest something like following:

@CsvBindByName(column = "columnName1|columnName2|columnA|columnB")
public Long example;

If this is already possible somehow, I apologize for opening a new ticket for this feature.

regards
Patrick

Discussion

  • Scott Conway

    Scott Conway - 2017-12-04

    Well hopefully its multiple customers and each one has their own terminology not one customer that says I am going to send you three columns and they can all map to this field.

    I am not sure about the CsvBindByName but the HeaderColumnNameTranslateMappingStrategy can allow this as the below test demonstrates. But be carefult because the results could be undefined if you get cute and try multithreading.

    Unless you have multiple customers whose different spreadsheets do not overlap I would recommend you create what I call a DataTransferObject (DTO) which would be an intermediate object that has all the fields in it and then in either the DTO or a separate factory object (preferred) have the logic that would take the DTO and produce your desired object so you can take care of the overlapping null/empty string or give an error if the customer decided to fill in both overlapping columns with the different values.

    @Test
    public void canHaveMultipleColumnsToSameFieldIfYouGetOffOnShootingYourselfInTheFoot() {
      String s = "n,o,foo,o2\n" +
              "kyle,123456,emp123,911878\n" +
              "jimmy,abcnum,cust09878,996655";
      HeaderColumnNameTranslateMappingStrategy<MockBean> strat = new HeaderColumnNameTranslateMappingStrategy<>();
      strat.setType(MockBean.class);
      Map<String, String> map = new HashMap<>();
      map.put("n", "name");
      map.put("o", "orderNumber");
      map.put("foo", "id");
      map.put("o2", "orderNumber");
    
      strat.setColumnMapping(map);
    
      CsvToBean<MockBean> csv = new CsvToBean<>();
      List<MockBean> list = csv.parse(strat, new StringReader(s));
      assertNotNull(list);
      assertTrue(list.size() == 2);
      MockBean bean = list.get(0);
      assertEquals("kyle", bean.getName());
      assertEquals("911878", bean.getOrderNumber());
      assertEquals("emp123", bean.getId());
    }
    
    @Test
    public void youCanShootYourselfInTheFootWhenHaveMultipleColumnsToSameField() {
      String s = "n,o,foo,o2\n" +
              "kyle,123456,emp123,67890\n" +
              "jimmy,abcnum,cust09878,";   // o2 is not set
      HeaderColumnNameTranslateMappingStrategy<MockBean> strat = new HeaderColumnNameTranslateMappingStrategy<>();
      strat.setType(MockBean.class);
      Map<String, String> map = new HashMap<>();
      map.put("n", "name");
      map.put("o", "orderNumber");
      map.put("foo", "id");
      map.put("o2", "orderNumber");
    
      strat.setColumnMapping(map);
    
      CsvToBean<MockBean> csv = new CsvToBean<>();
      List<MockBean> list = csv.parse(strat, new StringReader(s));
      assertNotNull(list);
      assertTrue(list.size() == 2);
      MockBean bean = list.get(0);
      assertEquals("kyle", bean.getName());
      assertEquals("67890", bean.getOrderNumber());
      assertEquals("emp123", bean.getId());
    
      bean = list.get(1);
      assertEquals("jimmy", bean.getName());
      assertTrue(bean.getOrderNumber().isEmpty());       // since it was not set an emptyString is put in its place and previous value lost - foot shot!
      assertEquals("cust09878", bean.getId());
    }
    

    Regards

    Scott Conway :)

     

    Last edit: Scott Conway 2017-12-04
  • Scott Conway

    Scott Conway - 2017-12-04
    • assigned_to: Scott Conway
     
  • Andrew Rucker Jones

    Scott's suggestion is a natural and functional one. Still, I can understand the need to some extent. Let me ruminate on this a while before we make any decisions.

     
  • Andrew Rucker Jones

    • assigned_to: Scott Conway --> Andrew Rucker Jones
     
  • Andrew Rucker Jones

    • status: open --> wont-fix
     
  • Andrew Rucker Jones

    I did some thinking on this. The biggest problem I see here is that it cannot possibly be round-trip equivalent. That is, we could possibly implement a reading method that takes alternative header names, but what do we do on writing? We can't guess which one is correct.

    So, I have two further suggestions for you:

    1. Create a field for every possible input column name, but don't mark them as required. Then create a method in your bean that returns whichever field is not null.
    2. Wait for my planned development of Feature Request 90, which is meant to allow our users to subsume multiple columns under one field. I believe the field will be a map (for the same reason as above). Then you could simply get the list of values and take what is presumably the only value in the map as the one you want.

    If you have question, suggestions, or further comments, feel free to write back, even though I'm closing this ticket.

     

Log in to post a comment.

MongoDB Logo MongoDB