Join eq function not working with Jooq and Kotlin - kotlin

I'm using:
Jooq 3.13.2
Kotlin 1.3.71
Spring boot 2.2.6.RELESE
Java 11
I was able to generate Jooq classes and execute a simple query:
class StoryCustomRepositoryImpl #Autowired constructor(
private val dslContext: DSLContext
): StoryCustomRepository {
override fun findEmployeeStories(pageable: Pageable) {
return dslContext.select(STORY.ID, STORY.DESCRIPTION)
.from(STORY)
.forEach { println($it[STORY.ID]) }
}
}
When I try to add a bit more complex logic by adding join, compilation is failing:
class StoryCustomRepositoryImpl #Autowired constructor(
private val dslContext: DSLContext
): StoryCustomRepository {
override fun findEmployeeStories(pageable: Pageable) {
return dslContext.select(STORY.ID, STORY.DESCRIPTION)
.from(STORY)
.join(USERS).on(USERS.ID.eq(STORY.CREATED_BY))
.forEach { println($it[STORY.ID]) }
}
}
Compilation fails on following line .join(USERS).on(USERS.ID.eq(STORY.CREATED_BY))
Error:
None of the following functions can be called with the arguments supplied:
public abstract fun eq(p0: Int!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: Field<Int!>!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: QuantifiedSelect<out Record1<Int!>!>!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: Select<out Record1<Int!>!>!): Condition! defined in org.jooq.TableField
I was following this tutorial: https://blog.jooq.org/2017/05/18/10-nice-examples-of-writing-sql-in-kotlin-with-jooq/
Edit:
It looks like the issue is that STORY.CREATED_BY is type of Long, while USERS.ID is type of Integer. I'm not sure what needs to be changed to be able to fix this.
Thank you

You should probably change the type of all of these ID columns and their reference to be the same, i.e. BIGINT.
As a quick workaround, you can use Field.coerce(). I would prefer that over Field.cast(). The difference is that coerce() does not have any effect on the generated SQL (which you want to avoid to get better index usage), whereas cast() translates to the SQL CAST() function.

Related

benefit in using operator invoke in functional interfaces

I am just wondering what is the benefit of using the operator invoke than not using it. I am trying it out on one of my interfaces to see what the benefits are.
fun interface MapperDomainToData<in E, out M> {
operator fun invoke(entity: E): M
}
fun interface MapperDomainToData<in E, out M> {
fun map(entity: E): M
}
In my implementation there seems to be no difference. In fact I prefer not using it as the method name is more meaningful.
class MapSocialLoginRequestImp #Inject constructor() : MapperDomainToData<SocialLoginRequestEntity, SocialLoginRequestModel> {
override fun invoke(entity: SocialLoginRequestEntity): SocialLoginRequestModel {
return SocialLoginRequestModel(
token = entity.token,
provider = entity.provider
)
}
override fun map(entity: SocialLoginRequestEntity): SocialLoginRequestModel {
return SocialLoginRequestModel(
token = entity.token,
provider = entity.provider
)
}
}
I think the second implementation is the more clear as the map method is more readable.
The difference isn't in how you declare the interface implementation, but only in how you use the interface object. Of course there's no difference in your code.
The difference is between
myMapper(entity)
and
myMapper.map(entity)
To be clear, it's entirely reasonable to prefer the second one, but that's the difference that the invoke operator function provides.

Kotlin Factory Class with Generic outputs

I'm in the process of trying to port some code I wrote in Java over to Kotlin and I'm struggling mightily with some issues around generics. I quite commonly use a factory pattern in Java to return an instance of a generic interface that I want to call for a given type.
In Java I had this contract:
public Message<T extends Action> {
private List<T> actions;
..some other properties
}
And this interface:
public interface MessageConverter<T extends Action, M extends BaseModel> {
List<M> convertMessage(Message<T> message);
DataType getDataType();
}
And lastly this factory:
public class MessageConverterFactory {
//This gets populated via DI
private Map<DataType, MessageConverter> converterMap;
public <T extends Action, M extends BaseModel> MessageConverter<T, M> getMessageConverter(DataType dataType) {
return converterMap.get(dataType);
}
}
With all that in place, I was able to do things like this:
Message<T> message = mapper.readValue(messageString, type);
MessageConverter<T, M> messageConverter = messageConverterFactory.getMessageConverter(dataType);
List<M> dataModels = messageConverter.convertMessage(message);
I understand that I was abusing raw generic types in Java to an extent to make this happen, but I assumed there would be some way to still do a generic factory pattern like this.
However, no matter with I try with generic variance, star projections, etc. I cannot get Kotlin to accept any version of this code. The closest I got was down to the invocation of the generic converter's convertMessage call. It was failing because I was using star projections and attempting to restrict the type of T, but that was leading to the compiler thinking convertMessage accepts Message<Nothing>.
Is code like this possible in Kotlin? Or is there a similar alternative approach I should be using instead?
Thanks,
Jeff
The literal conversion of this to Kotlin is pretty simple, and the Java-to-Kotlin converter built in to IDEA would spit something like this out almost directly, given the equivalent Java code:
class Message<T: Action> {
private val actions: List<T> = TODO()
...
}
interface MessageConverter<T: Action, out M: BaseModel> {
fun convertMessage(message: Message<T>): List<M>
val dataType: DataType
}
class MessageConverterFactory(val converterMap: Map<DataType, MessageConverter<*, *>>) {
fun <T: Action, M: BaseModel> getMessageConverter(dataType: DataType): MessageConverter<T, M> {
return converterMap[dataType] as MessageConverter<T, M>
}
}
Note, the cast in getMessageConverter -- your Java code is doing the equivalent, without being explicit about it -- I believe the compiler would even spit out a warning about an unchecked assignment.
An alternative in Kotlin is to use an inline function with reified types to return the appropriate converter. For example, something like this:
inline fun <reified T: Action, reified M: BaseModel> converterOf(): MessageConverter<T, M> = when {
T::class == FooAction::class, M::class == BarModel::class -> TODO()
else -> error("No converter available for type ${T::class.simpleName} to ${M::class.simpleName}")
}

How to make a generic function for enumValues<T> in Kotlin?

I struggle with providing a type as parameter for a procedure that uses the enumValues<MyEnum>() function.
Got it to work with reified but using inline functions all the way is no option for me.
fun <T: Enum<Trait>> traits(
selectionState: SnapshotStateMap<Trait, Boolean>
) {
val chunks = enumValues<T>().toList().chunked(5)
chunks.forEach {
Row {
it.forEach {
TraitIcon(it, selectionState)
}
}
}
}
My enums all derive from enum class Trait. So in fact I want to pass enum class TraitFoo: Trait, enum class TraitBar: Trait and so on into the function.
Cannot use 'T' as reified type parameter. Use a class instead.
Is the compile error I receive here. Any idea of solving this? I am somewhat confused why this is not working.
Looking at the implementation of enumValues:
public inline fun <reified T : Enum<T>> enumValues(): Array<T>
I see it uses reified. That does mean the type has to be known at compile time. Therefore I can not pass a generic but need to pass an explicit type? Is that the issue?
If yes - is there another way to achieve this rather than using reified ?
If you want to be able to use T in your function as if it's a real type then it must be reified. And in order for a type parameter to be reified it must be part of an inline function. So you're going to need an inline function.
The next bit is figuring out the generics. You currently have:
<T : Enum<Trait>>
That means, due to the nature of enums, that T can't possibly be anything other than Trait. However, you have since clarified that Trait is not an enum but is actually an interface that's implemented by various enum classes. So what you really want is T to be bounded by both Enum<T> and Trait.
Given all this, I believe what you're looking for is the following:
inline fun <reified T> traits(
selectionState: SnapshotTraitMap<Trait, Boolean>
) where T : Enum<T>, T : Trait {
val chunks = enumValues<T>().toList().chunked(5)
chunks.forEach {
Row {
it.forEach {
TraitIcon(it, selectionState)
}
}
}
}

Nullable of nullable in Kotlin?

I have a use case where I need double level of nullable, something like x: SomeClass??. See prefetchedRecord argument in java code below
public Optional<SomeClass> fetchRecord(Long id) {
...
}
public void process(
Long id,
Optional<Optional<SomeClass>> prefetchedRecord
) {
Optional<SomeClass> fetchedRecord = prefetchedResult.orElseGet( () -> fetchRecord(id) )
if (fetchedRecord.isPresent()) { ... process ... }
else { ... do something else ... }
}
So for the prefetchedRecord the inner optional signifies the result of the fetching and the outer optional shows whether the fetching was ever done before calling the process function. I use two optional to avoid refetching the record even if the fetching returned nothing.
How would you write this in Kotlin? I realize using double optional is not that clear and I could use a custom class instead, smth like
data class FetchResult<T>(val result: T, val fetched: boolean)
but I wonder if there is something built in into Kotlin to support this use case.
There is no way to do nullable of nullable in Kotlin. I think Kotlin way is avoid null in most cases. You can use sealed-classes for more expressive code.
For example:
sealed class Result<out T> {
data class Fetched<T>(val result: T): Result<T>()
data class Prefetched<T>(val result: T): Result<T>()
object None: Result<Nothing>()
}
Sealed classes provides algebraic data types support and you can make very expressive types with this powerful language feature.
You also can use Kotlin standard Result in some cases
No, there is nothing built-in in Kotlin to handle your requirements. If you are targeting Java platform you can use java.util.Optional<T> class:
fun process(id: Long, prefetchedRecord: Optional<Optional<SomeClass>>) {
...
}
Or you can try to use java.util.Optional<T> class like this:
fun process(id: Long, prefetchedRecord: Optional<SomeClass>?) {
...
}

Prevent Kotlin from forcing Java to see a wildcard type

This works fine:
class Wrapped<out T>(val value: T)
open class Wrapper<T> {
fun wrap(map: T): Wrapped<T> = Wrapped(map)
}
class Wrapper2 : Wrapper<Map<String, String>>()
val wrapped: Wrapped<Map<String, String>> = Wrapper2().wrap(mapOf())
But, when I try to access Wrapper2.wrap from Java, the Map comes back with a wildcard type:
Map<String, String> toWrap = new HashMap<>();
Wrapped<Map<String, String>> result;
result = new Wrapper<Map<String, String>>().wrap(toWrap); // ok
result = new Wrapper2().wrap(toWrap); // NOT ok, returns Wrapped<Map<String, ? extends String>>
I can work around this by overriding wrap in Wrapper2 with the explicit type.
Why does Wrapper2.wrap return a different type than Wrapper.wrap?
You can suppress Kotlin using wildcards in generics as described in the Kotlin reference where it describes the #JvmSuppressWildcards annotation (or the reverse of that #JvmWildcard annotation).
From the docs:
On the other hand, if we don't need wildcards where they are generated, we can use #JvmSuppressWildcards:
fun unboxBase(box: Box<#JvmSuppressWildcards Base>): Base = box.value
// is translated to
// Base unboxBase(Box<Base> box) { ... }
NOTE: #JvmSuppressWildcards can be used not only on individual type arguments, but on entire declarations, such as functions or classes, causing all wildcards inside them to be suppressed.
Change
class Wrapper2 : Wrapper<Map<String, String>>()
to
class Wrapper2 : Wrapper<MutableMap<String, String>>()
You'll see in the Kotlin source,
public interface Map<K, out V> {
whereas:
public interface MutableMap<K, V> : Map<K, V> {
I believe out V is the reason you're getting ? extends String, see Covariance under the generics docs for Kotlin and a quick search on Google should give you some more insight into covariance and contravariance in Java .