Java Groovy@ListenerList生成的fireXXX()方法停止工作

Java Groovy@ListenerList生成的fireXXX()方法停止工作,java,groovy,Java,Groovy,我正在尝试编写一个简单的服务器,它接收消息并将它们分发给注册的侦听器。我找到了注释,它似乎完美地消除了样板代码。它就像一个符咒,所有的方法都按预期生成,侦听器被调用。唯一的问题是在一些调用之后,fireXXX()方法停止工作,并抛出一个NoSuchMethodError stacktrace的GeneratedMethodAccessor部分让我怀疑JVM优化了某些东西,这是问题的原因,但据我所知,这就是问题的原因。我是Groovy的新手,所以我也不太熟悉引擎盖下发生的事情 有人能告诉我问题出在

我正在尝试编写一个简单的服务器,它接收消息并将它们分发给注册的侦听器。我找到了注释,它似乎完美地消除了样板代码。它就像一个符咒,所有的方法都按预期生成,侦听器被调用。唯一的问题是在一些调用之后,
fireXXX()
方法停止工作,并抛出一个
NoSuchMethodError

stacktrace的
GeneratedMethodAccessor
部分让我怀疑JVM优化了某些东西,这是问题的原因,但据我所知,这就是问题的原因。我是Groovy的新手,所以我也不太熟悉引擎盖下发生的事情

有人能告诉我问题出在哪里吗

侦听器接口

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"
}
}
例外情况

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)

我已将示例代码压缩为一个较小的版本

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')
您可以在GroovyConsole中运行生成的代码(脚本菜单->检查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)
        }
    }
}
public void fireMessageReceived([B msg){
if(侦听器!=null){
java.util.ArrayList\uuu list=新建java.util.ArrayList(侦听器)
for(java.lang.Object侦听器:\列表){
listener.messageReceived(msg)
}
}
}
我的猜测是,当数组类型用作fireXXX方法的参数时,Groovy方法选择机制中可能存在一个bug。它与非数组类型的情况非常好。我建议在Groovy的问题跟踪器中报告bug之前,直接去问开发人员


使用Groovy 2.4.7进行测试。

谢谢!groovyConsole的好提示。将转到邮件列表并询问了解者。已在中解决
java.lang.NoSuchMethodError: MessageProducer.fireMessageReceived([B)V
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)
        }
    }
}