Skip to content

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

Description

@hjyun328

이슈

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;

참고

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions