<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Robbie Gates</title>
    <description>The latest articles on Forem by Robbie Gates (@robbieg).</description>
    <link>https://forem.com/robbieg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F121235%2F48e20064-a838-4fe6-bb27-aef9d12fb0ff.jpeg</url>
      <title>Forem: Robbie Gates</title>
      <link>https://forem.com/robbieg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/robbieg"/>
    <language>en</language>
    <item>
      <title>A deep, deep dive into Java debugging</title>
      <dc:creator>Robbie Gates</dc:creator>
      <pubDate>Fri, 11 Jan 2019 00:51:39 +0000</pubDate>
      <link>https://forem.com/atlassian/a-deep-deep-dive-into-java-debugging-335e</link>
      <guid>https://forem.com/atlassian/a-deep-deep-dive-into-java-debugging-335e</guid>
      <description>&lt;p&gt;This is the story of a Java debugging journey that started with a question I couldn't answer about Java stack traces. As a long time Java programmer, I am approached for help by developers who encounter unusual problems in the language. Diving in and getting acquainted with all the dark corners of Java is something I really enjoy, mainly because I emerge with a better understanding of the language, and also because it equips our team with better tools to solve the everyday problems ... as well as the unusual ones.&lt;/p&gt;

&lt;p&gt;Our trip takes us through a deeper look at Java lambdas and method references, and ends up with a quick foray into the JVM code. We'll use a couple of debugging tools and techniques to figure it all out, and learn a little about implementation details and diagnostic JVM options. &lt;span class="inline-comment-marker valid"&gt;It's a good example of how, with the source in hand, you can demystify a general phenomenon, such as missing frames.&lt;/span&gt;&lt;/p&gt;

&lt;h2 id="ParentEpicFinalTerminalClauseFactoryandthecaseofthemissingframe-ItstartedwithaNullPointerException..."&gt;It all started with a &lt;span&gt;NullPointerException&lt;/span&gt;...&lt;/h2&gt;

&lt;p&gt;&lt;span class="inline-comment-marker"&gt;A co-worker approac&lt;/span&gt;&lt;span class="inline-comment-marker"&gt;hed me with the following stack trace:&lt;/span&gt;&lt;/p&gt;

&lt;pre&gt;java.lang.NullPointerException
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.Collections$2.tryAdvance(Collections.java:4717)
    at java.util.Collections$2.forEachRemaining(Collections.java:4725)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
    at com.atlassian.jira.jql.util.ParentEpicFinalTerminalClauseFactory.getFinalTerminalQuery(ParentEpicFinalTerminalClauseFactory.java:47)&lt;/pre&gt;
This was accompanied by another 364 less-interesting frames. What's interesting, and what brought him to me, is the code of the first frame. It's from the JDK (build &lt;span&gt;1.8.0_172-b11&lt;/span&gt;), and it is as follows:
&lt;pre&gt;&lt;strong&gt;ReferencePipeline.java&lt;/strong&gt;
public final  Stream map(Function super P_OUT, ? extends R&amp;gt; mapper) {
    Objects.requireNonNull(mapper);
    return new StatelessOp(this, StreamShape.REFERENCE,
                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
        @Override
        Sink opWrapSink(int flags, Sink sink) {
            return new Sink.ChainedReference(sink) {
                @Override
                &lt;span&gt;public void accept(P_OUT u) {&lt;/span&gt;
                    downstream.accept(mapper.apply(u));
                }
            };
        }
    };
}
&lt;/pre&gt;

&lt;p&gt;The question at hand was, "What could be &lt;span&gt;null&lt;/span&gt; on line 193 (highlighted above in red)?"  It can't be &lt;span&gt;mapper&lt;/span&gt; because:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;It is a local, so it can't be updated from outside this code&lt;/li&gt;
    &lt;li&gt;There's a &lt;span&gt;requireNonNull&lt;/span&gt; before the usage, so it started not null, and&lt;/li&gt;
    &lt;li&gt;It is &lt;em&gt;effectively final&lt;/em&gt; and used in an inner class, so it can't have changed. For full details on &lt;em&gt;effectively final&lt;/em&gt; you can read the &lt;a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.4" class="external-link" rel="nofollow"&gt;Java Language Specification, version 8, section 4.12.4&lt;/a&gt;, but TL;DR: it could be &lt;span&gt;final&lt;/span&gt; and so is treated as &lt;span&gt;final&lt;/span&gt; since the inner class reference needs it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It can't be &lt;span&gt;downstream&lt;/span&gt;, because if you hunt down its declaration you find:&lt;/p&gt;

&lt;pre&gt;&lt;strong&gt;Sink.java&lt;/strong&gt;
static abstract class ChainedReference&amp;lt;T, E_OUT&amp;gt; implements Sink {
    protected final Sink&amp;lt;? super E_OUT&amp;gt; downstream;
 
    public ChainedReference(Sink&amp;lt;? super E_OUT&amp;gt; downstream) {
        this.downstream = Objects.requireNonNull(downstream);
    }
&lt;/pre&gt;

&lt;p&gt;As you can see:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;The field &lt;span&gt;downstream&lt;/span&gt; is final,&lt;/li&gt;
    &lt;li&gt;There's a &lt;span&gt;requireNonNull&lt;/span&gt; when it is initialized, and&lt;/li&gt;
    &lt;li&gt;There's no usage of &lt;span&gt;this&lt;/span&gt; or &lt;span&gt;super&lt;/span&gt; in the constructor, so we can't be in code executing on a partially constructed object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My next thought was that maybe &lt;span&gt;P_OUT&lt;/span&gt; was a boxed type, like &lt;span&gt;Integer&lt;/span&gt; or &lt;span&gt;Long&lt;/span&gt;, and that to invoke &lt;span&gt;mapper.apply&lt;/span&gt;, the compiler had inserted an unboxing of &lt;span&gt;u.&lt;/span&gt;&lt;span class="inline-comment-marker"&gt;Unboxing throws a &lt;span&gt;NullPointerException&lt;/span&gt; if the reference is &lt;span&gt;null&lt;/span&gt; (detailed in &lt;a class="external-link" href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.8" rel="nofollow"&gt;JLS 8, 5.1.8&lt;/a&gt;). For example, code like &lt;span&gt;int value = getValue();&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;can throw an exception, if &lt;span&gt;getValue()&lt;/span&gt; is declared to return &lt;span&gt;Integer&lt;/span&gt; and actually returns &lt;span&gt;null&lt;/span&gt; because the compiler inserts a call to &lt;span&gt;Integer.intValue&lt;/span&gt; to convert the returned &lt;span&gt;Integer&lt;/span&gt; to an &lt;span&gt;int&lt;/span&gt;. However, looking at the code for &lt;span&gt;getFinalTerminalQuery&lt;/span&gt; in this case revealed that &lt;span&gt;P_OUT&lt;/span&gt; was &lt;span&gt;com.atlassian.jira.issue.Issue&lt;/span&gt;, which isn't boxed – it's the main issue interface in Jira.&lt;/p&gt;

&lt;h2 id="ParentEpicFinalTerminalClauseFactoryandthecaseofthemissingframe-Where'sthenull?"&gt;Where's the &lt;span&gt;null&lt;/span&gt;?&lt;/h2&gt;

&lt;p&gt;Although these questions didn't find the source of the &lt;span&gt;NullPointerException&lt;/span&gt;, they did reveal that &lt;span&gt;mapper&lt;/span&gt; was &lt;span&gt;Issue::getId&lt;/span&gt; - that is - a &lt;em&gt;method reference&lt;/em&gt; (&lt;span class="inline-comment-marker"&gt;as per &lt;/span&gt;&lt;a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13" class="external-link" rel="nofollow"&gt;&lt;span class="inline-comment-marker"&gt;JLS 8, 15.13&lt;/span&gt;&lt;/a&gt;), and this seemed unusual enough to be interesting and worth looking at further. At this point I was somewhat bemused, but also quite excited, because I couldn't explain what I was seeing ... which meant that I was about to learn something new! So I broke out a bit &lt;span class="inline-comment-marker"&gt;of &lt;/span&gt;&lt;span class="inline-comment-marker"&gt;test code&lt;/span&gt;&lt;span class="inline-comment-marker"&gt; by&lt;/span&gt; boiling down the case above to the following code:&lt;/p&gt;

&lt;pre&gt;&lt;strong&gt;Main.java&lt;/strong&gt;
public class Main {
    static class Thing {
        Long
        getId() {
            return 163L;
        }
    }

    public static void main(String[] args) {
        Thing thing = null;
        System.out.println(
            Collections.singleton(thing).stream().map(Thing::getId).collect(toList())
        );
    }
}
&lt;/pre&gt;

&lt;p&gt;Sure enough, running this code got me a &lt;span&gt;NullPointerException&lt;/span&gt; with a stack similar enough to the above, at least at the pointy end. By the way, you can clone that repository using &lt;span&gt;git clone &lt;a href="mailto:git@bitbucket.org"&gt;git@bitbucket.org&lt;/a&gt;:atlassian/missing-frame.git&lt;/span&gt; if you want to see it for yourself. There are some handy canned command lines in the README.&lt;/p&gt;

&lt;p&gt;In other words, you'll get a &lt;span&gt;NullPointerException&lt;/span&gt; if you apply a valid method reference (like &lt;span&gt;Thing::getId&lt;/span&gt; in the example) to a &lt;span&gt;null&lt;/span&gt; reference.&lt;/p&gt;

&lt;p&gt;This is not surprising. What is surprising, until you know this, is that you won't see a frame for the invocation of that function. You &lt;em&gt;can't&lt;/em&gt; see a frame for &lt;span&gt;getId&lt;/span&gt; of course, because that would mean you'd be in a member function where &lt;span&gt;this&lt;/span&gt; was null, &lt;span class="inline-comment-marker"&gt;which&lt;/span&gt; won't happen while you're looking. This has nothing to do with the use of the &lt;span&gt;Stream&lt;/span&gt; by the way, you can get the same effect from&lt;/p&gt;

&lt;pre&gt;Thing thing = null;
Function&amp;lt;Thing, Long&amp;gt; function = Thing::getId;
function.apply(thing);
&lt;/pre&gt;

&lt;p&gt;&lt;span class="inline-comment-marker"&gt;But I didn't know that at the time I was writing the test code&lt;/span&gt;. This is one of the nice things about writing test code, you can freely edit it &lt;span class="inline-comment-marker"&gt;and&lt;/span&gt; play around with what exactly is causing the effect you are investigating.&lt;/p&gt;

&lt;h2&gt;
&lt;span class="inline-comment-marker"&gt;But where is &lt;/span&gt;&lt;span class="inline-comment-marker"&gt;the &lt;/span&gt;&lt;span class="inline-comment-marker"&gt;exception thrown&lt;/span&gt;?&lt;/h2&gt;

&lt;p&gt;In &lt;span class="inline-comment-marker"&gt;IntelliJ, you can use &lt;/span&gt;&lt;em&gt;&lt;span class="inline-comment-marker"&gt;View/Show Bytecode&lt;/span&gt;&lt;/em&gt;&lt;span class="inline-comment-marker"&gt; on these examples to see the JVM bytecode. Other IDEs have similar functionality. You could also use &lt;span&gt;javap&lt;/span&gt; from the command line. In any case, &lt;/span&gt;you will see something like:&lt;/p&gt;

&lt;pre&gt;INVOKEDYNAMIC apply()Ljava/util/function/Function; [
  // handle kind 0x6 : INVOKESTATIC
  java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  // arguments:
  (Ljava/lang/Object;)Ljava/lang/Object;, 
  // handle kind 0x5 : INVOKEVIRTUAL
  com/atlassian/rgates/missingframe/Main$Thing.getId()Ljava/lang/Long;, 
  (Lcom/atlassian/rgates/missingframe/Main$Thing;)Ljava/lang/Long;
]&lt;/pre&gt;
What is &lt;span&gt;invokedynamic&lt;/span&gt;, you say? In this case, we need to break out the &lt;a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic"&gt;Java Virtual Machine Specification, version 8, section 6.5&lt;/a&gt;, which tells us that some information is looked up and then resolved (as per &lt;a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.6"&gt;JVMS 8, section 5.4.3.6&lt;/a&gt;) to produce a &lt;span&gt;MethodHandle&lt;/span&gt; object. This is then &lt;span&gt;invoke()&lt;/span&gt;d to get a &lt;span&gt;CallSite&lt;/span&gt; which is bound to that instruction, effectively caching the costly lookup. Then, we &lt;span&gt;invokeExact&lt;/span&gt; the &lt;span&gt;CallSite.target&lt;/span&gt; to get a &lt;span&gt;Function&lt;/span&gt; object. Whoah. It's worth noting this is not what is throwing – it hasn't even looked at the &lt;span&gt;null&lt;/span&gt; reference yet, and the spec is quite clear that &lt;em&gt;an &lt;span&gt;"&lt;span class="inline-comment-marker"&gt;invokedynamic instruction which is bound to a call site object never throws a &lt;/span&gt;&lt;span&gt;&lt;span class="inline-comment-marker"&gt;NullPointerException&lt;/span&gt;&lt;/span&gt;&lt;span class="inline-comment-marker"&gt; or …"&lt;/span&gt;&lt;/span&gt;&lt;/em&gt;&lt;span class="inline-comment-marker"&gt;.&lt;/span&gt;

&lt;p&gt;So what is the &lt;span&gt;Function&lt;/span&gt; we get? If you look at it in IntelliJ, for example by breakpointing the constructor of &lt;span&gt;NullPointerException&lt;/span&gt; and inspecting the &lt;span&gt;mapper&lt;/span&gt;, you see an object which claims to be a &lt;span&gt;com.atlassian.rgates.missingframe.Main$$Lambda$1/6738746&lt;/span&gt;, but you won't find that in your source. These classes are generated on the fly by the &lt;span&gt;LambdaMetafactory&lt;/span&gt; referenced in the &lt;span&gt;INVOKEDYNAMIC&lt;/span&gt; opcode. The code that writes them is in the delightfully named &lt;span&gt;java.lang.invoke.InnerClassLambdaMetafactory#spinInnerClass&lt;/span&gt;. It's worth noting they don't go through the normal &lt;span&gt;ClassLoader&lt;/span&gt; machinery, but use the wonderful &lt;span&gt;sun.misc.Unsafe#defineAnonymousClass&lt;/span&gt; to get themselves loaded.&lt;/p&gt;

&lt;p&gt;Anyway, now that I was this far down, I had to keep digging. So I dumped the class spun up by &lt;span&gt;spinInnerClass&lt;/span&gt; to a file by evaluating &lt;span&gt;new FileOutputStream("lambdaClass.class").write(classBytes)&lt;/span&gt; in the debugger. This is a common trick I use when debugging – evaluating an expression which intentionally has side effects. There is some data we want to inspect – &lt;span&gt;classBytes&lt;/span&gt; in this example. To inspect it, we want to pass it off to another tool, and so we need to get it in a file. The expression has the side effect of writing &lt;span&gt;classBytes&lt;/span&gt; to the file &lt;span&gt;lambdaClass.class&lt;/span&gt;, and I can use this for further processing. Once I had the bytes from the built-on-the-fly class in a file, I could use the &lt;span&gt;javap&lt;/span&gt; utility to dump it.&lt;/p&gt;
&lt;pre&gt;0: aload_1
1: checkcast     #15                 // class com/atlassian/rgates/missingframe/Main$Thing
4: invokevirtual #19                 // Method com/atlassian/rgates/missingframe/Main$Thing.getId:()Ljava/lang/Long;
7: areturn
&lt;/pre&gt;

&lt;p&gt;&lt;span&gt;&lt;span&gt;Voila!&lt;/span&gt; It's the &lt;span&gt;invokevirtual&lt;/span&gt; that is throwing &lt;span&gt;NullPointerException&lt;/span&gt;, as per &lt;a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokevirtual"&gt;JVMS 8, section 6.5&lt;/a&gt;: &lt;em&gt;if &lt;/em&gt;objectref&lt;em&gt; is null, the &lt;/em&gt;invokevirtual&lt;em&gt; instruction throws a &lt;span&gt;NullPointerException&lt;/span&gt;&lt;/em&gt;. So that's kind of what one might expect – a runtime generated wrapper which calls the function named by the method reference.&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;&lt;span&gt;But the frame is still missing!&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;There totally should be a frame for &lt;span&gt;apply&lt;/span&gt;. In fact, if you're playing at home and have breakpointed the &lt;span&gt;NullPointerException&lt;/span&gt; constructor like me, you can see the &lt;span&gt;apply&lt;/span&gt; frame on the stack. However, if you step through the code until after the call to &lt;span&gt;java.lang.Throwable#fillInStackTrace(int)&lt;/span&gt;, you won't find the frame in the output of &lt;span&gt;Throwable.getStackTrace&lt;/span&gt;. At this point, the only place left to inspect was &lt;span&gt;fillInStackTrace&lt;/span&gt;, and of course that is &lt;span&gt;native&lt;/span&gt;. So you need to hop over to the &lt;span class="inline-comment-marker"&gt;OpenJdk source&lt;/span&gt;, and look at &lt;/span&gt;&lt;span&gt;void java_lang_Throwable::fill_in_stack_trace(Handle throwable, methodHandle method, TRAPS)&lt;/span&gt; in &lt;span&gt;hotspot/src/share/vm/classfile/javaClasses.cpp&lt;/span&gt;. I didn't &lt;span class="inline-comment-marker"&gt;grok&lt;/span&gt; the whole method, but I did skip through it enough to find:&lt;/p&gt;

&lt;pre&gt;&lt;strong&gt;javaClasses.cpp&lt;/strong&gt;
if (method-&amp;gt;is_hidden()) {
  if (skip_hidden)  continue;
}&lt;/pre&gt;
Methods can be &lt;em&gt;hidden&lt;/em&gt;? &lt;span&gt;&lt;span class="inline-comment-marker"&gt;TIL.&lt;/span&gt;&lt;span class="inline-comment-marker"&gt; &lt;/span&gt;&lt;/span&gt;I wonder who calls &lt;span&gt;set_hidden&lt;/span&gt;? As it turns out, &lt;span&gt;void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m)&lt;/span&gt; says:
&lt;pre&gt;&lt;strong&gt;classFileParser.cpp&lt;/strong&gt;
if (has_annotation(_method_LambdaForm_Hidden))
  m-&amp;gt;set_hidden(true);&lt;/pre&gt;
&lt;span class="inline-comment-marker"&gt;A bit more digging reveals&lt;/span&gt; that the value of &lt;span&gt;_method_LambdaForm_Hidden&lt;/span&gt; is the string &lt;span&gt;Ljava/lang/invoke/LambdaForm$Hidden;&lt;/span&gt;. To tie this back to the Java code, I again used &lt;span&gt;javap&lt;/span&gt; to decompile the class file we dumped above. This time, however, I added an extra flag to &lt;span&gt;javap&lt;/span&gt; - the &lt;span&gt;-v&lt;/span&gt; flag, which makes &lt;span&gt;javap&lt;/span&gt; verbose. In particular, this makes it dump the strings in the class constant pool - our string is at index &lt;span&gt;#13&lt;/span&gt;, and we can see the runtime annotation &lt;span&gt;#13&lt;/span&gt; is present on the &lt;span&gt;apply&lt;/span&gt; method:
&lt;pre&gt;#13 = Utf8               Ljava/lang/invoke/LambdaForm$Hidden;

...
public java.lang.Object apply(java.lang.Object);
...
RuntimeVisibleAnnotations:
  0: #13()
&lt;/pre&gt;

&lt;p class="auto-cursor-target"&gt;So, you can't see the frame because it's hidden. In fact, a bit further up in &lt;span&gt;spinInnerClass&lt;/span&gt;, it calls:&lt;/p&gt;

&lt;pre&gt;mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);&lt;/pre&gt;

&lt;p&gt;to add the annotation, but I missed this on the first read through. Reading this backwards to understand the flow: When generating the runtime wrappers used to invoke the method references, the generation code annotates the &lt;span&gt;apply&lt;/span&gt; method with a &lt;span&gt;java.lang.invoke.LambdaForm$Hidden&lt;/span&gt; annotation, and the JVM code (which fills in stack traces to implement the Java level &lt;span&gt;&lt;span&gt;fillInStackTrace&lt;/span&gt;&lt;/span&gt; function) checks for this annotation, and skips over frames for methods with this annotation.&lt;/p&gt;

&lt;h2&gt;One more thing …&lt;/h2&gt;

&lt;p&gt;The &lt;span class="inline-comment-marker"&gt;sharp eyed will have noticed&lt;/span&gt; that the JVM code in &lt;span&gt;javaClasses.cpp&lt;/span&gt; above has a &lt;span&gt;skip_hidden&lt;/span&gt; check also, which turns out to be set from &lt;span&gt;ShowHiddenFrames&lt;/span&gt;, which is mentioned in:&lt;/p&gt;

&lt;pre&gt;diagnostic(bool, ShowHiddenFrames, false,                                 \
        "show method handle implementation frames (usually hidden)")      \
&lt;/pre&gt;

&lt;p&gt;Reading some documentation in this file led me to &lt;span&gt;java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal&lt;/span&gt; which shows a wealth of JVM diagnostic and internal stuff, including:&lt;/p&gt;

&lt;pre&gt;bool ShowHiddenFrames                          = false                               {diagnostic}&lt;/pre&gt;

&lt;p&gt;and thus, finally to:&lt;/p&gt;

&lt;pre&gt;:; java -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -cp build/libs/missing-frame.jar com.atlassian.rgates.missingframe.Main
Exception in thread "main" java.lang.NullPointerException
    at com.atlassian.rgates.missingframe.Main$$Lambda$1/295530567.apply(:1000004)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.Collections$2.tryAdvance(Collections.java:4717)
    at java.util.Collections$2.forEachRemaining(Collections.java:4725)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
    at com.atlassian.rgates.missingframe.Main.main(Main.java:17)&lt;/pre&gt;

&lt;p class="auto-cursor-target"&gt;There's the frame! The error is at &lt;span&gt;&amp;lt;Unknown&amp;gt;:1000004&lt;/span&gt; –  the JVM doesn't know the source name (hence &lt;span&gt;&amp;lt;Unknown&amp;gt;&lt;/span&gt;), and uses &lt;span&gt;1000000 + bci&lt;/span&gt; for line numbers if it has no line numbers, where &lt;span&gt;bci&lt;/span&gt; is the byte code index of the &lt;span&gt;invokevirtual&lt;/span&gt; we identified as the cause above.&lt;/p&gt;

&lt;h2 class="auto-cursor-target"&gt;And my co-worker?&lt;/h2&gt;

&lt;p&gt;I got back to my co-worker with my findings, and they responded &lt;em&gt;&lt;span&gt;Curiosity: Satisfied&lt;/span&gt;&lt;/em&gt;. It's nice to go beyond just "use this workaround" and instead gain a full understanding of exactly why the code is behaving in the way we observe. It's especially nice when I get to learn a few things about Java implementation details and JVM internals.&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>java</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
