question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Getting MappingException when reading TINYINT value from H2 database as boolean/Boolean

See original GitHub issue

Bug Report

I am using R2DBC H2 for integration testing my reactive application (which is based on Spring Webflux , Java). Getting no issue when saving PrepTaskEntity but when trying to read, getting the following error. On debugging through the classes, it seems that the tiny int value is being read as Bytes and BooleanCodec of H2 is unable to decode it.

Versions

  • Driver: io.r2dbc:r2dbc-h2:0.8.4.RELEASE (Spring boot 2.3.2.RELEASE)
  • Database: H2
  • Java: 11
  • OS: Mac

Current Behavior

Stack trace
org.springframework.data.mapping.MappingException: Could not read property @org.springframework.data.relational.core.mapping.Column(value="is_active")private boolean com.example.demosvc.persistence.entities.PrepTaskEntity.isActive from result set!
	at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readFrom(MappingR2dbcConverter.java:172) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	|_ checkpoint ⇢ Handler com.example.demosvc.controllers.PrepTaskController#getPrepTasksForGivenBU(String) [DispatcherHandler]
	|_ checkpoint ⇢ com.example.demosvc.filters.TenancyContextFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ HTTP GET "/sites/BU-002/prepTasks" [ExceptionHandlingWebHandler]
Stack trace:
		at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readFrom(MappingR2dbcConverter.java:172) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
		at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:133) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
		at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:116) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
		at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:46) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
		at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:29) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
		at io.r2dbc.h2.H2Result.lambda$map$0(H2Result.java:67) ~[r2dbc-h2-0.8.4.RELEASE.jar:0.8.4.RELEASE]
		at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:100) ~[reactor-core-3.3.8.RELEASE.jar:3.3.8.RELEASE]
		at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73) ~[reactor-core-3.3.8.RELEASE.jar:3.3.8.RELEASE]
...
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Byte] to type [boolean]
	at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321) ~[spring-core-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194) ~[spring-core-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174) ~[spring-core-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.getPotentiallyConvertedSimpleRead(MappingR2dbcConverter.java:263) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
	at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readValue(MappingR2dbcConverter.java:187) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
	at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readFrom(MappingR2dbcConverter.java:169) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
	at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:133) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
	at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:116) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
	at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:46) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
	at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:29) ~[spring-data-r2dbc-1.1.2.RELEASE.jar:1.1.2.RELEASE]
	at io.r2dbc.h2.H2Result.lambda$map$0(H2Result.java:67) ~[r2dbc-h2-0.8.4.RELEASE.jar:0.8.4.RELEASE]
...

Table schema

Input Code
CREATE TABLE `prep_task` (
  `id` SERIAL,
  `external_id` VARCHAR(45) NOT NULL,
  `name` VARCHAR(45) NOT NULL,
  `description` VARCHAR(100) NULL,
  `is_active` TINYINT,
  PRIMARY KEY (`id`)
);

Steps to reproduce

Input Code
@Table("prep_task")
public class PrepTaskEntity implements Persistable<Long> {
  @Id
  @Column("id")
  private Long id;

  @Column("external_id")
  private String externalId;

  @Column("name")
  private String name;

  @Column("description")
  private String description;

  @Column("is_active")
  private boolean isActive;

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getExternalId() {
    return externalId;
  }

  public void setExternalId(String externalId) {
    this.externalId = externalId;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public boolean isActive() {
    return isActive;
  }

  public void setActive(boolean active) {
    isActive = active;
  }

  @Override
  public boolean isNew() {
    return id == null;
  }


}

Expected behavior/code

Should be able to read the is_active column value in the boolean isActive.

Additional context

H2 Connection Config (using Routing Connection Factory because of multi-tenancy)

@Configuration
@Profile(Application.Profiles.INTEGRATION_TEST)
public class H2ConnectionConfig extends AbstractR2dbcConfiguration {

  private final R2dbcConfigProperties r2dbcConfigProperties;

  @Autowired
  public H2ConnectionConfig(R2dbcConfigProperties r2dbcConfigProperties) {
    this.r2dbcConfigProperties = r2dbcConfigProperties;
  }

  @Override
  @Bean
  public ConnectionFactory connectionFactory() {
    RoutingConnectionFactory connectionFactory = new RoutingConnectionFactory();
    Map<String, ConnectionFactory> factories = new HashMap<>();
    H2ConnectionConfiguration.Builder configurationBuilder = H2ConnectionConfiguration.builder()
        .property(H2ConnectionOption.MODE, "MySQL")
        .property(H2ConnectionOption.DB_CLOSE_DELAY, "-1")
        .property(H2ConnectionOption.DB_CLOSE_ON_EXIT, "false");
    for (String tenant : r2dbcConfigProperties.getTenants()) {
      String databaseName = r2dbcConfigProperties.getDbPrefix() + tenant;
      factories.put(tenant, new H2ConnectionFactory(configurationBuilder.inMemory(databaseName).build()));
    }
    connectionFactory.setTargetConnectionFactories(factories);
    connectionFactory.setDefaultTargetConnectionFactory(factories.get("default"));
    return connectionFactory;
  }

}

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
abhinaba-chakraborty-bycommented, Aug 13, 2020

@mp911de My bad. Missed that in the stacktrace. Thought to omit the unnecessary ones (which had the trace from Reactor classes). Adding that.

0reactions
abhinaba-chakraborty-bycommented, Aug 13, 2020

Thanks @mp911de for the guide.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Getting MappingException when reading TINYINT value from ...
The issue is that there is no converter from Byte (mapped to tinyint) to Boolean. I have also mapped Integer to Boolean (in...
Read more >
2.0.202 and hibernate: boolean field regression?
to H2 Database. Hi,. congratulations for the new H2 release!! ... JdbcSQLSyntaxErrorException: Values of types "BOOLEAN" and "INTEGER" are not comparable.
Read more >
Data Types - H2 Database Engine
BOOLEAN TINYINT SMALLINT, INTEGER BIGINT NUMERIC REAL DOUBLE PRECISION ... These special values can't be read or set as BigDecimal values, but they...
Read more >
The jOOQ Release Note History
#13204, Boolean values aren't serialised correctly in SQL Server JSON documents. #13211, KotlinGenerator cannot read existing catalog/schema version.
Read more >
Hibernate ORM 5.4.33.Final User Guide - Red Hat on GitHub
CHAR, 'F'/'f' is false, 'T'/'t' is true. The uppercase value is written to the database. boolean, java.lang.Boolean. true_false. ByteType. TINYINT.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found