org.dbunit.dataset.NoSuchColumnException
Asked Answered
S

2

7

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).

Stephie answered 13/11, 2017 at 12:44 Comment(10)
Since you have already done a detailed analysis of the problem I guess the best place to ask this question is non the DBUnit support forum.Drusilla
There are two possible reasons. Either the DBUnit is wrong. Or, you provided it wrong columnName in some annotation or wrongly named getter/setter pair.Tick
You need to show a bit more code than that for someone to get a better idea of the situation. Also which table gets used in your case and did you check where it is coming from?Aroid
@TarunLalwani What exactly can I look for?Stephie
Some annotation or some setup code, also see which table is getting picked? That should give you a clue where the code is loading the table details fromAroid
Is this is a JPA project? How is the test database created? See also here to enable logging of all SQL being generated, including table creation and iserts https://mcmap.net/q/66867/-how-to-print-a-query-string-with-parameter-values-when-using-hibernateMelliemelliferous
Could you share createColumnIndexesMap() method?Cumulative
Three things: (a) what DOES this.getColumns() return? (b) what is the content of this._columnsToIndexes? (c) what is the table's DDL?Salami
@DP_ How are you configuring your DbUnit env. Which DatabaseTester are you using? Can you share your DatabaseTester and it's detailsPhidippides
Look AT #2210929Staton
C
4

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?
Camilia answered 19/11, 2017 at 0:34 Comment(0)
S
1

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

Status answered 20/11, 2017 at 20:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.