简体   繁体   中英

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

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 an instance variable name:

更改变量名称错误

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?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM