Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use WebTestClient with mock server in Kotlin #20606

Closed
spring-projects-issues opened this issue Oct 10, 2017 · 13 comments
Closed

Unable to use WebTestClient with mock server in Kotlin #20606

spring-projects-issues opened this issue Oct 10, 2017 · 13 comments
Assignees
Labels
in: test Issues in the test module type: task A general task
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Oct 10, 2017

Daniel Jones opened SPR-16057 and commented

I'm trying to set up a Kotlin/Spring project using Spring Boot 2.0.0.M4 and Spring Framework 5.0.0.M4 and have ran into trouble with WebTestClient in a mocked-server test.

Essentially the following in Java works fine:

class JavaHelper {
    static WebTestClient getMockWebTestClient(ApplicationContext ctx) {
        return WebTestClient.bindToApplicationContext(ctx)
                            .apply(springSecurity())
                            .configureClient()
                            .filter(basicAuthentication())
                            .build();
    }
}

But Kotlin is unable to infer the type T of apply method:

<T extends B> T apply(MockServerConfigurer configurer)

With the following code:

WebTestClient.bindToApplicationContext(context)
                .apply(springSecurity())
                .configureClient()
                .filter(basicAuthentication())
                .build()

The problem is to do with the generic typings, I'm still fairly new to Kotlin but if I write my test using the same package as ApplicationContextSpec (since they're package-private) and do the following, it works as expected:

(WebTestClient.bindToApplicationContext(context) as ApplicationContextSpec)
                .apply<ApplicationContextSpec>(springSecurity())
                .configureClient()
                .filter(basicAuthentication())
                .build()

I think the following:

static MockServerSpec<?> bindToApplicationContext(ApplicationContext applicationContext) {
    return new ApplicationContextSpec(applicationContext);
}

should be changed to return ApplicationContextSpec (or at least AbstractMockServerSpec<ApplicationContextSpec>):

and make the class ApplicationContextSpec public. The constructor can still be default visibility so users won't be able to misuse the class outside of the defined API, and users in Kotlin will be able to import it for type inference.


Affects: 5.0 GA

Issue Links:

Referenced from: commits b9a0e6b

2 votes, 11 watchers

@spring-projects-issues
Copy link
Collaborator Author

Daniel Jones commented

I've added a test repo here:

https://github.com/dan-j/kotlin-reactive-test-SPR-16057

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Oct 27, 2017

Sébastien Deleuze commented

I think this is similar to #20251 which was expected to be fixed in Kotlin 1.2 via KT-5464 and similar to what Rob Winch raised as well, but was sadly postponed to Kotlin 1.3. As reported to JetBrains, this pending issue on Kotlin side makes WebTestClient not usable at all with Kotlin, and I have no other workaround to propose than using WebClient with non-mocked server for now, Reactor and Spring Kotlin extensions making that quite usable as demonstrated on this example.

For now I am going to update WebTestClient Javadoc to add a warning and a link to JetBrains issue + update our reference documentation with these infos. We will mark this issue as resolved asap we have the confirmation Kotlin 1.3 fixes this issue and our documentation has been updated to specify Kotlin 1.3+ should be used for WebTestCient.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Apr 17, 2018

Sébastien Deleuze commented

Notice that #20251 is now fixed.

@andriipivovarov
Copy link

Any work around?

@noah-iam
Copy link

Hey,
For the similar issue , I want to share you my piece of code that is giving me same error :

.webFilter<>(myfilter) . This is saying to give the generic type here.

Error : Type expected

val client: WebTestClient = WebTestClient.bindToWebHandler { Mono.empty() } .webFilter<>(myfilter) .build()

Error : Type argument is not within its bounds. Expected: Nothing! Found: WebFilter!

@sdeleuze can you help me in this

@maresja1
Copy link

maresja1 commented Oct 19, 2020

@andriipivovarov Work around:

You have to re-define class MutatorFilter (it is a private static class in SecurityMockServerConfigurers):

// copy of org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.MutatorFilter
internal class MutatorFilter : WebFilter {

    override fun filter(exchange: ServerWebExchange, webFilterChain: WebFilterChain): Mono<Void> {
        val context = exchange.getAttribute<Supplier<Mono<SecurityContext>>>(ATTRIBUTE_NAME)
        if (context != null) {
            exchange.attributes.remove(ATTRIBUTE_NAME)
            return webFilterChain.filter(exchange)
                .subscriberContext(ReactiveSecurityContextHolder.withSecurityContext(context.get()))
        }
        return webFilterChain.filter(exchange)
    }

    companion object {
        const val ATTRIBUTE_NAME = "context"
    }
}

And apply:

        WebTestClient.bindToApplicationContext(context)
            .configureClient()
            .baseUrl("https://api.example.com")
            .defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE)
// ...
            .apply { _, httpHandlerBuilder, _ ->
                httpHandlerBuilder?.filters { filters -> filters.add(0, MutatorFilter()) }
            }

If anyone knows about a better way, please let me know.

@sdeleuze sdeleuze changed the title Unable to use WebTestClient with mock server in Kotlin [SPR-16057] Unable to use WebTestClient with mock server in Kotlin Oct 27, 2020
@sdeleuze
Copy link
Contributor

This issue still happens with Kotlin 1.4.10 likely due to KT-40804 and I agree we should try to find a solution. I am discussing that with Kotlin team.

@xetra11
Copy link

xetra11 commented Feb 4, 2021

Any updates on this?

@sdeleuze
Copy link
Contributor

Both Kotlin and Spring team agreed this issue should be fixed on Kotlin side. My current hope is that it will be fixed in Kotlin 1.6 (Kotlin 1.5 is just around the corner and Kotlin has now a 6 month release cycle so that won't be too far away).

@petukhovv
Copy link

Note that we (Kotlin team) supported given cases in the experimental mode in 1.5.30. In 1.5.30 the -Xself-upper-bound-inference compiler flag could be used to enabled the corresponding feature.
More information: https://youtrack.jetbrains.com/issue/KT-40804

@sdeleuze
Copy link
Contributor

sdeleuze commented Sep 7, 2021

Indeed seems to work based on my tests, thanks! I will close this issue when we will be based on Kotlin 1.6 in order to add proper test.

@petrukhnov Could you please confirm this will be the default as of Kotlin 1.6?

@petukhovv
Copy link

Yes, it's going to be enabled by default since 1.6.

@sdeleuze sdeleuze modified the milestones: 5.x, 6.0 M1 Oct 29, 2021
@sdeleuze sdeleuze self-assigned this Oct 29, 2021
@sdeleuze sdeleuze removed the status: blocked An issue that's blocked on an external project change label Oct 29, 2021
@sdeleuze
Copy link
Contributor

Depends on #27413.

@jhoeller jhoeller modified the milestones: 6.0 M1, 6.0.x Nov 16, 2021
@sdeleuze sdeleuze removed this from the 6.0.x milestone Dec 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module type: task A general task
Projects
None yet
Development

No branches or pull requests

9 participants