naver / naver/arcus-java-client

Java 9 미만 환경에서 java.lang.NoSuchMethodError 발생

Open
#340 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

deferred
Dominant language
Java
Stars
56
Forks
49
Avg merge
2d 21h
Merged PRs (30d)
5

Description

이슈

arcus-java-client는 최소 Java 6 이상 버전을 지원한다. 하지만 Java 9 미만 환경에서 TCPMemcachedNodeImpl 클래스의 생성자 호출 시 아래와 같은 ByteBuffer.clear() 메소드의 NoSuchMethodError 현상이 발생한다.

java.lang.NoSuchMethodError: java.nio.ByteBuffer.clear()Ljava/nio/ByteBuffer;
	at net.spy.memcached.protocol.TCPMemcachedNodeImpl.<init>(TCPMemcachedNodeImpl.java:147) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.protocol.ascii.AsciiMemcachedNodeImpl.<init>(AsciiMemcachedNodeImpl.java:23) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.DefaultConnectionFactory.createMemcachedNode(DefaultConnectionFactory.java:220) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.MemcachedConnection.attachMemcachedNode(MemcachedConnection.java:542) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.MemcachedConnection.<init>(MemcachedConnection.java:131) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.DefaultConnectionFactory.createConnection(DefaultConnectionFactory.java:243) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.ConnectionFactoryBuilder$1.createConnection(ConnectionFactoryBuilder.java:444) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.MemcachedClient.<init>(MemcachedClient.java:223) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.plugin.FrontCacheMemcachedClient.<init>(FrontCacheMemcachedClient.java:53) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.ArcusClient.<init>(ArcusClient.java:326) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.ArcusClient.getInstance(ArcusClient.java:313) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.CacheManager.createArcusClient(CacheManager.java:432) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.CacheManager.commandCacheListChange(CacheManager.java:375) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at net.spy.memcached.CacheMonitor.processResult(CacheMonitor.java:103) ~[arcus-java-client-9.9.9.jar:9.9.9]
	at org.apache.zookeeper.ClientCnxn$EventThread.processEvent(ClientCnxn.java:592) [zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]
	at org.apache.zookeeper.ClientCnxn$EventThread.run(ClientCnxn.java:508) [zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]

원인

Java 9부터 ByteBuffer의 일부 메소드가 Override 되었다. Override 된 메소드는 리턴 타입이 Buffer에서 ByteBuffer로 변경되었다.

변경된 메소드는 아래와 같다.

  • position(int newPosition)
  • limit(int newLimit)
  • flip()
  • clear()
  • mark()
  • reset()
  • rewind()

Java 9 미만

public abstract class ByteBuffer extends Buffer {
   // clear 메소드는 Buffer에 의해 상속됨
}
​
public abstract class Buffer {
  ...
  public Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
  }
  ...
}

Java 9 이상

public abstract class ByteBuffer extends Buffer {
   ...
   ByteBuffer clear() {
       super.clear();
       return this;
   }
   ...
}

Java 9 이상의 환경에서 arcus-java-client를 배포(source 1.6, target 1.6 설정으로 빌드)하면 ByteBuffer.clear() 메소드 호출의 바이트 코드는 아래와 같이 Java 9 기준으로 생성된다.

$ javap -c TCPMemachedNodeImpl
... (생략) ...
288: invokevirtual #50                 // Method java/nio/ByteBuffer.clear:()Ljava/nio/ByteBuffer;
... (생략) ...

Java 9 미만 환경에서 ByteBuffer 클래스는 Buffer 클래스로부터 상속받은 Buffer.clear()라는 메소드는 존재하지만, ByteBuffer.clear() 라는 메소드는 존재하지 않는다. 따라서 Java 9 이상 환경에서 빌드된 arcus-java-client를 Java 9 미만에서 사용할 경우 메소드의 Signature를 찾을 수 없어 NoSuchMethodError가 발생한 것이다.

참고로 Java 9 미만 환경에서 arcus-java-client를 배포하면, ByteBuffer.clear() 메소드 호출의 바이트 코드는 아래와 같이 생성된다.

$ javap -c TCPMemachedNodeImpl
... (생략) ...
288: invokevirtual #50                 // Method java/nio/Buffer.clear:()Ljava/nio/Buffer;
... (생략) ...

해결 방법

해결 방법은 3가지다.

  1. Java 9 미만 환경에서 빌드한다.

  2. --release 옵션을 사용하여 빌드하여, 해당 버전을 기준으로 바이트코드를 생성한다. 이 옵션으로 빌드하려면 Java 9 이상의 환경을 요구한다.

<properties>
     <maven.compiler.release>6</maven.compiler.release>
</properties>

or

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
    <configuration>
        <release>6</release>
    </configuration>
</plugin>
  1. Buffer로 타입 캐스팅하여, Buffer의 clear 메소드를 호출하도록 바이트 코드 변경을 유도한다.
Buffer buffer = ByteBuffer.allocate(1024);
buffer.clear();                    // Method java/nio/Buffer.clear:()Ljava/nio/Buffer;                  

((Buffer) buffer).clear();     // Method java/nio/Buffer.clear:()Ljava/nio/Buffer;

참고

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at src/main/java/net/spy/memcached/protocol/TCPMemcachedNodeImpl.java:147 and inspect the Maven compiler configuration and generated bytecode. Reproduce the build on Java 9 or later, verify the resulting call signature, and test the artifact on a pre-Java 9 runtime; done means the client no longer raises NoSuchMethodError while preserving the stated Java 6 compatibility.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.