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

冰箱

我正在尝试编写一个简单的服务器,它接收消息并将它们分发给注册的侦听器。我发现了ListenerList批注,它似乎非常适合消除样板代码。它就像一个魅力,所有的方法都按预期生成,监听器被调用。唯一的问题是,在一些调用之后,该fireXXX()方法停止工作并NoSuchMethodError抛出 a 。

GeneratedMethodAccessorstacktrace一部分让我怀疑某些东西被 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"
}
}

printAllMethods() 的输出。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)
安德烈斯·阿尔米雷

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

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

您可以在 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)
        }
    }
}

我的猜测是,当数组类型用作 fireXXX 方法的参数时,Groovy 方法选择机制中可能存在错误。它适用于非数组类型。我建议前往http://groovy-lang.org/mailing-lists.html并在报告 Groovy 问题跟踪器中的错误之前直接询问开发人员。

使用 Groovy 2.4.7 测试。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

生成PDF报告停止工作

来自分类Dev

Border Radius生成器无故停止工作

来自分类Dev

Groovy生成的类名

来自分类Dev

应用程序在视图中生成断开的链接(无故停止工作)

来自分类Dev

在Groovy中生成JSON对象

来自分类Dev

React的findNodeHandle方法停止工作

来自分类Dev

方法的jQuery选项停止工作

来自分类常见问题

从Map值生成的Groovy groupby List

来自分类Dev

Groovy @Grab生成java.lang.NoClassDefFoundError

来自分类Dev

从Map值生成的Groovy groupby List

来自分类Dev

OutputCache停止工作

来自分类Dev

HDCP停止工作

来自分类Dev

npm停止工作

来自分类Dev

InvalidateWindow()停止工作

来自分类Dev

SSL停止工作

来自分类Dev

Apache停止工作

来自分类Dev

通配符停止工作

来自分类Dev

袜子停止工作

来自分类Dev

XRDP停止工作!

来自分类Dev

POST令牌停止工作:我们如何生成将grant_type作为密码传递的令牌?超过401未经授权-invalid_grant

来自分类Dev

移动.jar时Java保存方法停止工作

来自分类Dev

在navigation() 方法网页在selenium 中停止工作后

来自分类Dev

身份验证方法已停止工作

来自分类Dev

MS Access 仅在更改特定方法时停止工作

来自分类Dev

Groovy:继承特征方法

来自分类Dev

Groovy歧义方法重载

来自分类Dev

Groovy:继承特征方法

来自分类Dev

NoSuchMethodError:eclipse中的eclipse.core.runtime.ListenerList错误

来自分类Dev

列出由Canonical和TupleConstructor生成的Groovy构造函数