arnaudroger / SimpleFlatMapper

Fast and Easy mapping from database and csv to POJO. A java micro ORM, lightweight alternative to iBatis and Hibernate. Fast Csv Parser and Csv Mapper
http://simpleflatmapper.org
MIT License
437 stars 76 forks source link

Mapping Fails on Pseudo-Duplicate Columns (Case Sensitive) #670

Closed chriszwickerocteris closed 4 years ago

chriszwickerocteris commented 5 years ago

It seems that there are some inconsistencies with regards to the case sensitivity of mapping properties, which leads to unexpected behavior. Interestingly, while the two variations seem to be treated the same in some case, ignoring one of them fixes the problem.

This seems to only affect collections: when I tried to further simplify to get rid of class Bar, renaming linkBList_id to linkb_id and adding linkB_id, the test succeeded.

Reproducing test (fails with No constructor available for class java.lang.String)

public class CaseSensitiveTests {
  private static Connection conn;
  private static final String query = String.join("\n",
    "with t (",
      "id, linkBList_id, linkBList_linkc_id, linkBList_linkC_id",
    " ) as ( values",
      "('aa', 'bb', 'cc', 'cc'",
      ")",
    ")",
    "select * from t"
  );

  @BeforeClass
  public static void init() throws SQLException {
    conn = DriverManager.getConnection("jdbc:postgresql://localhost:4001/testing", "postgres", "testing");
  }

  @Test
  public void failing() throws SQLException {
    PreparedStatement stmt = conn.prepareStatement(query);
    ResultSet rs = stmt.executeQuery();
    final JdbcMapperFactory mapperFactory = JdbcMapperFactory.newInstance()
      .useAsm(false)
      .ignorePropertyNotFound()
      .addKeys("id")
      .addKeys("linkBList_id")
      .addKeys("linkBList_linkC_id")
    ;

    mapperFactory.newMapper(Root.class).iterator(rs);
  }

  @Test
  public void succeeding() throws SQLException {
    PreparedStatement stmt = conn.prepareStatement(query);
    ResultSet rs = stmt.executeQuery();
    final JdbcMapperFactory mapperFactory = JdbcMapperFactory.newInstance()
      .useAsm(false)
      .ignorePropertyNotFound()
      .addKeys("id")
      .addKeys("linkBList_id")
      .addKeys("linkBList_linkC_id")
      .ignoreColumns("linkBList_linkc_id") 
    ;
    final Iterator<Root> iterator = mapperFactory.newMapper(Root.class).iterator(rs);

    assertTrue(iterator.hasNext());
    final Root found = iterator.next();
    assertNotNull(found);
  }

  public static class Root {
    private String id;
    private List<Foo> linkBList;

    public Root() {}
    public Root(final String id, final List<Foo> linkBList) {
      this.id = id;
      this.linkBList = linkBList;
    }
  }

  public static class Foo {
    private String id;
    private Bar linkC;

    public Foo() {}
    public Foo(final String id, final Bar linkC) {
      this.id = id;
      this.linkC = linkC;
    }
  }

  public static class Bar {
    private String id;

    public Bar() {}
    public Bar(final String id) {
      this.id = id;
    }
  }
}
chriszwickerocteris commented 5 years ago

In fact, I have to change the wording: it doesn't "work", it just doesn't fail. Ignoring columns is case insensitive (as far as I can see), so the expected class is also not created ;-(

arnaudroger commented 5 years ago

first thanks for all the bur report, will have a thorough look when I can!