2017-03-07 4 views
0

メッセージを受信して​​登録されたリスナーに配信する単純なサーバーを作成しようとしています。私はListenerListアノテーションを見つけました。これは定型的なコードを削除するのに完璧だと思われました。それは魅力的に機能し、すべてのメソッドが期待どおりに生成され、リスナーが呼び出されました。唯一の問題は、一部の呼び出し後にfireXXX()メソッドが機能しなくなり、NoSuchMethodErrorがスローされることです。Groovy @ListenerListで生成されたfireXXX()メソッドの動作が停止する

stacktraceの一部であるJVMによって最適化されたものが原因で問題が発生していると思われますが、これは私の知る限りです。私はGroovyをかなり新しくしているので、まだよく理解できていません。

問題が何であるか教えていただけますか? printAllMethodsの

リスナーインターフェース

package connector 

interface MessageListener { 
    void messageReceived(byte[] mess) 
} 

TCPConnectorクラス

package connector 

import groovy.beans.ListenerList 
import groovy.util.logging.Slf4j 

import java.nio.ByteBuffer 
import java.nio.channels.AsynchronousCloseException 
import java.nio.channels.ServerSocketChannel 
import java.nio.channels.SocketChannel 
import java.util.concurrent.* 

@Slf4j 
class TCPConnector { 

@ListenerList(name="StatusListener") 
List<TCPConnectorStatusListener> listeners 

String host 
Integer port 
BlockingQueue<byte[]> inQueue = new ArrayBlockingQueue<>(10) 
BlockingQueue<byte[]> outQueue = new ArrayBlockingQueue<>(10) 
ExecutorService senderExecutor 
Future sender 
ExecutorService receiverExecutor 
Future receiver 
ServerSocketChannel ssc 

TCPConnector(String host, Integer port) { 
    this.host = host 
    this.port = port 
} 

def start() { 
    ssc = ServerSocketChannel.open() 
    def address = new InetSocketAddress(host, port) 
    ssc.bind(address) 

    log.info("Accepting on $host:$port - $address") 
    try { 
     SocketChannel sc = ssc.accept() 
     log.info("Accepted connection from $sc") 
     startThreads(sc) 
     fireConnectionUp() 
    } catch (AsynchronousCloseException ace) { 
     log.info("ace - shutdown ${ace.getMessage()}") 
    } 
} 

private void startThreads(sc) { 
    def senderThread = { 
     log.info "Poller start" 
     try { 
      while (sc.isConnected()) { 
       def taken = outQueue.take() 
       log.info "poller ${taken}" 
       def wr = ByteBuffer.allocate(taken.size()) 
       wr.put(taken) 
       wr.flip() 
       sc.write(wr) 
      } 
     } catch (InterruptedException ie) { 
      log.info("interrupt $ie") 
      throw ie 
     } catch (Exception ex) { 
      log.error(ex.getMessage()) 
      stop() 
      throw ex 
     } 
    } as Runnable 
    senderExecutor = Executors.newSingleThreadExecutor({ Runnable r -> new Thread(r, "Sender-$sc") } as ThreadFactory) 
    sender = senderExecutor.submit(senderThread) 

    def receiverThread = { 
     try { 
      ByteBuffer receiver = ByteBuffer.allocate(16384) 
      int rec 
      while ((rec = sc.read(receiver)) != -1) { 
       log.info "received $rec $sc" 
       receiver.flip() 
       byte[] readed = new byte[receiver.remaining()] 
       receiver.get(readed) 
       inQueue.offer(readed) 
       receiver.clear() 
      } 
      log.info("minusone") 
      stop() 
     } catch (Exception ex) { 
      log.error(ex.getMessage()) 
      throw ex 
     } finally { 
      try { 
       log.info("finally stop") 
       stop() 
      } catch (Exception ex) { 
       log.error("ex while stop ${ex.getMessage()}") 
       throw ex 
      } 
     } 
    } 
    receiverExecutor = Executors.newSingleThreadExecutor(
      { Runnable r -> new Thread(r, "Receiver-$sc") } as ThreadFactory) 
    receiver = receiverExecutor.submit(receiverThread) 
} 

def stop() { 
    if (sender != null) { 
     sender.cancel(true) 
     receiver.cancel(true) 
     senderExecutor.shutdown() 
     receiverExecutor.shutdown() 
     fireConnectionDown() 
    } 
    ssc.close() 
    log.info("stopped") 
} 

static void main(String[] args) { 
    new TCPConnector("192.168.0.1", 1234) 
} 
} 

コネクタクラス

package connector 

import groovy.beans.ListenerList 
import groovy.util.logging.Slf4j 

@Slf4j 
class Connector implements TCPConnectorStatusListener { 

@ListenerList(name="MessageListener") 
List<MessageListener> listenerList 

TCPConnector tcpconn 
Thread ConnThread 

Connector(String host, Integer port) { 
    tcpconn = new TCPConnector(host, port) 
    tcpconn.addStatusListener((TCPConnectorStatusListener) this) 
} 

def start() { 
    tcpconn.start() 
} 

@Override 
void connectionUp() { 
    log.info("Connection up") 
    def recvMessage = { 
     try { 
      while (!Thread.currentThread().isInterrupted()) { 
       def mess = tcpconn.inQueue.take() 
       log.info(" $mess") 
       try { 
        printAllMethods(this) 
        this.fireMessageReceived(mess) 
       } catch (NoSuchMethodError nsme) { 
        log.error("WHY????", nsme) 
        nsme.printStackTrace() 
       } 
      } 
     } catch (Exception ex) { 
      log.error(ex.getMessage()) 
      throw ex 
     } 
    } 
    ConnThread = new Thread(recvMessage, "Conn-${tcpconn.host}:${tcpconn.port}") 
    ConnThread.setUncaughtExceptionHandler({t, e -> 
     log.error(e.getMessage()) 
     e.printStackTrace() 
    }) 
    ConnThread.start() 
} 

@Override 
void connectionDown() { 
    log.info("Connection down") 
    ConnThread.interrupt() 
} 

static void printAllMethods(obj){ 
    if(!obj){ 
     println("Object is null\r\n"); 
     return; 
    } 
    if(!obj.metaClass && obj.getClass()){ 
     printAllMethods(obj.getClass()); 
     return; 
    } 
    def str = "class ${obj.getClass().name} functions:\r\n"; 
    obj.metaClass.methods.name.unique().each{ 
     str += it+"(" 
     obj.metaClass.methods.find {m -> it == m.name}.each {mm -> str += mm.parameterTypes} 
     str += "); " 
    } 
    println "${str}\r\n" 
} 
} 

出力()。 fireXXX()が動作しているときとそうでないときは同じです。

class connector.Connector functions: 
equals([class java.lang.Object]boolean); getClass([]class java.lang.Class); hashCode([]int); notify([]void); notifyAll([]void); toString([]class java.lang.String); wait([]void); addMessageListener([interface connector.MessageListener]void); connectionDown([]void); connectionUp([]void); fireMessageReceived([class [B]void); getListenerList([]interface java.util.List); getMessageListeners([]class [Lconnector.MessageListener;); getMetaClass([]interface groovy.lang.MetaClass); getProperty([class java.lang.String]class java.lang.Object); getConnThread([]class java.lang.Thread); getTcpconn([]class connector.TCPConnector); invokeMethod([class java.lang.String, class java.lang.Object]class java.lang.Object); printAllMethods([class java.lang.Object]void); removeMessageListener([interface connector.MessageListener]void); setListenerList([interface java.util.List]void); setMetaClass([interface groovy.lang.MetaClass]void); setProperty([class java.lang.String, class java.lang.Object]void); setConnThread([class java.lang.Thread]void); setTcpconn([class connector.TCPConnector]void); start([]class java.lang.Object); 

私は小さいバージョンにサンプルコードを凝縮しました

12:25:12.544 [Conn-192.168.0.1:5555] ERROR connector.Connector - WHY???? 
java.lang.NoSuchMethodError: connector.Connector.fireMessageReceived([B)V 
    at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) 
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1218) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027) 
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:166) 
    at connector.Connector$_connectionUp_closure1.doCall(Connector.groovy:34) 
    at connector.Connector$_connectionUp_closure1.doCall(Connector.groovy) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) 
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325) 
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027) 
    at groovy.lang.Closure.call(Closure.java:414) 
    at groovy.lang.Closure.call(Closure.java:408) 
    at groovy.lang.Closure.run(Closure.java:495) 
    at java.lang.Thread.run(Thread.java:745) 
java.lang.NoSuchMethodError: connector.Connector.fireMessageReceived([B)V 
    at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) 
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1218) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027) 
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:166) 
    at connector.Connector$_connectionUp_closure1.doCall(Connector.groovy:34) 
    at connector.Connector$_connectionUp_closure1.doCall(Connector.groovy) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) 
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325) 
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027) 
    at groovy.lang.Closure.call(Closure.java:414) 
    at groovy.lang.Closure.call(Closure.java:408) 
    at groovy.lang.Closure.run(Closure.java:495) 
    at java.lang.Thread.run(Thread.java:745) 
+0

https://issues.apache.org/jira/browse/GROOVY-8110で解決されました – frigo

答えて

0

例外。このコードを実行する

import groovy.beans.ListenerList 

interface MessageListener { 
    void messageReceived(byte[] msg) 
} 

class MessageProducer { 
    @ListenerList 
    List<MessageListener> listeners 

    void produce(String msg) { 
    fireMessageReceived(msg.getBytes()) 
    } 
} 

producer = new MessageProducer() 
producer.addMessageListener({ println it } as MessageListener) 
producer.produce('Groovy') 

がエラー

java.lang.NoSuchMethodError: MessageProducer.fireMessageReceived([B)V 

を再現groovyコンソール内でそれを実行しているときは、生成されたコードを検査することができます(スクリプトメニュー - > ASTを点検して)、次のメソッドを持つMessageProducerクラスが得られ

public void fireMessageReceived([B msg) { 
    if (listeners != null) { 
     java.util.ArrayList<E extends java.lang.Object> __list = new java.util.ArrayList<MessageListener>(listeners) 
     for (java.lang.Object listener : __list) { 
      listener.messageReceived(msg) 
     } 
    } 
} 

私の推測では、アレイタイプは、火災のためのパラメータとして使用される場合グルービー方法選択機構にバグがあるかもしれないことですXXXメソッド。これは、非配列型ではうまく動作します。私はhttp://groovy-lang.org/mailing-lists.htmlに向かい、Groovyの問題トラッカーのバグを報告する前に開発者に直接お尋ねします。

Groovy 2.4.7でテスト済みです。

+0

ありがとうございました! groovyConsoleを使った素晴らしいヒントメーリングリストに向かい、知り合いに尋ねます。 – frigo

関連する問題