ResultMap - Kotlin support

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

ResultMap - Kotlin support

Kamil Hliwa
Hi,

I wanted to post a feature request, but the "before you post" message suggest to ask first on this group for feedback. So here I am! :)

Problem:
If we have class like this:

class Foo(var bar: String)

Where we don't want ever never bar to be null, at the moment we can't use MyBatis without ugly workarounds or just bad workarounds. There is no default constructor, so MyBatis is not able to map the values to model.

Proposition:
Allow ResultMap to try to find suitable constructor if empty constructor wasn't found?
Or some other way to automaticly map ResultMap to parametrized constructor.

Workarounds:

class Foo(var bar: String) {
 
@Deprecated(message = "workaround1")
 constructor
() : this("")
}

Well, I think I don't need to say why this is bad. There is much urge to use this easy default constructor to initialize object in other way than designed and projected.
Also, you need to to provide a lot of thrash values as in this example:

constructor
() : this(null, "", "", "", "", null, null, null, false,
 
false, false, AuthorizationTypeEnum.None, Date(), null)


Second workaround is using ConstructorArgs, but it's not suitable for large projects (reason).

@ConstructorArgs(value = [
 
Arg(column = "bar", name = "bar")
])
fun getFoo
(): Foo;




--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: ResultMap - Kotlin support

Jeff Butler
MyBatis is quite good at figuring out constructors now - without any mapping needed.  I have some Kotlin examples working now with a data class similar to what you've shown and it works just fine (no @ConstructorArgs needed).

If you are having some specific issue, feel free to post an example somewhere and we'll take a look at it.

Jeff Butler


On Thu, Mar 1, 2018 at 9:25 AM Kamil Hliwa <[hidden email]> wrote:
Hi,

I wanted to post a feature request, but the "before you post" message suggest to ask first on this group for feedback. So here I am! :)

Problem:
If we have class like this:

class Foo(var bar: String)

Where we don't want ever never bar to be null, at the moment we can't use MyBatis without ugly workarounds or just bad workarounds. There is no default constructor, so MyBatis is not able to map the values to model.

Proposition:
Allow ResultMap to try to find suitable constructor if empty constructor wasn't found?
Or some other way to automaticly map ResultMap to parametrized constructor.

Workarounds:

class Foo(var bar: String) {
 
@Deprecated(message = "workaround1")
 constructor
() : this("")
}

Well, I think I don't need to say why this is bad. There is much urge to use this easy default constructor to initialize object in other way than designed and projected.
Also, you need to to provide a lot of thrash values as in this example:

constructor
() : this(null, "", "", "", "", null, null, null, false,
 
false, false, AuthorizationTypeEnum.None, Date(), null)


Second workaround is using ConstructorArgs, but it's not suitable for large projects (reason).

@ConstructorArgs(value = [
 
Arg(column = "bar", name = "bar")
])
fun getFoo
(): Foo;




--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: ResultMap - Kotlin support

Kamil Hliwa
Ok, so there's my problem.
Class:
data class OneTimeToken(
       
var oneTimeTokenId: Long?,
       
var userId: Long,
       
var token: String,
       
var tokenType: TokenTypeEnum,
       
var createDate: Date = Date()) {
    constructor
(oneTimeTokenId: Long?, user: User, token: String, tokenType: TokenTypeEnum, createDate: Date = Date())
           
: this(oneTimeTokenId, user.userId!!, token, tokenType, createDate) {
       
this.user = user
   
}
   
var user: User? = null
       
set(value) {
            field
= value
            userId
= value?.userId!!
       
}
}
 
var user: User? = null
 
set(value) {
 field
= value
 userId
= value?.userId!!
 
}
}



Mapping (shouldn't be needed beside userId at all):
@Results(id = "oneTimeTokenResult", value = [
 
Result(property = "oneTimeTokenId", column = "oneTimeTokenId"),
 
Result(property = "userId", column = "user_userId"),
 
Result(property = "token", column = "token"),
 
Result(property = "tokenType", column = "tokenType"),
 
Result(property = "createDate", column = "createDate")
])


Exception:
nested exception is org.apache.ibatis.executor.ExecutorException: No constructor found in pl.inwebit.letspay.model.token.OneTimeToken matching [java.lang.Long, java.sql.Timestamp, java.lang.String, java.lang.Long, java.lang.String

And MyBatis dependency:

<dependency>
 
<groupId>org.mybatis.spring.boot</groupId>
 
<artifactId>mybatis-spring-boot-starter</artifactId>
 
<version>${spring.mybatis.version}</version> <!-- 1.3.1 version-->
</dependency>



It works with any of workarounds descripted by me, but not without them.


On Thursday, 1 March 2018 15:35:46 UTC+1, Jeff Butler wrote:
MyBatis is quite good at figuring out constructors now - without any mapping needed.  I have some Kotlin examples working now with a data class similar to what you've shown and it works just fine (no @ConstructorArgs needed).

If you are having some specific issue, feel free to post an example somewhere and we'll take a look at it.

Jeff Butler


On Thu, Mar 1, 2018 at 9:25 AM Kamil Hliwa <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="UdZxzGhoCwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">elat...@...> wrote:
Hi,

I wanted to post a feature request, but the "before you post" message suggest to ask first on this group for feedback. So here I am! :)

Problem:
If we have class like this:

class Foo(var bar: String)

Where we don't want ever never bar to be null, at the moment we can't use MyBatis without ugly workarounds or just bad workarounds. There is no default constructor, so MyBatis is not able to map the values to model.

Proposition:
Allow ResultMap to try to find suitable constructor if empty constructor wasn't found?
Or some other way to automaticly map ResultMap to parametrized constructor.

Workarounds:

class Foo(var bar: String) {
 
@Deprecated(message = "workaround1")
 constructor
() : this("")
}

Well, I think I don't need to say why this is bad. There is much urge to use this easy default constructor to initialize object in other way than designed and projected.
Also, you need to to provide a lot of thrash values as in this example:

constructor
() : this(null, "", "", "", "", null, null, null, false,
 
false, false, AuthorizationTypeEnum.None, Date(), null)


Second workaround is using ConstructorArgs, but it's not suitable for large projects (<a href="https://stackoverflow.com/questions/22166478/mybatis-constructorargs-annotation-and-embedded-objects" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fstackoverflow.com%2Fquestions%2F22166478%2Fmybatis-constructorargs-annotation-and-embedded-objects\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEukBNjYFYPHgWIbwDSliSGprdDRw&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fstackoverflow.com%2Fquestions%2F22166478%2Fmybatis-constructorargs-annotation-and-embedded-objects\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEukBNjYFYPHgWIbwDSliSGprdDRw&#39;;return true;">reason).

@ConstructorArgs(value = [
 
Arg(column = "bar", name = "bar")
])
fun getFoo
(): Foo;




--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="UdZxzGhoCwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">mybatis-user...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: ResultMap - Kotlin support

Jeff Butler
As far as I know, the automatic constructor mapping only works if the select list from the DB matches the constructor fields.  It looks like your select statement is specifying things in a different order than the fields of your constructor.  Can you try it with matching the order of the select list and the fields in the constructor?

Of course, that is a kind of coupling that you might not want to accept.  In that case, @ConstructorArgs seems like a reasonable workaround to me.  It is no more cumbersome than @Results IMHO.  I'd like to understand why you think @ConstructorArgs is not an acceptable solution and if you have an idea for something better.

Jeff Butler



On Thu, Mar 1, 2018 at 9:51 AM Kamil Hliwa <[hidden email]> wrote:
Ok, so there's my problem.
Class:
data class OneTimeToken(
       
var oneTimeTokenId: Long?,
       
var userId: Long,
       
var token: String,
       
var tokenType: TokenTypeEnum,
       
var createDate: Date = Date()) {
    constructor
(oneTimeTokenId: Long?, user: User, token: String, tokenType: TokenTypeEnum, createDate: Date = Date())
           
: this(oneTimeTokenId, user.userId!!, token, tokenType, createDate) {
       
this.user = user
   
}
   
var user: User? = null
       
set(value) {
            field
= value
            userId
= value?.userId!!
       
}
}
 
var user: User? = null
 
set(value) {
 field
= value
 userId
= value?.userId!!
 
}
}



Mapping (shouldn't be needed beside userId at all):
@Results(id = "oneTimeTokenResult", value = [
 
Result(property = "oneTimeTokenId", column = "oneTimeTokenId"),
 
Result(property = "userId", column = "user_userId"),
 
Result(property = "token", column = "token"),
 
Result(property = "tokenType", column = "tokenType"),
 
Result(property = "createDate", column = "createDate")
])


Exception:
nested exception is org.apache.ibatis.executor.ExecutorException: No constructor found in pl.inwebit.letspay.model.token.OneTimeToken matching [java.lang.Long, java.sql.Timestamp, java.lang.String, java.lang.Long, java.lang.String

And MyBatis dependency:

<dependency>
 
<groupId>org.mybatis.spring.boot</groupId>
 
<artifactId>mybatis-spring-boot-starter</artifactId>
 
<version>${spring.mybatis.version}</version> <!-- 1.3.1 version-->
</dependency>



It works with any of workarounds descripted by me, but not without them.



On Thursday, 1 March 2018 15:35:46 UTC+1, Jeff Butler wrote:
MyBatis is quite good at figuring out constructors now - without any mapping needed.  I have some Kotlin examples working now with a data class similar to what you've shown and it works just fine (no @ConstructorArgs needed).

If you are having some specific issue, feel free to post an example somewhere and we'll take a look at it.

Jeff Butler


On Thu, Mar 1, 2018 at 9:25 AM Kamil Hliwa <[hidden email]> wrote:
Hi,

I wanted to post a feature request, but the "before you post" message suggest to ask first on this group for feedback. So here I am! :)

Problem:
If we have class like this:

class Foo(var bar: String)

Where we don't want ever never bar to be null, at the moment we can't use MyBatis without ugly workarounds or just bad workarounds. There is no default constructor, so MyBatis is not able to map the values to model.

Proposition:
Allow ResultMap to try to find suitable constructor if empty constructor wasn't found?
Or some other way to automaticly map ResultMap to parametrized constructor.

Workarounds:

class Foo(var bar: String) {
 
@Deprecated(message = "workaround1")
 constructor
() : this("")
}

Well, I think I don't need to say why this is bad. There is much urge to use this easy default constructor to initialize object in other way than designed and projected.
Also, you need to to provide a lot of thrash values as in this example:

constructor
() : this(null, "", "", "", "", null, null, null, false,
 
false, false, AuthorizationTypeEnum.None, Date(), null)


Second workaround is using ConstructorArgs, but it's not suitable for large projects (reason).

@ConstructorArgs(value = [
 
Arg(column = "bar", name = "bar")
])
fun getFoo
(): Foo;




--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: ResultMap - Kotlin support

Kamil Hliwa
I have results set alligned to the primary constructor - saddly, this doesn't work. It's probably slightly different case than in Java because of differences in Kotlin classes. But my small research suggest, that the lack of no-args constructor is source of the problem.

@ConstructorArgs are unacceptable because of maintence problem. Let's look at this:
data class A(aStr: String, bStr: String, cStr: String, dStr: String)
data
class B(aStr: String, dStr: String, eStr: String, fStr: String)
data
class C(aStr: String, gStr: String, hStr: String, iStr: String)
data
class Final(a: A?, b: B?, c: C?) {
constructor(a_aStr: String, bStr
: String, cStr: String, dStr: String, b_aStr: String, dStr: String, eStr: String, fStr: String, c_aStr: String, gStr: String, hStr: String, iStr: String)
: this (A(a_aStr, bStr, cStr, dStr), B(b_aStr, dStr, eStr, fStr), C(c_aStr, gStr, hStr, iStr)

}

Of course this case is not fully real life, but the need to create separate constructor to initialize nested objects is just silly (and now imagine the constructor for more depth in objects).
And what if object A is null? We can't initialize it with nulls (Kotlin will prohibit this), so... we need constructor with just B and C. Clearly hell.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: ResultMap - Kotlin support

Jeff Butler
Yeah - that is terrible.

I'll put my Kotlin examples up on GitHub soon.  I have quite a few working examples that work as they should with Kotlin with no changes to MyBatis. I know there are cases I haven't covered.  I would welcome your collaboration on identifying the issues and then making improvements to MyBatis if needed.

I'm pretty motivated about Kotlin in general.  I've been working on code patterns for Kotlin that might find their way into MyBatis generator.

Jeff Butler


On Fri, Mar 2, 2018 at 3:03 AM Kamil Hliwa <[hidden email]> wrote:
I have results set alligned to the primary constructor - saddly, this doesn't work. It's probably slightly different case than in Java because of differences in Kotlin classes. But my small research suggest, that the lack of no-args constructor is source of the problem.

@ConstructorArgs are unacceptable because of maintence problem. Let's look at this:
data class A(aStr: String, bStr: String, cStr: String, dStr: String)
data
class B(aStr: String, dStr: String, eStr: String, fStr: String)
data
class C(aStr: String, gStr: String, hStr: String, iStr: String)
data
class Final(a: A?, b: B?, c: C?) {
constructor(a_aStr: String, bStr
: String, cStr: String, dStr: String, b_aStr: String, dStr: String, eStr: String, fStr: String, c_aStr: String, gStr: String, hStr: String, iStr: String)
: this (A(a_aStr, bStr, cStr, dStr), B(b_aStr, dStr, eStr, fStr), C(c_aStr, gStr, hStr, iStr)

}

Of course this case is not fully real life, but the need to create separate constructor to initialize nested objects is just silly (and now imagine the constructor for more depth in objects).
And what if object A is null? We can't initialize it with nulls (Kotlin will prohibit this), so... we need constructor with just B and C. Clearly hell.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: ResultMap - Kotlin support

Kamil Hliwa
Keep me in touch and give me info via this topic when you'll post examples for github. I'm also set positive to Kotlin, and as MyBatis is my favorite framework for DB communication, I'll gladly try to help.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: ResultMap - Kotlin support

Jeff Butler
Hello Kamil and everyone else interested in Kotlin...

I've put some examples for Kotlin up on GitHub here: https://github.com/jeffgbutler/mybatis-kotlin-examples

This is an evolving work, but these examples show patterns for calling MyBatis in Kotlin for a variety of different types of queries.  Initially I didn't write any extensions to MyBatis - this uses MyBatis as is.

If anyone has a better idea for patterns please feel free to open issues or send pull requests, I'm very open to collaboration on this.

Jeff Butler


On Fri, Mar 2, 2018 at 9:22 AM Kamil Hliwa <[hidden email]> wrote:
Keep me in touch and give me info via this topic when you'll post examples for github. I'm also set positive to Kotlin, and as MyBatis is my favorite framework for DB communication, I'll gladly try to help.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Tim
Reply | Threaded
Open this post in threaded view
|

Re: ResultMap - Kotlin support

Tim
Hi Kamil your issue sounds similar to https://github.com/mybatis/mybatis-3/issues/1200

For nested constructor classes that's a separate matter, we don't destruct nested class constructors.
It would require us to hold on to the objects as we build them.
In your example, it is holding on to A, B, C before we construct Final.
We do support this using @ConstructorArgs as Jeff mentioned so it's worth looking at.

You can open a issue on the github https://github.com/mybatis/mybatis-3/issues




On Mon, Mar 5, 2018 at 2:35 PM, Jeff Butler <[hidden email]> wrote:
Hello Kamil and everyone else interested in Kotlin...

I've put some examples for Kotlin up on GitHub here: https://github.com/jeffgbutler/mybatis-kotlin-examples

This is an evolving work, but these examples show patterns for calling MyBatis in Kotlin for a variety of different types of queries.  Initially I didn't write any extensions to MyBatis - this uses MyBatis as is.

If anyone has a better idea for patterns please feel free to open issues or send pull requests, I'm very open to collaboration on this.

Jeff Butler


On Fri, Mar 2, 2018 at 9:22 AM Kamil Hliwa <[hidden email]> wrote:
Keep me in touch and give me info via this topic when you'll post examples for github. I'm also set positive to Kotlin, and as MyBatis is my favorite framework for DB communication, I'll gladly try to help.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.