Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

org.dbunit.dataset.NoSuchColumnException

I'm getting the following error when I run my tests:

org.dbunit.dataset.NoSuchColumnException: myTable.MYFIELD -  (Non-uppercase input column: myfield) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.
    at org.dbunit.dataset.AbstractTableMetaData.getColumnIndex(AbstractTableMetaData.java:117)

I set a breakpoint in org.dbunit.dataset.AbstractTableMetaData#getColumnIndex and discovered the following. In IntelliJ Idea the method looks like this:

public int getColumnIndex(String columnName) throws DataSetException 
{
    logger.debug("getColumnIndex(columnName={}) - start", columnName);

    if(this._columnsToIndexes == null) 
    {
        // lazily create the map
        this._columnsToIndexes = createColumnIndexesMap(this.getColumns());
    }

    String columnNameUpperCase = columnName.toUpperCase();
    Integer colIndex = (Integer) this._columnsToIndexes.get(columnNameUpperCase);
    if(colIndex != null) 
    {
        return colIndex.intValue();
    }
    else 
    {
        throw new NoSuchColumnException(this.getTableName(), columnNameUpperCase,
                " (Non-uppercase input column: "+columnName+") in ColumnNameToIndexes cache map. " +
                "Note that the map's column names are NOT case sensitive.");
    }
}

The value of this.getColumns() does not contain any Column with Column.columnName matching the parameter columnName. Therefore colIndex becomes null and the exception is thrown.

It looks like DBUnit is looking for the column index in the wrong table meta data.

How can I fix this?

Note: I inherited this code from someone else (didn't write it).

like image 950
Dmitrii Pisarenko Avatar asked Nov 13 '17 12:11

Dmitrii Pisarenko


2 Answers

It's not clear from you post how do you get the _columnsToIndexes It looks like a piece of some reflection code that depends on your POJO. In this case the problem migth be in Lazy initialization of the object. Lazy initialized objects are not just entity object but some kind of proxy and attemption of getting its properties through the reflection may cause this problem. Probably you should try add some kind of unproxy method into you createColumnIndexesMap. Here is example:

public static <T> T initializeAndUnproxy(T entity) {
    if (entity == null) {
      throw new InternalServerException("Entity passed for initialization is null");
    }

    T unproxy = entity;
    Hibernate.initialize(entity);
    if (isProxy(entity)) {
      unproxy = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
    }
    return unproxy;
  }
  public static <T> boolean isProxy(T entity) {
    return entity instanceof HibernateProxy;
  }

of course it depends on your ORM, here is example for Hibernate

like image 24
Yuriy Tsarkov Avatar answered Sep 20 '22 05:09

Yuriy Tsarkov


I'm sensitive to the fact that you can't really share code. That does make things a little difficult, but here's an answer I think is reasonable given the confines:

I was able to easily reproduce this exception using a minimal Spring Boot/DbUnit project cloned from GitHub. Perhaps my observations will amount to the hint you're looking for, or at least inspire a better answer.

Steps

  • Clone the project and install dependencies.
  • Run the HsqldbexampleApplicationTests.contextLoads() test. It passes.
  • Get into StaticResource.java, and change one of the @Column annotations.

For example, I changed:

@Column(name = "CONTENT")
private String content;

to:

@Column(name = "CONTENTZ")
private String content;
  • Run the test again and observe the exception
  • Alternatively, you can get into sampleData.xml and change the CONTENT attributes there (the attribute name), to produce the same exception.

Observations

  • The test gets its data from /META-INF/dbtest/sampleData.xml. Note the CONTENT attribute.
  • The resource has an @Column annotation whose name must match an attribute found in the sampleData.xml elements.
  • Since your trouble is also with running tests, it may be that your code and the .xml(?) that hydrates your test data store are simply out of sync with respect to a column name.

Further implication of an XML file?

My attempts to provoke this exception by changing queries and instance variable names were unsuccessful. Everything I tried made the compiler complain, so I ruled it out.

For example, I also checked out this repo, and tried to change a query and an instance variable, but was thwarted by the compiler at every step. Changing a query:

Changing query error

Changing an instance variable name:

Changing variable name error

Where to look

  • Anywhere in any java code where you have @Column with MYFIELD inside it. Remember, annotations can span several lines in a file.
  • Any xml files containing MYFIELD.
  • Assuming the code under test works fine, and your problems are confined to running tests, the mechanism that injects data into your test is the prime suspect. If this isn't an xml file, what is it?
like image 197
Mike Patrick Avatar answered Sep 21 '22 05:09

Mike Patrick