Mapping Result of Primitive Type Field when using Native Query
See original GitHub issueHi @mirromutth, I faced this situation when I map result to object from native query.
Environment
- Spring Boot 2.3.4.RELEASE
- Kotlin (java compat w/ 1.8)
- R2DBC-MySQL 0.8.2 (dev.miku:r2dbc-mysql:0.8.2.RELEASE)
- if any other is needed, just let me know 😃
Observation
- My DB has a table as below:
field1 (varchar) | field2 (varchar) | field3 (double) |
---|---|---|
first | row | 1.0 |
second | row | 2.0 |
third | row | null |
- Query I used is as below:
SELECT field1, field2, field3
FROM my_table
...
and mapped into object with its result like this:
data class ResultObject(val f1: String, val f2: String, val f3: Double?)
val ro: ResultObject = connection.createStatement(query).execute()
.map { row, _ -> ResultObject(
row.get(0, String::class.java)!!,
row.get(1, String::class.java)!!,
row.get(2, Double::class.java)!!,
) }
And I got an error java.lang.IllegalArgumentException: Cannot decode null for type 5
.
Conjecture
- From my analysis of code, r2dbc (this library) gets its type information from db (type 5 -
DataTypes.DOUBLE
) and guesses “this field should be mapped into proper java type (Double.class
)” – maybe around this line (DefaultCodecs.java) - Next, when this field (
Double.class
in above) is primitive, dodecodePrimitive()
. – this line - Comment on
decodePrimitive()
is// If value is null field, then primitive codec should throw an exception instead of return null.
. But I’d like to ask about this – when type of corresponding field is wrapper type, could be nullable though it is primitive(or numeric) type? In my understanding, not only Kotlin, but also Java, wrapper type is nullable and could have null value. - Note that, my workaround is mapping last field of
ResultObject
usingrow.get(2, Any::class.java) as Double?
. - I’d happy if I could hear your thoughts on this 😃 (if you agree with my opinion – wrapper type could have null value; I’ll consider how it could be resolved 😃)
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (4 by maintainers)
Top Results From Across the Web
Result Set Mapping: The Basics - Thorben Janssen
SQL result set mappings provide a nice way to map the List returned by native queries in JPA. Lets have a look at...
Read more >Mapping and querying a list of primitive types with JPA 2.0
Sometimes you just want to map a list of primitive types. For example, a Book entity has a list of tags and tags...
Read more >Native SQL - Doctrine Object Relational Mapper (ORM)
With NativeQuery you can execute native SELECT SQL statements and map the results to Doctrine entities or any other result format supported by...
Read more >Converting a native query result having NULL values to a POJO
Explicity mention the type e.g @ColumnResult(name = "count", type = Integer.class; For POJO fields use Class(Integer) and not primitive(int) ...
Read more >A Guide to SqlResultSetMapping - Baeldung
The core functionality here involves mapping result sets from database SQL statements into Java objects. 2. Setup.
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
Hi, @btakeya,
Great thanks for @mp911de suggestion. Apologies for the late reply.
Well, this should be a little difference between Java and Kotlin.
In Java,
double.class
is a primitive class, which is different fromDouble.class
, a boxed type. So that’s why I want to throw an exception when callingdouble someData = row.get(0, double.class)
in Java. If I do not, it will be an NPE and thrown by unboxing instead of driver-side.In Kotlin/JVM,
Double::class.java
is a primitive class, and Kotlin/JVM blurs the difference between boxed type and primitive type at the usage level, because Kotlin is a multi-platform language (e.g. Kotlin/Native, Kotlin/JS). And if Kotlin/JVM wants to do the same behavior as the Java boxed type, it should bejava.lang.Double::class.java
instead.Actually, yes, considering cross-language compatibility, even if the type is a primitive class, it should return
null
. And then, if the Java code executesint someData = row.get(0, int.class)
and the field isnull
, it will be NPE (thrown by unboxing) instead ofIllegalArgumentException
(thrown byr2dbc-mysql
).I will merge your PR soon.
Great regards,
R2DBC doesn’t support primitive values as
T
always has to be an object, therefore use the wrapper type class.