Getting MappingException when reading TINYINT value from H2 database as boolean/Boolean
See original GitHub issueBug 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:
- Created 3 years ago
- Comments:8 (4 by maintainers)
Top 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 >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@mp911de My bad. Missed that in the stacktrace. Thought to omit the unnecessary ones (which had the trace from Reactor classes). Adding that.
Thanks @mp911de for the guide.