Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java系统类中的日志方法调用_Java_Aop_Aspectj_Powermock_Jmockit - Fatal编程技术网

Java系统类中的日志方法调用

Java系统类中的日志方法调用,java,aop,aspectj,powermock,jmockit,Java,Aop,Aspectj,Powermock,Jmockit,我正在寻找一种方法来记录对java.nio.ByteBuffer中所有方法的调用 我只想知道调用了哪些方法 这在JMockit中是可能的,但是在版本1.47中,一些非常明智的人决定取消对私有方法的支持&版本1.46在JDK9和更高版本中工作得不太好 有人能推荐一种工具吗?它不一定需要是一个单元测试框架,但它应该在Eclipse中工作 我需要至少支持JDK 11,最好是JDK 13 下面是与JMockit 1.46和JDK 1.8一起使用的代码: import java.nio.ByteBuffe

我正在寻找一种方法来记录对java.nio.ByteBuffer中所有方法的调用

我只想知道调用了哪些方法

这在JMockit中是可能的,但是在版本1.47中,一些非常明智的人决定取消对私有方法的支持&版本1.46在JDK9和更高版本中工作得不太好

有人能推荐一种工具吗?它不一定需要是一个单元测试框架,但它应该在Eclipse中工作

我需要至少支持JDK 11,最好是JDK 13

下面是与JMockit 1.46和JDK 1.8一起使用的代码:

import java.nio.ByteBuffer;
import org.junit.Test;
import org.slf4j.*;
import mockit.*;

public class TestFakeByteBufferAdvice {

    private static final Logger LOG = LoggerFactory.getLogger(TestFakeByteBufferAdvice.class);

    public static final class FakeByteBuffer extends MockUp<ByteBuffer> {
        @Mock
        public Object $advice(Invocation invocation) {
            LOG.info("$advice.....: {} {}", invocation.getInvokedMember(), invocation);

            return invocation.proceed();
        }
    }

    @Test
    public void getFakeByteBuffer() {

        final ByteBuffer real  = ByteBuffer.wrap("abc".getBytes());
        LOG.info("Real........: {} {}", real, real.array());

        LOG.info("MockUp......: {}",    new FakeByteBuffer());

        final ByteBuffer fake  = ByteBuffer.wrap("def".getBytes());
        LOG.info("Fake........: {} {}", fake, fake.array());
    }
}

如果这是为了学习或分析,为什么不使用调试器呢?我将向您展示IntelliJ IDEA中的一个示例:

在主要方法或测试的某个地方给出以下代码:

final ByteBuffer real=ByteBuffer.wrapabc.getBytes; LOG.infoReal…….:{}{},real,real.array; 在调试器中定义方法断点时,如下所示:

定义其属性(如此断点)不会挂起正在运行的程序,但也可以记录方法条目、其他筛选条件和日志信息:

然后,您会看到这样一个控制台日志缩短,因为它相当长:

已连接到目标VM,地址:'127.0.0.1:54734',传输:'socket' 在java.nio.ByteBuffer.allocateByteBuffer.java:333输入的方法“java.nio.ByteBuffer.allocate” 方法“java.nio.ByteBuffer.”在java.nio.ByteBuffer.ByteBuffer.java:281处输入 方法“java.nio.ByteBuffer.hasArray”在java.nio.ByteBuffer.hasaraybytebuffer.java:970处输入 在java.nio.ByteBuffer.arrayByteBuffer.java:993处输入的方法“java.nio.ByteBuffer.array” 方法“java.nio.ByteBuffer.arrayOffset”在java.nio.ByteBuffer.arrayOffsetByteBuffer.java:1021处输入 ... 方法“java.nio.ByteBuffer.wrap”在java.nio.ByteBuffer.wrapByteBuffer.java:396处输入 方法“java.nio.ByteBuffer.wrap”在java.nio.ByteBuffer.wrapByteBuffer.java:373处输入 方法“java.nio.ByteBuffer.”在java.nio.ByteBuffer.ByteBuffer.java:281处输入 在java.nio.ByteBuffer.arrayByteBuffer.java:993处输入的方法“java.nio.ByteBuffer.array” 在java.nio.ByteBuffer.toStringByteBuffer.java:1085处输入的方法“java.nio.ByteBuffer.toString” 08:23:16.943[main]INFO d.s.s.q.TestFakeByteBufferAdvice-Real……:java.nio.HeapByteBuffer[pos=0 lim=3 cap=3][97,98,99] 方法“java.nio.ByteBuffer.hasArray”在java.nio.ByteBuffer.hasaraybytebuffer.java:970处输入 在java.nio.ByteBuffer.arrayByteBuffer.java:993处输入的方法“java.nio.ByteBuffer.array” ... 方法“java.nio.ByteBuffer.arrayOffset”在java.nio.ByteBuffer.arrayOffsetByteBuffer.java:1021处输入 在java.nio.ByteBuffer.arrayByteBuffer.java:993处输入的方法“java.nio.ByteBuffer.array” 方法“java.nio.ByteBuffer.arrayOffset”在java.nio.ByteBuffer.arrayOffsetByteBuffer.java:1021处输入 已断开与目标VM的连接,地址:'127.0.0.1:54734',传输:'socket' 进程已完成,退出代码为0 使用断点选项并找到一个最有帮助的设置。例如,您可以过滤掉某些不感兴趣的方法,或者指定其他条件,计算表达式并记录它们,或者任何您想到的方法

更新2020-05-17:JetBrains花了几周时间才做出反应,但他们同意改进文档并修复一个bug:


嗯,我设法找到了解决办法

首先,JMockit不能很好地与JDK13配合使用,所以我将jdk13http客户机向后移植到JDK8。这是一个邪恶的黑客,但对于我的测试用例来说已经足够了

然后我使用了一个稍旧的JMockit版本1.46,因为一些喜剧演员认为不应该允许任何人用私有方法伪造类

然后,我将要跟踪的对象存储在一个列表中,这样就可以通过identity==比较从日志记录中排除不需要的对象

尽管如此,JMockit可能会在下面的示例中的某些方法上崩溃,我已经注释掉了它们,所以在异常发生后禁止日志记录是一个好主意。 我已经向JMockit的人报告了这一点:

类似地,在构造测试用例以降低输出量的同时抑制日志记录也是有意义的。我用了一个原子布尔值

尽管如此,跟踪并没有完全解决问题,但加入Stacktrace让我找到了解决方案:以下调用链正在读取我的ByteBuffers: sun.nio.ch.writeByteBuffer[]srcs,int偏移量,int长度 sun.nio.ch.writeFileDescriptor fd,ByteBuffer src,多头仓位,本地发货人nd java.nio.DirectByteBuffer.putByteBuffer src

导演用了一些巧妙的技巧来朗读我的作品

该解决方案只适用于我的Http客户端黑客,但无论如何,它在这里,只是为了记录在案。也许其中一些会帮助其他人调试其他一些类:

package http.jmockit;

import java.net.*;
import java.net.http.*;
import java.net.http.HttpRequest.BodyPublisher;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.*;
import mockit.*;

public class TestHttpIdentity {

    private static final Logger        LOG         = LoggerFactory.getLogger(TestHttpIdentity.class);
    private static final AtomicBoolean LOG_ENABLED = new AtomicBoolean();
    private static final List<Object>  TRACKED     = new ArrayList<>();

    public static final class FakeByteBuffer extends MockUp<ByteBuffer> {
        @Mock
        public Object $advice(final Invocation invocation) {

            if (TRACKED.stream().noneMatch(tracked -> tracked == invocation.getInvokedInstance())) {
                return invocation.proceed();
            }

            if (LOG_ENABLED.get()) {
                LOG    .info("$advice.invokedInstance.: {}", invocation.getInvokedInstance(), "" /* (makes signature unique)*/);
                LOG    .info("$advice.invokedMember...: {}", invocation.getInvokedMember(),   "" /* (makes signature unique)*/);
//              Thread.dumpStack(); // Use Stack Trace as last measure if needs be
            }

            Object     result = "Not available due to Exception in invocation.proceed()";
            try {
                /**/   result = invocation.proceed();
                return result;
            }
            catch (final Throwable e) {

                for (final Object arg : invocation.getInvokedArguments()) {
                    LOG.info("$advice.arg.............: {} class={}", arg,   arg == null ? "?" : arg.getClass());
                }
                LOG    .info("$advice.Result..........: {}", result);

                LOG_ENABLED.set(false);  // Disable Logging when JMockit fails

                try {Thread.sleep(100);} catch (final InterruptedException shortDelayToSyncLoggingOutput) {}

                e.printStackTrace();
                throw e;
            }
        }
    }

    public static void main(final String[] args) throws Exception {

        LOG.info("MockUp..................: {}", new FakeByteBuffer());

        final ByteBuffer[] byteBuffers  = TestBytes.asWrappedByteBuffers();

        for (final ByteBuffer byteBuffer : byteBuffers) {
            LOG.info("byteBuffer..............: {}", byteBuffer);

            final int limit    = byteBuffer.limit();
            final int position = byteBuffer.position();

            TRACKED.add(byteBuffer);  // Track Objects via their Identity (==)

            LOG.info("Test Bytes..............: {}", byteBuffers, "");
            LOG.info("byteBuffer0.array().....: {}", byteBuffer.array());
            LOG.info("byteBuffer0.capacity()..: {}", byteBuffer.capacity());
            LOG.info("byteBuffer0.get().......: {}", byteBuffer.get());
//          LOG.info("byteBuffer0.get(byte[]).: {}", byteBuffers0.get(new byte[5]));  // ClassCastException
            LOG.info("byteBuffer0.get(byte[]->) {}", byteBuffer.get(new byte[5], 0, 5));
            LOG.info("byteBuffer0.get(0)......: {}", byteBuffer.get(0));
            LOG.info("byteBuffer0.hasArray()..: {}", byteBuffer.hasArray());
            LOG.info("byteBuffer0.hasRemaining: {}", byteBuffer.hasRemaining());
            LOG.info("byteBuffer0.isDirect()..: {}", byteBuffer.isDirect());
            LOG.info("byteBuffer0.isReadOnly(): {}", byteBuffer.isReadOnly());
            LOG.info("byteBuffer0.limit().....: {}", limit);
            LOG.info("byteBuffer0.limit(0)....: {}", byteBuffer.limit(limit));
            LOG.info("byteBuffer0.mark(0).....: {}", byteBuffer.mark());
            LOG.info("byteBuffer0.order().....: {}", byteBuffer.order());
            LOG.info("byteBuffer0.position()..: {}", position);
            LOG.info("byteBuffer0.position(99): {}", byteBuffer.position(99));
            LOG.info("byteBuffer0.remaining().: {}", byteBuffer.remaining());
//          LOG.info("byteBuffer0.reset().....: {}", byteBuffers0.reset());      // -> InvalidMarkException
            LOG.info("byteBuffer0.rewind()....: {}", byteBuffer.rewind());
            LOG.info("byteBuffer0.slice().....: {}", byteBuffer.slice());

            byteBuffer.rewind();
            byteBuffer.position(position);
            byteBuffer.limit   (limit);

            LOG.info("byteBuffer..............: {}", byteBuffer);
        }
        final BodyPublisher pub = new ByteArrayBodyPublisherIterator(byteBuffers);

        LOG_ENABLED.set(false);  // Enable Logging now we've got things set up.

        final HttpRequest request = HttpRequest.newBuilder()
                .uri(new URI("http://localhost:631"))
                .headers("Content-Type", "application/ipp")
                .POST(pub)
                .build();

        HttpResponse<byte[]> response = HttpClient
                .newBuilder()
                .build()
                .send(request, HttpResponse.BodyHandlers.ofByteArray());

        LOG.info("Result......: {} {}", response, response.body());
    }
}

我们谈论的是拦截由您自己的代码调用的ByteBuffer方法,还是您还需要知道J
在内部重新上课?至于一个基于AOP的答案,这会有所不同,因此我的问题是。我希望跟踪调用ByteBuffer的JRE类,特别是新的Java 9 Http客户端中的发布者内容,该客户端在Java 13中得到了进一步增强。因此,您不能使用AspectJ加载时编织,因为Java和javax类不向编织者公开。唯一的方法是使用二进制编织,将方面直接编译到JRE中,并创建自己的编织JRE版本。我以前在较旧的Java版本中也做过这样的工作,它工作得很好。也许这是过度的工程设计,对于生产使用来说绝对不是一个好主意,但是为了了解JRE,这可能是一个可行的方法。不过,通过使用调试器,您也可以学到同样多的东西。我将继续为社区使用英语。我正在使用一个开源Java Cups客户端,因为目前可用的客户端非常有限&我想知道如何最好地将我的ByteBuffers提供给新的Http客户端,所以我想知道它们是如何使用的。理想情况下,我也想知道电话从哪里打来。IntelliJ IDEA日志看起来相当不错。您知道社区版中是否有日志记录吗?来自Odenwald的问候,Dave。事实上我不知道确切原因,因为我使用的是Ultimate Edition,但我希望它也能在社区中使用。试试看。这里是对应的。我可能会尝试一下,毕竟本周我已经尝试了从Mockito到PowerMock再到Spock&JMockit的所有其他方法。但是,自Java9以来,所有这些工具似乎或多或少都已损坏。难怪全世界仍在使用Java8!我已经在当前的社区版v2019.3.4上试用过。它起作用了。某种程度上。如果能找到只记录我的ByteBuffer的方法,那就太好了。我试着输入hashCode;在Evaluate和log下:旨在提取我的实例,但它会导致JVM崩溃。堆栈跟踪选项也很方便,但实际上仍然不可能找出谁在用我的ByteBuffer做什么。嗯,是的,调试器过滤器的文档和条件不好,我甚至向JetBrains支持部门抱怨过。他们问我缺少什么,我只是给他们发了一份长长的清单。让我们看看他们是否有所改进。跟踪单个实例上的方法调用是我在您之前的评论之后尝试时也没有做到的。当我知道更多的时候,我会告诉你,这是一个有趣的用例。但我今天可能很忙。