Look at the code:
CompletableFuture.supplyAsync({
awsBatch.terminateJob(
TerminateJobRequest.builder().jobId(it).reason("terminated").build())}, executor)
Intellij get me:
Type mismatrch:
Required: Supplier<TerminateJobResponse>
Found: () -> TerminateJobResponse
While this compile perfect but without executor:
CompletableFuture.supplyAsync {
awsBatch.terminateJob(TerminateJobRequest.builder().jobId(it).reason("terminated").build())
}
How to pass Supplier to java 8 API from kotlin?
Offtop (just my mood for today)
They created a nice method CompletableFuture.allOf() with return type void, and created this - pass supplier as first argument...
I love java but all of this makes me berserk sometimes - why just not to look at scala and creates something the same??? Kotlin, scala
automatically expose second argument as function like myFunc("parameter"){"function"}. So now I have created a code and must
spend couple hours for compilation some sugar (which should save my time instead)
:(((
Have you tried
CompletableFuture.supplyAsync(Supplier<TerminateJobResponse> {
?
Use Function Literals
CompletableFuture.supplyAsync<Something>({ Runnable { println("abc") } }, { Runnable { println("xyz") } })
See SAM Conversions
Related
I'm trying to develop a Gradle plugin for a language I use (SystemVerilog). I'm still experimenting and figuring things out. Before I write the entire thing as a plugin, I thought it would be best to try out the different parts I need inside a build script, to get a feel of how things should work.
I'm trying to define a container of source sets, similar to how the Java plugin does it. I'd like to be able to use a closure when configuring a source set. Concretely, I'd like to be able to do the following:
sourceSets {
main {
sv {
include '*.sv'
}
}
}
I defined my own sourceSet class:
class SourceSet implements Named {
final String name
final ObjectFactory objectFactory
#Inject
SourceSet(String name, ObjectFactory objectFactory) {
this.name = name
this.objectFactory = objectFactory
}
SourceDirectorySet getSv() {
SourceDirectorySet sv = objectFactory.sourceDirectorySet('sv',
'SystemVerilog source')
sv.srcDir("src/${name}/sv")
return sv
}
SourceDirectorySet sv(#Nullable Closure configureClosure) {
configure(configureClosure, getSv());
return this;
}
}
I'm using org.gradle.api.file.SourceDirectorySet because that already implements PatternFilterable, so it should give me access to include, exclude, etc.
If I understand the concept correctly, the sv(#Nullable Closure configureClosure) method is the one that gives me the ability to write sv { ... } to configure via a closure.
To add the sourceSets property to the project, I did the following:
project.extensions.add("sourceSets",
project.objects.domainObjectContainer(SourceSet.class))
As per the Gradle docs, this should give me the possibility to configure sourceSets using a closure. This site, which details using custom types, states that by using NamedDomainObjectContainer, Gradle will provide a DSL that build scripts can use to define and configure elements. This would be the sourceSets { ... } part. This should also be the sourceSets { main { ... } } part.
If I create a sourceSet for main and use it in a task, then everything works fine:
project.sourceSets.create('main')
task compile(type: Task) {
println 'Compiling source files'
println project.sourceSets.main.sv.files
}
If I try to configure the main source set to only include files with the .sv extension, then I get an error:
sourceSets {
main {
sv {
include '*.sv'
}
}
}
I get the following error:
No signature of method: build_47mnuak4y5k86udjcp7v5dkwm.sourceSets() is applicable for argument types: (build_47mnuak4y5k86udjcp7v5dkwm$_run_closure1) values: [build_47mnuak4y5k86udjcp7v5dkwm$_run_closure1#effb286]
I don't know what I'm doing wrong. I'm sure it's just a simple thing that I'm forgetting. Does anyone have an idea of what that might be?
I figured out what was going wrong. It was a combination of poor copy/paste skills and the fact that Groovy is a dynamic language.
First, let's look at the definition of the sv(Closure) function again:
SourceDirectorySet sv(#Nullable Closure configureClosure) {
configure(configureClosure, getSv());
return this;
}
Once I moved this code to an own Groovy file and used the IDE to show me what is getting called, I noticed that it wasn't calling the function I expected. I was expecting a call to org.gradle.util.ConfigureUtil.configure. Since this is part of the public API, I expected it to be imported by default in the build script. As this page states, this is not the case.
To solve the issue, it's enough to add the following import:
import static org.gradle.util.ConfigureUtil.configure
This will get rid of the cryptic closure related error. It is replaced by the following error, though:
Cannot cast object 'SourceSet_Decorated#a6abab9' with class 'SourceSet_Decorated' to class 'org.gradle.api.file.SourceDirectorySet'
This is caused by the copy/paste error I mentioned. When I wrote the SourceSet class, I drew heavily from org.gradle.api.tasks.SourceSet (and org.gradle.api.internal.tasks.DefaultSourceSet). If we look at the java(Closure) method there, we'll see it has the following signature:
SourceSet java(#Nullable Closure configureClosure);
Notice that it returns SourceSet and not SourceDirectorySet like in my code. Using the proper return type fixes the issue:
SourceSet sv(#Nullable Closure configureClosure)
With this new return type, let's look again at the configuration code for the source set:
sourceSets {
main {
sv {
include '*.sv'
}
}
}
Initially, I thought it was supposed to work as follows: pass main { ... } as a Closure to sourceSets, pass sv { ... } as a Closure to main, and handle the include ... part inside sourceDirectorySet. I banged my head against the wall for a while, because I couldn't find any code in that class hierarchy that takes closures like this.
Now, I think the flow is slightly different: pass main { ... } as a Closure to sourceSets (as initially thought), but call the sv(Closure) function on main (of type sourceSet), passing it { include ... } as the argument.
Bonus: There was one more issue that wasn't related to the "compile" errors I was having.
Even after getting the code to run without errors, it still wasn't behaving as expected. I had some files with the *.svh extension that were still getting picked up. This is because, when calling getSv(), it was creating a new SourceDirectorySet each time. Any configuration that was done previously was getting thrown away each time that this function was called.
Making the sourceDirectorySet a class member and moving its creation to the constructor fixed the issue:
private SourceDirectorySet sv
SourceSet(String name, ObjectFactory objectFactory) {
// ...
sv = objectFactory.sourceDirectorySet('sv',
'SystemVerilog source')
sv.srcDir("src/${name}/sv")
}
SourceDirectorySet getSv() {
return sv
}
The official doc says:
You may sometimes have to call Groovy methods that take Closure arguments from Kotlin code. For example, some third-party plugins written in Groovy expect closure arguments.
In order to provide a way to construct closures while preserving Kotlin’s strong typing, two helper methods exist:
closureOf<T> {}
delegateClosureOf<T> {}
Both methods are useful in different circumstances and depend upon the method you are passing the Closure instance into.
Some plugins expect simple closures.
In other cases, the plugin expects a delegate closure.
There sometimes isn’t a good way to tell, from looking at the source code, which version to use. Usually, if you get a NullPointerException with closureOf<T> {}, using delegateClosureOf<T> {} will resolve the problem.
Well, I have nothing againgst try-fail-fix approach, but maybe there is a deterministic way to tell in advance which method to use and why?
but maybe there is a deterministic way to tell in advance which method to use
Sure by simply examining the source code of the plugin you are configuring. For example, their Bintray plugin example is:
bintray {
pkg(closureOf<PackageConfig> {
// Config for the package here
})
}
If you were to examine the source, you'll find this: https://github.com/bintray/gradle-bintray-plugin/blob/master/src/main/groovy/com/jfrog/bintray/gradle/BintrayExtension.groovy#L35..L37
def pkg(Closure closure) {
ConfigureUtil.configure(closure, pkg)
}
That is a simple Closure so closureOf<T> {} would be appropriate here according to the docs.
Now their other example is for the Gretty Plugin when configuring farms:
farms {
farm("OldCoreWar", delegateClosureOf<FarmExtension> {
// Config for the war here
})
}
If you examine the source, you'll find this: https://github.com/akhikhl/gretty/blob/master/libs/gretty-core/src/main/groovy/org/akhikhl/gretty/FarmsConfig.groovy#L23..L32
void farm(String name = null, Closure closure) {
if(name == null)
name = ''
def f = farmsMap_[name]
if(f == null)
f = farmsMap_[name] = createFarm()
closure.delegate = f
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure()
}
That's much more complex than the previous example and according to the docs, since this clearly expects delegate closure, then delegateClosureOf<T> {} would be the appropriate choice.
I have a data class A with a function as follows:
data class A(val a: String) {
fun foo(b: String) = "$a, $b"
}
I attempt the following mock in my test:
fun `whatever`() {
val spy = spyk<A>()
every { spy.a } returns "Tree"
assertThat(spy.foo("Snake")).isEqualTo("Tree Snake")
}
When I run a test written like this it fails with a NullPointerException on the line fun foo... in the data class.
Am I doing anything wrong or is this a bug in MockK?
I have totally different results when I run your code. Firstly it complains that there is no default constructor.
Then I fixed it to use the non-default constructor and it prints "abc Snake"
val spy = spyk(A("abc"))
every { spy.a } returns "Tree"
println(spy.foo("Snake"))
There is a reason for that. Kotlin is accessing a property through a field in foo function. This seems to be an optimization.
MockK is not able to do anything about it right now. There is the following ticket to transform getfield call: https://github.com/mockk/mockk/issues/104
I'm trying to build a Gradle plugin that would allow the following:
myPluginConfig {
something1 {
// this is a closure
}
somethingElse {
// this is another closure
}
// more closures here
}
To achieve this I'm fairly certain I need to use a NamedDomainObjectContainer to wrap a Closure collection, so I've set up the following plugin:
class SwitchDependenciesPlugin implements Plugin<Project> {
void apply(Project project) {
// add the extension
project.getExtensions().myPluginConfig = project.container(Closure)
// read the current configuration
NamedDomainObjectContainer<Closure> config = project.myPluginConfig
// test it out, always returns []
System.out.println(config)
}
}
What am I doing wrong, do I need to use project.extensions.create instead? If so, how?
EDIT: my use case consists in adding dependencies according to some variables defined in the project hierarchy. For example, the following configuration would add the red project if the variable red is defined on project.ext, or gson otherwise:
myPluginConfig {
redTrue {
compile project(':red')
}
redFalse {
compile 'com.google.code.gson:gson:2.4'
}
greenTrue {
compile project(':green')
}
}
For this use case I need to have dynamic names for myPluginConfig, and therefore either a Map or a NamedDomainObjectContainer.
Can you elaborate what you try to model here? I think you have two options. One is to use NamedDomainObjectContainer. Here you need a class that represents "something". Have a look at the Gradle userguide chapter about maintaining multiple domain objects (see https://docs.gradle.org/current/userguide/custom_plugins.html#N175CF) in the sample of the userguide, the "thing" is 'Book'. The build-in configuration syntax like you described above comes for free.
If you want to have a syntax like above without the need for maintaining multiple domain objects, you can simply add a method that takes a Closure as a parameter to your Extension class:
void somethingToConfigure(Closure) {
}
You cannot have Closure as a type for NamedDomainObjectContainer simply because the type you use must have a property called name and a public constructor with a single String parameter.
To overcome this, you may create a wrapper around Closure with a name field added.
EDIT: Please let me be clear, I'm asking how to do this in Grails using Spring Dependency Injection, and NOT Grails' metaclass functionality or new().
I have a grails service that is for analyzing log files. Inside the service I use the current time for lots of things. For unit testing I have several example log files that I parse with this service. These have times in them obviously.
I want my service, DURING UNIT TESTING to think that the current time is no more than a few hours after the last logging statement in my example log files.
So, I'm willing to this:
class MyService {
def currentDate = { -> new Date() }
def doSomeStuff() {
// need to know when is "right now"
Date now = currentDate()
}
}
So, what I want to be able to do is have currentDate injected or set to be some other HARDCODED time, like
currentDate = { -> new Date(1308619647140) }
Is there not a way to do this with some mockWhatever method inside my unit test? This kind of stuff was super easy with Google Guice, but I have no idea how to do it in Spring.
It's pretty frustrating that when I Google "grails dependency injection" all I find are examples of
class SomeController {
// wow look how amazing this is, it's injected automatically!!
// isn't spring incredible OMG!
def myService
}
It feels like all that's showing me is that I don't have to type new ...()
Where do I tell it that when environment equals test, then do this:
currentDate = { -> new Date(1308619647140) }
Am I just stuck setting this property manually in my test??
I would prefer not to have to create a "timeService" because this seems silly considering I just want 1 tiny change.
Groovy is a dynamic language, and as such it allows you to do almost what you're asking for:
class MyServiceTests extends GrailsUnitTestCase {
def testDoSomeStuff() {
def service = new MyService()
service.currentDate = { -> new Date(1308619647140) }
// assert something on service.doSomeStuff()
}
}
Keep in mind this only modifies the service instance, not the class. If you need to modify the class you'll need to work with the metaClass. Take a look at this post by mrhaki.
Another option would be to make the current date a parameter to doSomeStuff(). That way you wouldn't need to modify your service instance.
Thanks for the help guys. The best solution I could come up with for using Spring DI in this case was to do the following in
resources.groovy
These are the two solutions I found:
1: If I want the timeNowService to be swapped for testing purposes everywhere:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
timeNowService(TimeNowMockService)
} else {
println ">>> not test env"
timeNowService(TimeNowService)
}
}
2: I could do this if I only want this change to apply to this particular service:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
time1(TimeNowMockService)
} else {
println ">>> not test env"
time1(TimeNowService)
}
myService(MyService) {
diTest = 'hello 2'
timeNowService = ref('time1')
}
}
In either case I would use the service by calling
timeNowService.now().
The one strange, and very frustrating thing to me was that I could not do this:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
myService(MyService) {
timeNow = { -> new Date(1308486447140) }
}
} else {
println ">>> not test env"
myService(MyService) {
timeNow = { -> new Date() }
}
}
}
In fact, when I tried that I also had a dummy value in there, like dummy = 'hello 2' and then a default value of dummy = 'hello' in the myService class itself. And when I did this 3rd example with the dummy value set in there as well, it silently failed to set, apparently b/c timeNow blew something up in private.
I would be interested to know if anyone could explain why this fails.
Thanks for the help guys and sorry to be impatient...
Since Groovy is dynamic, you could just take away your currentDate() method from your service and replace it by one that suits your need. You can do this at runtime during the setup of your test.
Prior to having an instance of MyService instantiated, have the following code executed:
MyService.metaClass.currentDate << {-> new Date(1308619647140) }
This way, you can have a consistent behavior across all your tests.
However, if you prefer, you can override the instance method by a closure that does the same trick.
Let me know how it goes.
Vincent Giguère