<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<p>Sorry,<br>
<br>
It seems I'm just not well enough versed in byte code generation
and how the class verifier works. <br>
<br>
The verifier was fine with a `getProperty(outer)` definition with
the code within it referring to the outer type. But the abstract
class doesn't define that method, it defines
`getProperty(Styleable)` so this method wouldn't actually
implement the abstract method. If the only change I made was the
signature, then the verifier would reject it, as the method body
refers to outer. So I had this:<br>
</p>
<div style="background-color:#ffffff;padding:0px 0px 0px 2px;">
<div
style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:11pt;white-space:pre;"><p
style="margin:0;"><span style="color:#000000;"> cb.withMethodBody(</span><span
style="color:#2a00ff;">"getStyleableProperty"</span><span
style="color:#000000;">, MethodTypeDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(ClassDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(</span><span style="color:#2a00ff;">"javafx.css.StyleableProperty"</span><span
style="color:#000000;">), outer</span><span style="color:#000000;">), ClassFile.</span><span
style="color:#0000c0;">ACC_PUBLIC</span><span
style="color:#000000;">, mb -> {</span></p><p style="margin:0;"><span
style="color:#000000;"> mb.aload(1)</span></p><p
style="margin:0;"><span style="color:#000000;"> .getfield(</span><span
style="color:#000000;background-color:#d4d4d4;">outer</span><span
style="color:#000000;">, cssData.</span><span
style="color:#0000c0;">fieldName</span><span
style="color:#000000;">, ClassDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(</span><span style="color:#2a00ff;">"javafx.css.CssMetaData"</span><span
style="color:#000000;">))</span></p><p style="margin:0;"><span
style="color:#000000;"> .checkcast(ClassDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(</span><span style="color:#2a00ff;">"javafx.css.StyleableProperty"</span><span
style="color:#000000;">))</span></p><p style="margin:0;"><span
style="color:#000000;"> .areturn();</span></p><p
style="margin:0;"><span style="color:#000000;"> });</span></p></div>
</div>
<p>The above works, but doesn't implement the abstract method as it
has a different signature. I found this very confusing as I'm
hard referencing an outer ClassDesc here that doesn't exist yet,
but its fine with it, yet with the signature modified to correctly
implement the abstract method it rejects it suddenly:</p>
<div style="background-color:#ffffff;padding:0px 0px 0px 2px;">
<div
style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:11pt;white-space:pre;"><p
style="margin:0;"><span style="color:#000000;"> cb.withMethodBody(</span><span
style="color:#2a00ff;">"getStyleableProperty"</span><span
style="color:#000000;">, MethodTypeDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(ClassDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(</span><span style="color:#2a00ff;">"javafx.css.StyleableProperty"</span><span
style="color:#000000;">), ClassDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(</span><span style="color:#2a00ff;">"javafx.css.Styleable"</span><span
style="color:#000000;">)), ClassFile.</span><span
style="color:#0000c0;">ACC_PUBLIC</span><span
style="color:#000000;">, mb -> {</span></p><p style="margin:0;"><span
style="color:#000000;"> mb.aload(1)</span></p><p
style="margin:0;"><span style="color:#000000;"> .getfield(</span><span
style="color:#000000;background-color:#d4d4d4;">outer</span><span
style="color:#000000;">, cssData.</span><span
style="color:#0000c0;">fieldName</span><span
style="color:#000000;">, ClassDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(</span><span style="color:#2a00ff;">"javafx.css.CssMetaData"</span><span
style="color:#000000;">))</span></p><p style="margin:0;"><span
style="color:#000000;"> .checkcast(ClassDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(</span><span style="color:#2a00ff;">"javafx.css.StyleableProperty"</span><span
style="color:#000000;">))</span></p><p style="margin:0;"><span
style="color:#000000;"> .areturn();</span></p><p
style="margin:0;"><span style="color:#000000;"> });</span></p></div>
</div>
<p></p>
<p>The above gets rejected with a NoClassDefFoundError for the outer
type. The solution was to insert a checkcast(outer):<br>
</p>
<div style="background-color:#ffffff;padding:0px 0px 0px 2px;">
<div
style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:11pt;white-space:pre;"><p
style="margin:0;"><span style="color: rgb(0, 0, 0);"> cb.withMethodBody(</span><span
style="color: rgb(42, 0, 255);">"getStyleableProperty"</span><span
style="color: rgb(0, 0, 0);">, MethodTypeDesc.</span><span
style="color: rgb(0, 0, 0); font-style: italic;">of</span><span
style="color: rgb(0, 0, 0);">(ClassDesc.</span><span
style="color: rgb(0, 0, 0); font-style: italic;">of</span><span
style="color: rgb(0, 0, 0);">(</span><span
style="color: rgb(42, 0, 255);">"javafx.css.StyleableProperty"</span><span
style="color: rgb(0, 0, 0);">), ClassDesc.</span><span
style="color: rgb(0, 0, 0); font-style: italic;">of</span><span
style="color: rgb(0, 0, 0);">(</span><span
style="color: rgb(42, 0, 255);">"javafx.css.Styleable"</span><span
style="color: rgb(0, 0, 0);">)), ClassFile.</span><span
style="color: rgb(0, 0, 192);">ACC_PUBLIC</span><span
style="color: rgb(0, 0, 0);">, mb -> {</span></p><p
style="margin:0;"><span style="color:#000000;"> mb.aload(1)</span></p><p
style="margin:0;"><span style="color:#000000;"> .checkcast(</span><span
style="color:#000000;background-color:#d4d4d4;">outer</span><span
style="color:#000000;">)</span></p><p style="margin:0;"><span
style="color:#000000;"> .getfield(</span><span
style="color:#000000;background-color:#d4d4d4;">outer</span><span
style="color:#000000;">, cssData.</span><span
style="color:#0000c0;">fieldName</span><span
style="color:#000000;">, ClassDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(</span><span style="color:#2a00ff;">"javafx.css.CssMetaData"</span><span
style="color:#000000;">))</span></p><p style="margin:0;"><span
style="color:#000000;"> .checkcast(ClassDesc.</span><span
style="color:#000000;font-style:italic;">of</span><span
style="color:#000000;">(</span><span style="color:#2a00ff;">"javafx.css.StyleableProperty"</span><span
style="color:#000000;">))</span></p><p style="margin:0;"><span
style="color:#000000;"> .areturn();</span></p><p
style="margin:0;"><span style="color:#000000;"> });</span></p></div>
</div>
<p>I'm very happy this works. At first I thought it was just
something that only javac in combination with class loaders was
allowed to do (a circular class reference) and it couldn't be done
with Lookup::defineClass -- it turns out the actual reason seems
to be that the reference isn't actually circular during
loading, but simply attempted at runtime. <br>
<br>
--John<br>
</p>
<p><br>
</p>
<div class="moz-cite-prefix">On 15/03/2025 10:53, Michael van Acken
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:CAEYHehhcMfFmR6g2yiRVaM-JfHL-fTzHn=Q3ST_Dtt8rSdHPVA@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="ltr">As far as I know, at time of definition only the
class being extended must be available.
<div>From your example, this seems to be j.l.Object both times,
so this should not be the problem.</div>
<div><br>
</div>
<div>But your case triggers a vague recollection, where I had
the same behaviour of </div>
<div>Lookup.defineClass() in some gnarly unit test of my
compiler -- with a NoCDFE that</div>
<div>I was not able to explain.</div>
<div><br>
</div>
<div>Out of curiosity: what happens when you catch the exception
and do a findClass using</div>
<div>the same lookup and the dotted class name of the class you
just tried to define? In</div>
<div>my case, I got back the class instance in the catch clause,
suggesting the defineClass</div>
<div>completed after all.</div>
<div><br>
</div>
<div>-- mva</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
</div>
<br>
<div class="gmail_quote gmail_quote_container">
<div dir="ltr" class="gmail_attr">Am Sa., 15. März 2025 um
10:19 Uhr schrieb John Hendrikx <<a
href="mailto:john@int4.org" moz-do-not-send="true"
class="moz-txt-link-freetext">john@int4.org</a>>:<br>
</div>
<blockquote class="gmail_quote"
style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div>
<p>Hi list,<br>
<br>
I'm trying to use the ClassFile API to automatically
implement control classes (as found in JavaFX). These
classes define inner class CssMetaData implementations
that refer back to the outer class, and the outer class
refers to these implementations via static fields. When I
define one of the inner types using Lookup::defineClass I
get a NoClassDefFoundError for the outer type. When I
define the outer type first, I get a NoClassDefFoundError
for one of the inner types. The situation is essentially
this:</p>
<div
style="background-color:rgb(255,255,255);padding:0px 0px 0px 2px">
<div
style="color:rgb(0,0,0);background-color:rgb(255,255,255);font-family:Consolas;font-size:11pt;white-space:pre-wrap"><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">public</span><span
style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">class</span><span
style="color:rgb(0,0,0)"> Sample {</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">private</span><span
style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">final</span><span
style="color:rgb(0,0,0)"> Property </span><span
style="color:rgb(0,0,192)">b</span><span
style="color:rgb(0,0,0)"> = </span><span
style="color:rgb(0,0,160);font-weight:bold">new</span><span
style="color:rgb(0,0,0)"> Property(</span><span
style="color:rgb(0,0,192)">A</span><span
style="color:rgb(0,0,0)">);</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">private</span><span
style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">static</span><span
style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">final</span><span
style="color:rgb(0,0,0)"> CssMetaData </span><span
style="color:rgb(0,0,192)">A</span><span
style="color:rgb(0,0,0)"> = </span><span
style="color:rgb(0,0,160);font-weight:bold">new</span><span
style="color:rgb(0,0,0)"> CssMetaData() {</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(100,100,100)">@Override</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">public</span><span
style="color:rgb(0,0,0)"> Property getProperty(Object obj) {</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(127,0,85);font-weight:bold">return</span><span
style="color:rgb(0,0,0)"> ((Sample)obj).</span><span
style="color:rgb(0,0,192)">b</span><span
style="color:rgb(0,0,0)">;</span></p><p style="margin:0px"><span
style="color:rgb(0,0,0)"> }</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> };</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> }</span></p><p
style="margin:0px">
</p><p style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">abstract</span><span
style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">class</span><span
style="color:rgb(0,0,0)"> CssMetaData {</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">abstract</span><span
style="color:rgb(0,0,0)"> Property getProperty(Object obj);</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> }</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">class</span><span
style="color:rgb(0,0,0)"> Property {</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> </span><span
style="color:rgb(0,0,160);font-weight:bold">public</span><span
style="color:rgb(0,0,0)"> Property(CssMetaData </span><span
style="color:rgb(0,0,0);text-decoration:underline wavy rgb(244,200,45)">a</span><span
style="color:rgb(0,0,0)">) {</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> }</span></p><p
style="margin:0px"><span style="color:rgb(0,0,0)"> }</span></p></div>
</div>
<p>I'm trying to generate the Sample class. The classes
CssMetaData and Propery are pre-existing. As you can see,
Sample refers to A in a property it creates, while A
refers to that property by direct field access after a
cast.</p>
<p>Note that the above is perfectly legal as a Java class,
and I think the bytecode I generate is correct. It seems
I would need to be able to define both classes at the same
time, but Lookup doesn't seem to have anything for this
purpose.</p>
<p>I'd appreciate any insights!</p>
<p>--John<br>
</p>
</div>
</blockquote>
</div>
</blockquote>
</body>
</html>