I have several Kotlin methods I want to call from JNI.
With my current implementation, I have the following source on Kotlin side.
var eventLayer: EventInterface? = null
private fun onDisconnection(start: Boolean) {
eventLayer?.onDisconnection(start)
}
The method signature is "onDisconnection(Z)V" and everything's working fine.
For such a simple method, I was thinking of using a single-expression function. Something like.
var eventLayer: EventInterface? = null
private fun onDisconnection(start: Boolean) = eventLayer?.onDisconnection(start)
When running my application, I have a (not so expected!) NoSuchMethod exception, and I checked the method signature which changed to "onDisconnection(Z)Ljava/lang/Void;"
Anyone to explain me this slight difference? And is there a way to have the same "(Z)V" signature with the single-expression function?
Thank you!
VR
The return type of
private fun onDisconnection(start: Boolean) = eventLayer?.onDisconnection(start)
is whatever eventLayer?.onDisconnection returns. This at least includes null because that's what it returns when eventLayer is null.
If you care about the return type of this function, then you should probably declare it. Then you'll get a compiler error because null is not Unit.
I'm prett sure you could fix it like this:
private fun onDisconnection(start: Boolean) : Unit =
eventLayer?.onDisconnection(start) ?: Unit
... but it's pretty odd to use = with an expression that produces no value. You should probably just write it with braces.
Related
I am injecting a kotlin class into my java code. The kotlin class has two methods with nearly identical signatures:
fun <R> isFluxAuthorizedFor(
strings: List<StringRequest>,
then: (responses: List<StringResult>) -> Flux<R>
): Flux<R>
and
fun <R> isFluxAuthorizedFor(
string: StringRequest,
then: (per: StringResult) -> Flux<R>
): Flux<R> {
The kotlin class supports this overloading just fine.
However, I'm having a devil of a time getting my IDE to use the correct method. I have a method which matches the signature of the former:
private Flux<AuthorizedStrings> collectResults(List<StringResult> responses)
{
//not yet implemented
return null;
}
And yet, when I try and call the injected class' method, I get compilation errors:
List<StringRequest> allStrings = new ArrayList<StringRequest>();
Flux<UserReadAuthorizations> test = authCheck.isFluxAuthorizedFor(allStrings, (it) -> this.collectResults(it) );
The IDE makes two suggestions:
"change type of 'it' to 'List<StringResult>'"
"change method 'collectResults(List<StringResult>)' to 'collectResults(StringResult)'"
both of which imply that Java (or at least the compiler) can't figure out that I'm trying to call the other method. Is this a problem trying to integrate Java 8 and Kotlin? A quirk of the IDE? (I'm using Spring Tool Suite) Some silly user error that I've not yet been able to rubber-duck through?
I played with your code and found that IntelliJ tripped over the type of the lambda as a whole. I had to cast it -> this.collectResults(it) to the type Kotlin was expecting:
List<StringRequest> allStrings = new ArrayList<>();
Flux<UserReadAuthorizations> test = authCheck.isFluxAuthorizedFor(
allStrings,
(Function1<List<StringResult>, Flux<AuthorizedStrings>>) (it -> this.collectResults(it))
);
The signature of your methods themselves was not an issue. Hope this helps you in STS as well.
I have a method yet to be defined, but the return type is known. Is there a way I can still mock this method and test the return to match with the return type?
def getX(a: String): Future[returnType]
when(someService.getX(a)).thenReturn(Future.successful(returnType))
If I understand you correctly, you're looking for ???.
You can define your method like:
def getX(a: String): Future[returnType] = ???
Then you could reference it in your tests or other code and everything would compile, but calling it will fail at runtime with NotImplementedError thrown. It will also fail in tests unless you override it in mock.
I have a class that, in essence, looks like this:
class Checkpointer {
public <Input,Output> Output runFunction(Input input, Function<Input,Output> function) {
Output output;
// Sometimes run the function, sometimes return an Output from a cache
return output
}
}
I would like to mock this class using Mockito doAnswer:
Checkpointer checkpointer; // mocked via #Mock annotation
Mockito
.doAnswer(/* ??? */)
.when(checkpointer)
.runFunction(Mockito.any(), Mockito.any());
The function I want to mock needs to be generic. Can this be done?
For example, my first attempt produced the following. Not only did I resort to Object as the type arguments for Function, but the compiler was still unhappy with unchecked casting:
Mockito.doAnswer((invocation) ->
{
// compiler is not happy with this cast V
Function<Object,Object> function = (Function<Object,Object>)invocation.getArguments()[1];
return function.apply(invocation.getArgument(0));
}).when(checkpointer).runFunction(Mockito.any(), Mockito.any());
If this can't be done, I think can try writing my own mock class extending the first and use Mockito.spy.
The problem here is that you insist on using getArguments, which returns an Object[]
Since you know the index of the Function argument, you can use getArgument(index), as you're doing the line after that.
final Function<String, String> argument = invocation.getArgument(1);
Is this what you're looking for? Type inference for the getArgument generic type is working fine.
If not, can you provide a more elaborate example?
I'm confused on what the following line of code is supposed to be doing:
fun MyContext.req() = request as LaunchRequest
LaunchRequest is a Java class, and MyContext is a Kotlin data class. I've tried looking up examples of Kotlin code that use this syntax, but haven't found anything.
MyContext doesn't have a req() function, so is this just defining a new function for MyContext that returns a variable called "request" of type LaunchRequest?
It’s an extension function named req defined on the receiver MyContext. This technique is used to add new functions to existing classes without the use of inheritance. This concrete example req can be invoked on any object of MyContext.
If you have a reference of MyContext it may be used as follows:
val ctx: MyContext = ...
val req: LaunchRequest = ctx.req()
The as keyword is used to cast the variable request to LaunchRequest.
If the = in the function declaration also leads to confusion: it’s called function with expression body, which can be used to replace block bodies (enclosed in curly brackets) when the function contains a single expression like given in your code.
These are extension functions of Kotlin which help in improving a class's functionality without actually writing a lot of boilerplate code.The function could be also written as
fun MyContext.req(): LaunchRequest(){
return (request as LaunchRequest)
}
Another example of Extension function(to animate view)is:
fun View.animatePulsing() {
val animation = AnimatorSet()
....
....
animation.duration = 150
animation.start()
}
We can use this as:
txtView.animatePulsing()
My data on firebase uses many fields which have string type, but really are enum values (which I check in my validation rules). To download the data into my Android app, following the guide, the field must be a basic String. I know I can work around this with a second (excluded) field which is an enum, and set this basing on the string value. A short example:
class UserData : BaseModel() {
val email: String? = null
val id: String = ""
val created: Long = 0
// ... more fields omitted for clarity
#Exclude
var weightUnitEnum: WeightUnit = WeightUnit.KG
var weightUnit: String
get() = weightUnitEnum.toString()
set(value) { weightUnitEnum = WeightUnit.fromString(value) }
}
enum class WeightUnit(val str: String) {
KG("kg"), LB("lb");
override fun toString(): String = str
companion object {
#JvmStatic
fun fromString(s: String): WeightUnit = WeightUnit.valueOf(s.toUpperCase())
}
}
Now, while this works, it's not really clean:
The enum class itself is (1) kinda long for an
enum, (2) the insides are repeated for every enum. And I have more of them.
It's not only enums, the created field above is really a timestamp,
not a Long.
Each model uses these enum fields a lot of times, which bloats the model classes with repeatable code...
The helper field/functions are getting much worse/longer for fields with types such as Map<SomeEnum, Timestamp>...
So, is there any way to do this properly? Some library maybe? Or some way to write a magic "field wrapper" that would automatically convert strings to enums, or numbers to timestamps, and so on, but is still compatible with Firebase library for getting/setting data?
(Java solutions are welcome too :) )
If the conversion between a property with your enum value and another property of String type is enough, this can be easily done in a flexible way using Kotlin delegated properties.
To say it short, you can implement a delegate for String properties which performs the conversion and actually gets/sets the value of another property storing the enum values, and then delegate the String property to it.
One possible implementation would look like this:
class EnumStringDelegate<T : Enum<T>>(
private val enumClass: Class<T>,
private val otherProperty: KMutableProperty<T>,
private val enumNameToString: (String) -> String,
private val stringToEnumName: (String) -> String) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return enumNameToString(otherProperty.call(thisRef).toString())
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
val enumValue = java.lang.Enum.valueOf(enumClass, stringToEnumName(value))
otherProperty.setter.call(thisRef, enumValue)
}
}
Note: This code requires you to add the Kotlin reflection API, kotlin-reflect, as a dependency to your project. With Gradle, use compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version".
This will be explained below, but first let me add a convenience method to avoid creating the instances directly:
inline fun <reified T : Enum<T>> enumStringLowerCase(
property: KMutableProperty<T>) = EnumStringDelegate(
T::class.java,
property,
String::toLowerCase,
String::toUpperCase)
And a usage example for your class:
// if you don't need the `str` anywhere else, the enum class can be shortened to this:
enum class WeightUnit { KG, LB }
class UserData : BaseModel() {
// ... more fields omitted for clarity
#Exclude
var weightUnitEnum: WeightUnit = WeightUnit.KG
var weightUnit: String by enumStringLowerCase(UserData::weightUnitEnum)
}
Now, the explanation:
When you write var weightUnit: String by enumStringLowerCase(UserData::weightUnitEnum), you delegate the String property to the constructed delegate object. This means that when the property is accessed, the delegate methods are called instead. And the delegate object, in turn, works with the weightUnitEnum property under the hood.
The convenience function I added saves you from the necessity of writing UserData::class.java at the property declaration site (using a reified type parameter) and provides the conversion functions to EnumStringDelegate (you can create other functions with different conversions at any time, or even make a function that receives the conversion functions as lambdas).
Basically, this solution saves you from the boilerplate code that represents a property of enum type as a String property, given the conversion logic, and also allows you to get rid of the redundant code in your enum, if you don't use it anywhere else.
Using this technique, you can implement any other conversion between properties, like the number to timestamp you mentioned.
I am in similar situation & thus found your question, plus whole lot of other similar questions/answers.
Cant answer your question directly but this is what I ended up doing: I decided to change my app & not use enum data types at all - mainly because of the advice from Google dev portal which shows how bad the enum's are on app's performance. See the video below https://www.youtube.com/watch?v=Hzs6OBcvNQE