Maven dependency
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<version>4.9.0</version>
<scope>test</scope>
</dependency>
The test I've written
@SpringJUnitConfig(classes = {GithubApiService.class, WebClientConfiguration.class})
@EnableAutoConfiguration
public class GithubApiServiceTest {
@Test
public void testGithubResponseJsonToMapConversion(
@Autowired GithubApiService service,
@Value("classpath:github/commit-payload.json") Resource commitPayloadFile) throws IOException {
final String COMMITS_URL = "/repos/Codertocat/Hello-World/commits/sha";
//Stub response from Github Server
String responseJson = new ObjectMapper().writeValueAsString(
new String(Files.readAllBytes(Paths.get(commitPayloadFile.getFile().getAbsolutePath()))));
MockWebServer server = new MockWebServer();
server.enqueue(new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody(responseJson)
.setResponseCode(OK.value()));
server.start();
// Get mock server's URL
HttpUrl mockGithubUrl = server.url(COMMITS_URL);
//Call API Service
Map<String, Object> result = service.getCommitDetails(mockGithubUrl.toString()).block();
//Expect return type is hashmap
assertThat(result.get("sha")).isEqualTo("6dcb09b5b57875f334f61aebed695e2e4193db5e");
server.shutdown();
}
}
The class under test
@Service
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class GithubApiService {
@Autowired
private final WebClient webClient;
public Mono<Map<String, Object>> getCommitDetails(String commitsUrl) {
return webClient.get()
.uri(commitsUrl)
.httpRequest(httpRequest -> {
HttpClientRequest reactorRequest = httpRequest.getNativeRequest();
reactorRequest.responseTimeout(Duration.ofSeconds(2));
})
.accept(APPLICATION_JSON)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
});
}
}
I get this error when I run the test
java.lang.NoClassDefFoundError: okhttp3/internal/concurrent/TaskRunner$RealBackend
at okhttp3.mockwebserver.MockWebServer.<init>(MockWebServer.kt:101)
at com.digite.vcs.git.analytics.github.webhook.GithubApiServiceTest.testGithubResponseJsonToMapConversion(GithubApiServiceTest.java:37)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: java.lang.ClassNotFoundException: okhttp3.internal.concurrent.TaskRunner$RealBackend
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 67 more
When I browse on source TaskRunner on github I do see the TaskRunner class but not when I search for it from within my IDE. Am I missing something in the dependency declaration?
[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ git-analytics ---
[INFO] com.digite.vcs:git-analytics:jar:0.0.1-SNAPSHOT
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.4.1:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.4.1:compile
[INFO] | | +- org.springframework.boot:spring-boot:jar:2.4.1:compile
[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:2.4.1:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:2.4.1:compile
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.13.3:compile
[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.13.3:compile
[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:1.7.30:compile
[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.27:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:2.4.1:compile
[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.11.3:compile
[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.11.3:compile
[INFO] | | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.11.3:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.4.1:compile
[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.41:compile
[INFO] | | +- org.glassfish:jakarta.el:jar:3.0.3:compile
[INFO] | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.41:compile
[INFO] | +- org.springframework:spring-web:jar:5.3.2:compile
[INFO] | | \- org.springframework:spring-beans:jar:5.3.2:compile
[INFO] | \- org.springframework:spring-webmvc:jar:5.3.2:compile
[INFO] | +- org.springframework:spring-aop:jar:5.3.2:compile
[INFO] | +- org.springframework:spring-context:jar:5.3.2:compile
[INFO] | \- org.springframework:spring-expression:jar:5.3.2:compile
[INFO] +- org.springframework.boot:spring-boot-starter-webflux:jar:2.4.1:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-reactor-netty:jar:2.4.1:compile
[INFO] | | \- io.projectreactor.netty:reactor-netty-http:jar:1.0.2:compile
[INFO] | | +- io.netty:netty-codec-http:jar:4.1.55.Final:compile
[INFO] | | | +- io.netty:netty-common:jar:4.1.55.Final:compile
[INFO] | | | +- io.netty:netty-buffer:jar:4.1.55.Final:compile
[INFO] | | | +- io.netty:netty-transport:jar:4.1.55.Final:compile
[INFO] | | | +- io.netty:netty-codec:jar:4.1.55.Final:compile
[INFO] | | | \- io.netty:netty-handler:jar:4.1.55.Final:compile
[INFO] | | +- io.netty:netty-codec-http2:jar:4.1.55.Final:compile
[INFO] | | +- io.netty:netty-resolver-dns:jar:4.1.55.Final:compile
[INFO] | | | +- io.netty:netty-resolver:jar:4.1.55.Final:compile
[INFO] | | | \- io.netty:netty-codec-dns:jar:4.1.55.Final:compile
[INFO] | | +- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.55.Final:compile
[INFO] | | | \- io.netty:netty-transport-native-unix-common:jar:4.1.55.Final:compile
[INFO] | | \- io.projectreactor.netty:reactor-netty-core:jar:1.0.2:compile
[INFO] | | \- io.netty:netty-handler-proxy:jar:4.1.55.Final:compile
[INFO] | | \- io.netty:netty-codec-socks:jar:4.1.55.Final:compile
[INFO] | \- org.springframework:spring-webflux:jar:5.3.2:compile
[INFO] | \- io.projectreactor:reactor-core:jar:3.4.1:compile
[INFO] | \- org.reactivestreams:reactive-streams:jar:1.0.3:compile
[INFO] +- org.springframework.boot:spring-boot-starter-data-mongodb:jar:2.4.1:compile
[INFO] | +- org.mongodb:mongodb-driver-sync:jar:4.1.1:compile
[INFO] | | +- org.mongodb:bson:jar:4.1.1:compile
[INFO] | | \- org.mongodb:mongodb-driver-core:jar:4.1.1:compile
[INFO] | \- org.springframework.data:spring-data-mongodb:jar:3.1.2:compile
[INFO] | +- org.springframework:spring-tx:jar:5.3.2:compile
[INFO] | \- org.springframework.data:spring-data-commons:jar:2.4.2:compile
[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.11.3:compile
[INFO] | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.11.3:compile
[INFO] | \- com.fasterxml.jackson.core:jackson-core:jar:2.11.3:compile
[INFO] +- org.projectlombok:lombok:jar:1.18.16:compile (optional)
[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:2.4.1:test
[INFO] | +- org.springframework.boot:spring-boot-test:jar:2.4.1:test
[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:2.4.1:test
[INFO] | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.3:test
[INFO] | | \- jakarta.activation:jakarta.activation-api:jar:1.2.2:test
[INFO] | +- org.assertj:assertj-core:jar:3.18.1:test
[INFO] | +- org.hamcrest:hamcrest:jar:2.2:test
[INFO] | +- org.junit.jupiter:junit-jupiter:jar:5.7.0:test
[INFO] | | +- org.junit.jupiter:junit-jupiter-api:jar:5.7.0:test
[INFO] | | | +- org.apiguardian:apiguardian-api:jar:1.1.0:test
[INFO] | | | +- org.opentest4j:opentest4j:jar:1.2.0:test
[INFO] | | | \- org.junit.platform:junit-platform-commons:jar:1.7.0:test
[INFO] | | +- org.junit.jupiter:junit-jupiter-params:jar:5.7.0:test
[INFO] | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.7.0:test
[INFO] | | \- org.junit.platform:junit-platform-engine:jar:1.7.0:test
[INFO] | +- org.mockito:mockito-core:jar:3.6.28:test
[INFO] | | +- net.bytebuddy:byte-buddy:jar:1.10.18:test
[INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.10.18:test
[INFO] | | \- org.objenesis:objenesis:jar:3.1:test
[INFO] | +- org.mockito:mockito-junit-jupiter:jar:3.6.28:test
[INFO] | +- org.skyscreamer:jsonassert:jar:1.5.0:test
[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] | +- org.springframework:spring-core:jar:5.3.2:compile
[INFO] | | \- org.springframework:spring-jcl:jar:5.3.2:compile
[INFO] | +- org.springframework:spring-test:jar:5.3.2:test
[INFO] | \- org.xmlunit:xmlunit-core:jar:2.7.0:test
[INFO] +- de.flapdoodle.embed:de.flapdoodle.embed.mongo:jar:2.2.0:test
[INFO] | \- de.flapdoodle.embed:de.flapdoodle.embed.process:jar:2.1.2:test
[INFO] | +- org.apache.commons:commons-lang3:jar:3.11:test
[INFO] | +- net.java.dev.jna:jna:jar:4.0.0:test
[INFO] | +- net.java.dev.jna:jna-platform:jar:4.0.0:test
[INFO] | \- org.apache.commons:commons-compress:jar:1.18:test
[INFO] +- com.jayway.jsonpath:json-path:jar:2.4.0:test
[INFO] | +- net.minidev:json-smart:jar:2.3:test
[INFO] | | \- net.minidev:accessors-smart:jar:1.2:test
[INFO] | | \- org.ow2.asm:asm:jar:5.0.4:test
[INFO] | \- org.slf4j:slf4j-api:jar:1.7.30:compile
[INFO] \- com.squareup.okhttp3:mockwebserver:jar:4.9.0:test
[INFO] +- com.squareup.okhttp3:okhttp:jar:3.14.9:test
[INFO] | \- com.squareup.okio:okio:jar:1.17.2:test
[INFO] +- junit:junit:jar:4.13.1:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:2.2:test
[INFO] \- org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.4.21:test
[INFO] +- org.jetbrains.kotlin:kotlin-stdlib:jar:1.4.21:test
[INFO] | +- org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.4.21:test
[INFO] | \- org.jetbrains:annotations:jar:13.0:test
[INFO] \- org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.4.21:test
If you don't have a specific reason for a specific version, don't specify it in the POM
file and leave it for Maven to decide.
The version is set in the <dependencyManagement>
of the org.springframework.boot/spring-boot-dependencies
. It is set consistently with other related dependencies and there rarely is a legitimate reason to change it.
Then the versions of the transitive dependencies will not collide.
In your POM
this should be enough:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<scope>test</scope>
</dependency>
Originally I wrote this answer on 2021-09-29. This answer is not valid anymore, at least for mockwebserver
, although the general advice "if you don't have a specific reason for a specific version, leave it to the Spring Boot BOM" is still valid.
TL;DR: Spring Boot 3.4+ no longer manages mockwebserver
, you have to specify the version on your own.
Credit to @ThorstenSchöning for reminding this, it's an old post and I wouldn't otherwise remember to update it :)
spring-boot-dependencies-2.6.9.pom from 2022-06-23 contains
<properties>
<okhttp3.version>3.14.9</okhttp3.version>
</properties>
...
<dependencyManagement>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<dependencyManagement>
The next version spring-boot-dependencies-2.7.0.pom from 2022-05-23 changed it to
<properties>
<okhttp.version>4.9.3</okhttp.version>
</properties>
...
<dependencyManagement>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-bom</artifactId>
<version>${okhttp.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependencyManagement>
And in the version 3.4 from 2024-11-21 they completely removed the dependency:
OkHttp Dependency Management Removed
Spring Boot no longer depends on OkHttp so it no longer manages its version. If your application has OkHttp dependencies, update its build to use an OkHttp version that meets its needs.