DBUnit PostgresqlDataTypeFactory does not recognizes enum list
Asked Answered
R

4

8

I'm using DBUnit for an integration test, and before executing the test code I'm running into this error:

badges.track_types data type (2003, '_text') not recognized and will be ignored. See FAQ for more information.

org.dbunit.dataset.NoSuchColumnException: badges.TRACK_TYPES -  (Non-uppercase input column: track_types) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.

the column that is ignored is a list of enums. In the dataset it's written like this :

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
  // More info ...
  <badges name="30&apos;000" description="30k a day" image_name="30000.png" threshold_val="30000.00000000" has_many="true" id="45" track_types="{TRACK_GENERIC}" "/> 
</dataset> 

I looked in the DBUnit FAQ and saw this issue , that says that I have to override the isEnumType() method to support my enum is Postgresql, so I did this:

/**
 * Override method to set custom properties/features
 */
protected void setUpDatabaseConfig(DatabaseConfig config) {

    config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new PostgresqlDataTypeFactory(){
        public boolean isEnumType(String sqlTypeName) {
            if(sqlTypeName.equalsIgnoreCase("track_types")){
                return true;
            }
            return false;
        }
    });
    config.setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new DefaultMetadataHandler());
}

But I still get the same error, and I don't know why. Maybe I'm not overriding well the method? Maybe it's not even the cause of my problem? If you need any other code just ask, thanks!

Rodge answered 23/6, 2016 at 11:3 Comment(4)
Does your dataset badges contain a column TRACK_TYPES?Nickolas
Can you send me your source code ? I'll try to dig into it.Erny
@KevinWallis I just updated the question so you can see the dataset row. Yes, it contains that column, but it's ignored as the error states.Rodge
@IvanUrsul What do you need exactly? That's the source code involved in the problem, I have no problem in sharing it, but just let me know the part you need so I don't make the question so big. Thanks a lot!Rodge
R
2

Well... I wasn't able to solve this exactly but managed to solve it by a workaround.

This error comes because of the @DatabaseSetup annotation. If I did this process without using it, it still throws a 'column not recognized' error, because it doesn't recognize postgres arrays (that was the root cause that I have) but I could solve it by creating a new DataTypeFactory that extends from the default one:

public class PsqlArrayDataTypeFactory extends DefaultDataTypeFactory {
        public DataType createDataType(int sqlType, String sqlTypeName) throws DataTypeException {
            if (sqlType == Types.ARRAY)
            {
                return DataType.VARCHAR;
            }

            return super.createDataType(sqlType, sqlTypeName);
        }
    }
Rodge answered 6/7, 2016 at 10:54 Comment(0)
C
2

Try to persist the enum with its value

enum.values();

it return an array than you save this element

Cordalia answered 27/6, 2016 at 9:33 Comment(2)
where should I persist the enum? In the setUpDatabaseConfig method?Rodge
Try to use an EntityManager it has a persist(obj) methodsCordalia
R
2

Well... I wasn't able to solve this exactly but managed to solve it by a workaround.

This error comes because of the @DatabaseSetup annotation. If I did this process without using it, it still throws a 'column not recognized' error, because it doesn't recognize postgres arrays (that was the root cause that I have) but I could solve it by creating a new DataTypeFactory that extends from the default one:

public class PsqlArrayDataTypeFactory extends DefaultDataTypeFactory {
        public DataType createDataType(int sqlType, String sqlTypeName) throws DataTypeException {
            if (sqlType == Types.ARRAY)
            {
                return DataType.VARCHAR;
            }

            return super.createDataType(sqlType, sqlTypeName);
        }
    }
Rodge answered 6/7, 2016 at 10:54 Comment(0)
J
2

I had next error:

Caused by: org.postgresql.util.PSQLException: ERROR: column "status" is of type topic_status but expression is of type character varying
  Hint: You will need to rewrite or cast the expression.

DbUnit requests meta for table and receives a type VARCHAR for enums from PostgreSQL. But PostgreSQL won't accept this type back.

I overrode methods from PostgresqlDataTypeFactory in next way:

config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, 
    new PostgresqlDataTypeFactory() {
        @Override
        public boolean isEnumType(String sqlTypeName) {
            return "topic_status".equalsIgnoreCase(sqlTypeName);
        }

        @Override
        public DataType createDataType(int sqlType, String sqlTypeName) throws DataTypeException {
            if (isEnumType(sqlTypeName)) {
                sqlType = Types.OTHER;
            }
            return super.createDataType(sqlType, sqlTypeName);
        }
    });
);

This sets type for enum as OTHER and parent method super.createDataType(sqlType, sqlTypeName) creates DataType in proper way.

PostgreSQL version: 9.6.5
DbUnit version: 2.5.4

More information could be found on discussion.

Jaffna answered 8/9, 2017 at 18:5 Comment(0)
R
0

There is limited support for postgresql enums because only reading and writing strings is supported since dbunit 2.4.6. To do so you have to override the method "isEnumType" in the PostgresqlDataTypeFactory like this:

PostgresqlDataTypeFactory factory = new PostgresqlDataTypeFactory(){
  public boolean isEnumType(String sqlTypeName) {
    if(sqlTypeName.equalsIgnoreCase("abc_enum")){
      return true;
    }
    return false;
  }
}; 
Ratiocination answered 14/12, 2016 at 10:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.