I need to use WebClient on an existing Spring project. The existing Spring version is 4. I updated the Spring version to 5 because to use WebClient, Spring 5 is required.

Below are the spring dependencies in pom.xml:

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.2.4-1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webflux</artifactId>
            <version>5.2.15.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>io.projectreactor.netty</groupId>
            <artifactId>reactor-netty</artifactId>
            <version>0.9.20.RELEASE</version>
            <scope>compile</scope>
        </dependency>

added : spring-web, spring-webflux and reactor-netty.

Next, I configured WebClient bean in AppConfig

@Bean
  public WebClient webClient(@Value("${myservice.endpoint}") String countryServiceUrl, ClientHttpConnector connector) {
    return WebClient.builder()
            .baseUrl(countryServiceUrl)
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
            .clientConnector(connector)
            .build();
  }

Below is the project setup:

public class WebAppInitializer implements WebApplicationInitializer {
private AnnotationConfigWebApplicationContext applicationContext;
@Override
  public void onStartup(final ServletContext servletContext) throws ServletException {
    applicationContext = new AnnotationConfigWebApplicationContext();
    applicationContext.register(AppConfig.class);
    applicationContext.setDisplayName(DISPLAY_NAME);

    // Manage the life cycle of the root application context
    servletContext.addListener(new ContextLoaderListener(applicationContext));

    applicationContext.refresh();
    applicationContext.registerShutdownHook();
  }
}

I am deploying the project to tomcat 9 in my local. Below is the error:

WARN  AnnotationConfigWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'createMyMessageConverter': Unsatisfied dependency expressed through field 'myMessageConverter'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myMessageConverter': Unsatisfied dependency expressed through field ‘myServiceCaller'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘myServiceCaller': Unsatisfied dependency expressed through field ‘someDAO'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘someDAOImpl': Unsatisfied dependency expressed through field 'webClient'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webClient' defined in com.my.package.config.AppConfig: Unsatisfied dependency expressed through method 'webClient' parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.http.client.reactive.ClientHttpConnector' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
06-Oct-2023 07:37:23.262 SEVERE [main] org.apache.catalina.startup.HostConfig.deployWAR Error deploying web application archive [/Users/abhinash.kumar/Downloads/apache-tomcat-9.0.65/webapps/myApp-SNAPSHOT.war]
    java.lang.IllegalStateException: Error starting child
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:729)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:698)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:696)
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1024)
        at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1911)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
        at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:825)
        at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:475)
        at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1618)
        at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:319)
        at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123)
        at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:423)
        at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:366)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:946)
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:835)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1396)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1386)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:919)
        at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:265)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardService.startInternal(StandardService.java:432)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.startup.Catalina.start(Catalina.java:772)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476)
    Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/myApp-SNAPSHOT]]
        at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:198)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:726)
        ... 37 more
    Caused by: java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationUtils.clearCache()V
        at org.springframework.context.support.AbstractApplicationContext.resetCommonCaches(AbstractApplicationContext.java:915)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:575)
        at com.choicehotels.bs.ecb.accountmsgadapter.travelagentadapter.web.WebAppInitializer.onStartup(WebAppInitializer.java:37)
        at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:172)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5219)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        ... 38 more

So, basically, this part seems to be the issue: Unsatisfied dependency expressed through method 'webClient' parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.http.client.reactive.ClientHttpConnector' available:

But, I do see ClientHttpConnector present in the project classpath. image added

enter image description here

Thanks in advance!

1

There are 1 best solutions below

3
On BEST ANSWER

it seems that you are not initializing the connector, as you can see from the official spring documentation you need the connector instatiated before plug in the builder (a direct dependency injection of spring for the connector does not seem advisable):

@Bean
public JettyResourceFactory resourceFactory() {
    return new JettyResourceFactory();
}

    @Bean
public WebClient webClient() {

    HttpClient httpClient = new HttpClient();
    // Further customizations...

    ClientHttpConnector connector =
            new JettyClientHttpConnector(httpClient, resourceFactory()); 

    return WebClient.builder().clientConnector(connector).build(); 
}

here you can find the documentation: Client-builder

I hope it was helpful to you.