I have the following method in a Spring Boot application using Kotlin. It won't compile because addValue method takes String paramName, and Object value. In my case passing NULL is a valid case, because I want all bankers, not ones from a specific branch.
Is there anyway to work around this in Kotlin.
override fun getBankers(branchId: UUID?): Iterable<Banker> {
val query = this.sql.getProperty("banker.selectByBranch")
val params = MapSqlParameterSource()
.addValue("branchId", null)
return this.jdbcTemplate.query(query, params, BankerRowMapper())
}
If I do branchId!! I get an NPE.
If you call your method with a null branchId parameter and inside your method you use that parameter with the !! operator, you will get a NullPointerException because that's what the !! operator does. Shouldn't you use the parameter in your method somehow? Maybe like this:
override fun getBankers(branchId: UUID?): Iterable<Banker> {
val query = this.sql.getProperty("banker.selectByBranch")
val params = MapSqlParameterSource()
.addValue("branchId", branchId?.toString())
return this.jdbcTemplate.query(query, params, BankerRowMapper())
}
Related
I have an API that has method which takes vararg of some object (fox example Param).
I need to filter null params and not put it to vararg. Is it possible ?
I know there is a method in kotlin listOfNotNull but api accepts vararg(
This is example of calling API method (apiMethod(vararg params: Param)):
someFun() {
apiMethod(
Param("first"),
Param("second"),
null // need to filter it
)
}
P.S. I can't change apiMethod()
If I understand your question correctly, you need to filter your arguments before passing them to the function since you cannot modify the function. To do this, you can filter to a List, and then convert that list to a typed array and pass it using the * spread operator:
fun someFun() {
apiMethod(
*listOfNotNull(
Param("first"),
Param("second"),
null // need to filter it
).toTypedArray()
)
}
It's a shame you have to use toTypedArray(). IMO, it should be supported for all Iterables, since Lists are far more common than Arrays. This feature request has not had a lot of attention from JetBrains.
Try mapNotNull method
val notNullArgs = args.mapNotNull { it }
If there will be any null it it will be filtered
Your apiMethod() should fail either filter out nulls or just fail if provided list that contains null
fun apiMethod(a : Int, b : String, vararg params : List<Any?>){
require(params.size == params.mapNotNull { it }.size) {
"Params must not contain null values"
}
// or
val filtered = params.mapNotNull { it }
}
I am learning Kotlin coming from Java, and I stumbled upon an unexpected behavior.
I noticed, that in my below code, I seem to accidentally declare a new lambda at a bad position instead of using the one I already have. How can I fix this?
I wrote these two declarations:
/**
* Dataclass used as an example.
*/
data class Meeple(var name: String, var color: String = "translucent")
/**
* Function to map from a List<T> to a new List of equal length,
* containing the ordered elements received by applying a Mapper's map
* function to every element of the input List.
*
* #param T Type of input List-elements
* #param O Type of output List-elements
* #param mapper The mapping function applied to every input element.
* #return The List of output elements received by applying the mapper on all
* input elements.
*/
fun <T, O> List<T>.map(mapper: (T) -> O?): List<O?> {
val target = ArrayList<O?>();
for (t in this) {
val mapped: O? = mapper.invoke(t)
target.add(mapped);
}
return target;
}
The data class is just a dummy example of a simple object. The List.map extension function is meant to map from the elements of the list to a new type and return a new List of that new type, almost like a Stream.map would in Java.
I then create some dummy Meeples and try to map them to their respective names:
fun main(args: Array<String>) {
val meeples = listOf(
Meeple("Jim", "#fff"),
Meeple("Cassidy"),
Meeple("David", "#f00")
)
var toFilter: String = "Cassidy"
val lambda: (Meeple) -> String? =
{ if (it.name == toFilter) null else it.name }
toFilter = "Jim"
for (name in meeples.map { lambda }) {
println(name ?: "[anonymous]") // This outputs "(Meeple) -> kotlin.String?" (x3 because of the loop)
}
}
I did this to check the behavior of the lambda, and whether it would later filter "Jim" or "Cassidy", my expectation being the later, as that was the state of toFilter at lambda initialization.
However I got an entirely different result. The invoke method, though described by IntelliJ as being (T) -> O? seems to yield the name of the lambda instead of the name of the Meeple.
It seems, that the call to meeples.map { lambda } does not bind the lambda as I expected, but creates a new lambda, that returns lambda and probably internally calls toString on that as well.
How would I actually invoke the real lambda method, instead of declaring a new one?
You already mentioned in the comments you figured out that you were passing a new lambda that returns your original lambda.
As for the toFilter value changing: The lambda function is like any other interface. As you have defined it, it captures the toFilter variable, so it will always use the current value of it when the lambda is executed. If you want to avoid capturing the variable, copy its current value into the lambda when you define the lambda. There are various ways to do this. One way is to copy it to a local variable first.
var toFilter: String = "Cassidy"
val constantToFilter = toFilter
val lambda: (Meeple) -> String? =
{ if (it.name == constantToFilter) null else it.name }
toFilter = "Jim"
Pretty much anything you can do with Stream in Java, you can do to an Iterable directly in Kotlin. The map function is already available, as mentioned in the comments.
Edit: Since you mentioned Java behavior in the comments.
Java can capture member variables, but local variables have to be marked final for the compiler to allow you to pass them to a lambda or interface. So in this sense they capture values only (unless you pass member variable). The equivalent to Java's final for a local variable in Kotlin is val.
Kotlin is more lenient than Java in this situation, and also allows you to pass a non-final local variable (var) to an interface or lambda, and it captures the variable in this case. This is what your original code is doing.
Even though you have found the issue as you mention in comments, I am adding this answer with some details to help any future readers.
So when you create lambda using
val lambda: (Meeple) -> String? = { if (it.name == toFilter) null else it.name }
This basically translates to
final Function1 lambda = (Function1)(new Function1() {
public Object invoke(Object var1) {
return this.invoke((Meeple)var1);
}
#Nullable
public final String invoke(#NotNull Meeple it) {
Intrinsics.checkNotNullParameter(it, "it");
return Intrinsics.areEqual(it.getName(), (String)toFilter.element) ? null : it.getName();
}
});
Now correct way to pass this to your map method would be as you have mentioned in comments
name in meeples.map(lambda)
but instead of (lambda) you wrote { lambda }, this is the trailing lambda convention
name in meeples.map { lambda }
// if the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses:
// If the lambda is the only argument in that call, the parentheses can be omitted entirely
this creates a new lambda which returns the lambda we defined above, this line basically gets translated to following
HomeFragmentKt.map(meeples, (Function1)(new Function1() {
public Object invoke(Object var1) {
return this.invoke((Meeple)var1);
}
#Nullable
public final Function1 invoke(#NotNull Meeple it) {
Intrinsics.checkNotNullParameter(it, "it");
return lambda; // It simply returns the lambda you defined, and the code to filter never gets invoked
}
}))
I'm trying to create a Json object using Jackson but I can't use put because it's deprecated and will fail the pipelines checks in my company so I'm trying to use set:
fun HttpRequest.toJSONString(): String {
val mapper = ObjectMapper()
val root = mapper.createObjectNode()
val headers = mapper.createObjectNode()
this.headers().map().entries.forEach {h ->
headers.put(h.key, mapper.convertValue(h.value, JsonNode::class.java)) // its deprecated
}
root.set("headers", headers) // its failing
root.set("url_path", "https://facebook.com") // fails
return root.toString()
}
I got an error message: Not enough information to infer parameter T in operator fun <T : JsonNode!> set(p0: String!, p1: JsonNode!): T!
Please specify it explicitly.
How can I solve it?
I would advise you to try something more like that:
fun HttpRequest.toJSONString() =
ObjectMapper().writeValueAsString(
this.headers
.put("url_path", listOf("https://facebook.com"))
// put the rest here
)
It is usually inconvenient to deal directly with the Node objects and they are protected. I would strongly advise you to write your whole objects in kotlin and then use writeValueAsString from the ObjectMapper.
Use put when the value is a string (that version of the method is not deprecated). Use replace when the value is a JsonNode, or, if you want to chain the invocations together use set with a type parameter. Code to demonstrate:
val mapper = ObjectMapper()
val root = mapper.createObjectNode()
val headers = mapper.createObjectNode()
headers.put("key", "value") // Use put when the value is a primitive
root.replace("headers", headers) // Use replace for objects
root.set<JsonNode>("headers", headers) // Or use set with a type parameter
root.put("url_path", "https://facebook.com")
return root.toString()
I am trying to use the public interface Function (as I learned it in Java) in Kotlin.
For this I created my method
fun foo(input: List<String>, modifier1: Function<List<String>>? = null){
}
as far I remember here I should be able to do modifier1.apply(input)
but seems like it is not possible (it is possible to do modifier1.apply{input} though)
Reading more about it I found this:
Kotlin: how to pass a function as parameter to another?
So I changed my method signature to this:
fun foo(input:String, modifier2: (List<String>) -> (List<String>){
}
Here I am able to do modifier2(input)
and I can call foo this way
service.foo(input, ::myModifierFunction)
where
fun myModifierFunction(input:List<String>):List<String>{
//do something
return input
}
So far this seems possible but it is not acceptable to have the function reference as nullable, is there any way I can do that? or use Function ?
You were using kotlin.Function instead of java.util.function.Function in your first example. Note that the latter takes 2 generic types: 1 for the incoming parameter and 1 for the resulting one.
The apply method you saw is the default Kotlin one: apply, not the one of Java's Function-interface.
If you really want to have the Java-function as nullable type the following should work:
fun foo(input: List<String>, modifier1: java.util.function.Function<List<String>, List<String>>? = null) {
modifier1?.apply(input) ?: TODO("what should be done if there wasn't passed any function?")
}
Kotlin variant for the same:
fun foo(input: List<String>, modifier1: ((List<String>) -> List<String>)? = null) {
modifier1?.invoke(input) ?: TODO("what should be done if there wasn't passed any function?")
}
Maybe also a default function, such as { it } instead of null might better suite your needs? (Java variant would be Function.identity()):
// java modifier1 : Function<List<String>, List<String>> = Function.identity()
// kotlin modifier1 : (List<String>) -> List<String> = { it }
You can make the reference nullable simply with ? — the only wrinkle is that the whole function type needs to be in parens first:
fun foo(input: String, modifier2: ((List<String>) -> List<String>)? = null) {
}
As required, modifier2 is optional; if specified, it may contain null, or it may contain a function taking and returning a list of strings.
As mentioned in another answer, kotlin.Function is not the same as java.util.function.Function — though in practice you shouldn't need to refer to either directly, as the -> notation is simpler.
If you want to pass in a function that takes List<String> as its parameter and returns nothing meaningful, the type for you is Function1<List<String>, Unit>. The method name for invoking a function is invoke(), which you could also do with just regular parentheses, if it wasn't nullable. All in all, your code could look something like this:
fun foo(input: List<String>, modifier1: Function1<List<String>, Unit>? = null) {
modifier1?.invoke(input)
}
The 1 in the typename of Function1 means that it's a one parameter function, there's also Function0, Function2, etc.
The Function type on its own is not something you can use to call that function, as it's an empty marker interface. All functions implement this regardless of how many parameters they have.
I have a function with a prototype similar to:
class objectToMock {
fun myFunc(stringArg: String, booleanArg: Boolean = false, functionArg: (String) -> Any = { 0 }): String
}
I'd like to be able to stub myFunc but can't figure out how to. Something like
#Mock
lateinit var mockedObject: ObjectToMock
#Before
fun setup() {
MockitoAnnotations.initMocks(this)
`when`(mockedObject.myFunc(anyString(), anyBoolean(), any())).thenReturn("")
}
Using any() and notNull() both lead to java.lang.IllegalStateException: any() must not be null
The solution here is to use anyOrNull from https://github.com/nhaarman/mockito-kotlin, or implement that helper yourself.
Mockito often returns null when calling methods like any(), eq() etcetera. Passing these instances to methods that are not properly mocked, can cause NullPointerExceptions
see: https://github.com/nhaarman/mockito-kotlin/wiki/Parameter-specified-as-non-null-is-null
you can add
mockedObject = ObjectToMock()
#Before It is the place to initialize.
#Test It is the place to test.you can call mockedObject.myFunc()