Support inner classes in inline-java
facundominguez opened this issue · 3 comments
Try the following snippet
diff --git a/dep/inline-java/tests/Language/Java/InlineSpec.hs b/dep/inline-java/tests/Language/Java/InlineSpec.hs
index 6c50a70..2f7f1a6 100644
--- a/dep/inline-java/tests/Language/Java/InlineSpec.hs
+++ b/dep/inline-java/tests/Language/Java/InlineSpec.hs
@@ -51,3 +51,8 @@ spec = do
let foo = 1 :: Int32
([java| { class Foo { int f() { return $foo; } }; return 1; } |]
>>= reify) `shouldReturn` (1 :: Int32)
+
+ it "Supports using antiquotation variables of inner classes" $ do
+ foo <- [java| p.Outer.Inner.A |] :: IO (J ('Class "p.Outer$Inner"))
+ _ <- [java| $foo |] :: IO JObject
+ return ()
with
package p;
public class Outer {
public static enum Inner { A, B, C }
}
the result is
[1 of 3] Compiling Language.Java.InlineSpec ( tests/Language/Java/InlineSpec.hs, .stack-work/dist/x86_64-linux-nix/Cabal-1000.24.2.0/build/spec/spec-tmp/Language/Java/InlineSpec.o )
/run/user/1000/inlinejava21090/Inline__main_Language_Java_InlineSpec.java:60: error: cannot find symbol
public static java.lang.Object function_6989586621679076301 (final p.Outer$Inner $foo)
^
symbol: class Outer$Inner
location: package p
1 error
callProcess: javac "/run/user/1000/inlinejava21090/Inline__main_Language_Java_InlineSpec.java" (exit 1): failed
The problem seems to be that the jni package wants the name of the inner class to be p.Outer$Inner
(this is the same name that javap
prints) and inline-java wants p.Outer.Inner
.
Once we understand what syntax these names are expected to have, we can see what inline-java can do to translate them into java source names (e.g. p.Outer.Inner
), and what jni can do to translate them to JNI internal names (e.g. p/Outer$Inner
).
In principle, replacing '$' with '.' wouldn't work because class names can contain '$'. But it could be an acceptable stop-gap.
Examining the output of javap -v
, it looks like some metadata is included in the bytecode to specify whether a class is an inner class or it is top level. The occurrences of $
in the name may or may not come from separating the outer and inner class names.
Thus translating names between internal and source representations does seem to require additional metadata.
There is an interesting advice about dealing with inner classes here. It refers to serialization, but it also serves as a warning that we are dealing with a non-standard encoding of inner classes and names.
Some options:
- Don't support inner classes or enums in inline-java.
- Offer a new kind of antiquotation that overrides the type of the antiquoted variable.
- Like (2), but substitute '$' with '.' when the normal antiquotation is used.
Note that (2) can be achieved without any changes to inline-java, if verbosely:
it "Supports using antiquotation variables of inner classes" $ do
foo <- [java| p.Outer.Inner.A |] :: IO (J ('Class "p.Outer$Inner"))
let foo2 = upcast foo :: J ('Class "java.lang.Object")
_ <- [java| (p.Outer.Inner) $foo2 |] :: IO JObject
return ()
with a new antiquotation it could be for instance:
it "Supports using antiquotation variables of inner classes" $ do
foo <- [java| p.Outer.Inner.A |] :: IO (J ('Class "p.Outer$Inner"))
_ <- [java| $(p.Outer.Inner foo) |] :: IO JObject
return ()
"Verbose" option (2) sounds reasonable to me. Maybe just documentation work to be done then?
Fixed in #90.