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
435 stars 76 forks source link

Discriminators don't seem to work for JdbcTemplateMapperFactory using a ResultSetExtractor #748

Open FrankZappaterrini opened 3 years ago

FrankZappaterrini commented 3 years ago

I am using version 8.2.3, and I cannot add a discriminator column to JdbcTemplateMapperFactory. Here is my code using JdbcTemplateMapperFactory:

return this.jdbcTemplate.query(this.sqlQueryManager.getMediaItemsQuery(), new MapSqlParameterSource("accountId", accountId), 
                    JdbcTemplateMapperFactory.newInstance()
                            .addKeys("mediaItemId")
                            .discriminator(MediaItem.class)
                            .onColumn("uploadType", String.class)
                            .with(builder -> builder
                                    .when("message", Message.class)
                                    .when(v -> !"message".equals(v), MediaItem.class) 
                                    )
                    .newResultSetExtractor(MediaItem.class));

I expect this code to return a List where some items in the list are the type Message when the value of the "uploadType" column is equal to "message" (Message extends MediaItem). This is not the case. All items in the list are MediaItems. Through debugging, I found the problem. The problem starts in JdbcTemplateMapperFactory.newResultSetExtractor(Type target):

public <T> ResultSetExtractorImpl<T> newResultSetExtractor(Type target) throws MapperBuildingException {
        return new ResultSetExtractorImpl<T>(this.<T>newJdbcMapper(target));
}

The call to JdbcTemplateMapperFactory.newJdbcMapper() switches types to a JdbcMapperFactory:

public <T> JdbcMapper<T> newJdbcMapper(Type target) {
        return JdbcMapperFactory.newInstance(this).newMapper(target);
}

Calling JdbcMapperFactory.newInstance(this) should copy all of the properties from the JdbcTemplateMapperFactory to the new JdbcMapperFactory, but it does not. The copy constructor for the parent class, AbstractMapperFactory, does not copy the list of discriminators:

public AbstractMapperFactory(AbstractMapperFactory<K, ?, S> config) {
        this.fieldMapperErrorHandler = config.fieldMapperErrorHandler;
        this.mapperBuilderErrorHandler = config.mapperBuilderErrorHandler;
        this.consumerErrorHandler = config.consumerErrorHandler;

        this.columnDefinitions = config.columnDefinitions;
        this.identity = config.identity;

        this.useAsm = config.useAsm;
        this.failOnAsm = config.failOnAsm;
        this.asmMapperNbFieldsLimit = config.asmMapperNbFieldsLimit;

        this.propertyNameMatcherFactory = config.propertyNameMatcherFactory;

        this.reflectionService = config.reflectionService;
        this.maxMethodSize = config.maxMethodSize;
        this.assumeInjectionModifiesValues = config.assumeInjectionModifiesValues;
        this.rowFilter = config.rowFilter;
        this.unorderedJoin = config.unorderedJoin;
        this.getterFactory = config.getterFactory;
    }

Therefore, you can never use discriminators with the JdbcTemplateMapperFactory using a ResultSetExtractor. Adding the line:

this.discriminators.addAll(config.discriminators);

to the copy constructor fixes the problem and my code works as expected.