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

Upgrading incompatible issue: NoSuchFieldError: Companion #5378

Closed
SElab2019 opened this issue Aug 17, 2019 · 6 comments
Closed

Upgrading incompatible issue: NoSuchFieldError: Companion #5378

SElab2019 opened this issue Aug 17, 2019 · 6 comments
Labels
needs info More information needed from reporter

Comments

@SElab2019
Copy link

Hi,

The following code snippets throw an incompatible issue when I try to upgrade okhttp from 3.10.0 to 4.1.0.

import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.notNull;
import static org.mockito.BDDMockito.then;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import org.assertj.core.api.Assertions;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class TestRxWebSocket {

  private static final String TEST_MESSAGE = "test message";
  private static final String TEST_WS_URL = "wss://test.url/";

  @Mock private OkHttpClient mockClient;

  @Mock private WebSocket mockWebSocket;

  private ArgumentCaptor<WebSocketListener> listenerCaptor;

  private RxWebSocket subject;

  @BeforeMethod
  public void mockito() {
    MockitoAnnotations.initMocks(this);
  }

  @BeforeMethod
  public void setupSubject() {
    MockitoAnnotations.initMocks(this);

    subject = new RxWebSocket(mockClient);

    listenerCaptor = ArgumentCaptor.forClass(WebSocketListener.class);

    given(mockClient.newWebSocket(notNull(), listenerCaptor.capture())).willReturn(mockWebSocket);
  }

  private WebSocketListener getListener() {
    return listenerCaptor.getValue();
  }

  @Test
  public void connect_shouldConnectToUrl() {
    ArgumentCaptor<Request> request = ArgumentCaptor.forClass(Request.class);

    given(mockClient.newWebSocket(request.capture(), notNull())).willReturn(null);

    subject.connect(TEST_WS_URL).subscribe();

    Assertions.assertThat(request.getValue().url().toString()).isEqualTo("https://test.url/");
  }

  @Test
  public void send_whenBeforeConnect_shouldThrowNullPointerException() {
    subject.send(TEST_MESSAGE).test().assertError(NullPointerException.class);
  }


}

The mockito version is 2.16.0. It works well before. After upgrading, it throws an error:

[ERROR] mockito(com.github.princesslana.eriscasper.rx.websocket.TestRxWebSocket)  Time elapsed: 1.801 s  <<< FAILURE!
java.lang.NoSuchFieldError: Companion
	at okhttp3.internal.Util.<clinit>(Util.kt:69)
	at okhttp3.OkHttpClient.<clinit>(OkHttpClient.kt:959)
	at sun.reflect.GeneratedSerializationConstructorAccessor1.newInstance(Unknown Source)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
	at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
	at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:19)
	at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.createMock(InlineByteBuddyMockMaker.java:185)
	at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)
	at org.mockito.internal.MockitoCore.mock(MockitoCore.java:65)
	at org.mockito.Mockito.mock(Mockito.java:1864)
	at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:36)
	at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:16)
	at org.mockito.internal.configuration.IndependentAnnotationEngine.createMockFor(IndependentAnnotationEngine.java:38)
	at org.mockito.internal.configuration.IndependentAnnotationEngine.process(IndependentAnnotationEngine.java:62)
	at org.mockito.internal.configuration.InjectingAnnotationEngine.processIndependentAnnotations(InjectingAnnotationEngine.java:57)
	at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:41)
	at org.mockito.MockitoAnnotations.initMocks(MockitoAnnotations.java:69)
	at com.github.princesslana.eriscasper.rx.websocket.TestRxWebSocket.mockito(TestRxWebSocket.java:36)
	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.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124)
	at org.testng.internal.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:59)
	at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:455)
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:222)
	at org.testng.internal.Invoker.invokeMethod(Invoker.java:520)
	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:716)
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:988)
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
	at org.testng.TestRunner.privateRun(TestRunner.java:648)
	at org.testng.TestRunner.run(TestRunner.java:505)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
	at org.testng.SuiteRunner.run(SuiteRunner.java:364)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
	at org.testng.TestNG.runSuites(TestNG.java:1049)
	at org.testng.TestNG.run(TestNG.java:1017)
	at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:135)
	at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeSingleClass(TestNGDirectoryTestSuite.java:112)
	at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:99)
	at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:146)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:373)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:334)
	at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:119)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:407)
@SElab2019 SElab2019 added the bug Bug in existing code label Aug 17, 2019
@swankjesse
Copy link
Collaborator

Are you using the same versions for all your OkHttp and MockWebServer libraries? They must be in sync.

@yschimke yschimke added the needs info More information needed from reporter label Aug 18, 2019
@yschimke yschimke changed the title Upgrading incompatible issue Upgrading incompatible issue: NoSuchFieldError: Companion Aug 18, 2019
@JakeWharton JakeWharton removed the bug Bug in existing code label Aug 19, 2019
@dvdmunckhof
Copy link

I just had the same issue with OkHttp 4.x when upgrading from 3.x. We're not using MockWebServer or any other 'extensions', just OkHttp, so mismatching versions was not the case.

Exception in thread "main" java.lang.NoSuchFieldError: Companion
	at okhttp3.internal.Util.<clinit>(Util.kt:69)
	at okhttp3.internal.connection.RealConnectionPool.<clinit>(RealConnectionPool.kt:263)
	at okhttp3.ConnectionPool.<init>(ConnectionPool.kt:37)
	at okhttp3.ConnectionPool.<init>(ConnectionPool.kt:39)
	at okhttp3.OkHttpClient$Builder.<init>(OkHttpClient.kt:438)
	at [redacted]

Eventually I found the cause. Our dependency tree (simplified and stripped):

project :main
+--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.41
|    +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.41
|    |    +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.41
|    |    \--- org.jetbrains:annotations:13.0
|    \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.41
|         \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.41
+--- project :subproject
|    \--- com.squareup.okhttp3:okhttp:4.1.0
|         +--- com.squareup.okio:okio:2.2.2
|         \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.41
\--- com.squareup.moshi:moshi:1.8.0
     \--- com.squareup.okio:okio:1.16.0

Moshi depends on Okio 1.16.0, while OkHttp depends on Okio 2.2.2. This resulted in both okio 1.x and 2.x being added to the classpath. Forcing Okio to 2.x in the :main solved this issue.

@JakeWharton
Copy link
Collaborator

This resulted in both okio 1.x and 2.x being added to the classpath.

This sounds like a fairly severe Gradle bug if this truly is the result. The presence of a 2.x should replace the use of 1.x given they have the same Maven coordinates. You should see something like

     \--- com.squareup.okio:okio:1.16.0 -> 2.2.2

@dvdmunckhof
Copy link

dvdmunckhof commented Aug 21, 2019

I ran into the issue when running a Main class from IntelliJ, I'm not sure if this issue is related to IntelliJ or Gradle. I'm not a Gradle expert, but I think Gradle does report the right dependencies on the classpath:

Output of gradlew main:dependencies --configuration runtimeClasspath:

------------------------------------------------------------
Project :main
------------------------------------------------------------

runtimeClasspath - Runtime classpath of compilation 'main' (target  (jvm)).
+--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.41
|    +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.41
|    |    +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.41
|    |    \--- org.jetbrains:annotations:13.0
|    \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.41
|         \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.41 (*)
+--- project :subproject
|    +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.41 (*)
|    +--- com.squareup.okhttp3:okhttp:4.1.0
|    |    +--- com.squareup.okio:okio:2.2.2
|    |    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.2.60 -> 1.3.41 (*)
|    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.41 (*)
|    \--- com.squareup.moshi:moshi:1.8.0
|         \--- com.squareup.okio:okio:1.16.0 -> 2.2.2 (*)
\--- com.squareup.moshi:moshi:1.8.0 (*)

(*) - dependencies omitted (listed previously)

Output of gradlew main:dependencies --configuration compileClasspath:

------------------------------------------------------------
Project :main
------------------------------------------------------------

compileClasspath - Compile classpath for compilation 'main' (target  (jvm)).
+--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.41
|    +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.41
|    |    +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.41
|    |    \--- org.jetbrains:annotations:13.0
|    \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.41
|         \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.41 (*)
+--- project :subproject
\--- com.squareup.moshi:moshi:1.8.0
     \--- com.squareup.okio:okio:1.16.0

(*) - dependencies omitted (listed previously)

Again, both logs are simplified and stripped. I could provide detailed information privately if interested. We're using Gradle 5.6.

@JakeWharton
Copy link
Collaborator

Ok so those actually indicate that there are not two Okios on the classpath and that Gradle is doing the correct thing by upgrading the 1.x dependency to 2.x for the runtime classpath.

@dvdmunckhof
Copy link

That's what I thought, it looks like IntelliJ is wrong. Thanks for looking into it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs info More information needed from reporter
Projects
None yet
Development

No branches or pull requests

5 participants