Fun project I am working on

Daestrum

Expert
Licensed User
Longtime User
I have currently got working, the ability to inline java into B4J not like #If JAVA ...#End If, but inside a sub if needed. It's still rough at present, but a few sneak views of what it looks like.


B4J code:
Sub listSort(mylist As List)
    java("_mylist.getObject().sort((a, b) -> ((Comparable)a).compareTo(b))")
    java("System.out.println(@@Class: @@ + _mylist.getClass())")
    java("for (Field f : _mylist.getClass().getDeclaredFields()) System.out.println(@@Declared: @@ + f)")
    java("for (Field f : _mylist.getClass().getFields()) System.out.println(@@Public: @@ + f)")
    java("for (Field f : _mylist.getClass().getSuperclass().getDeclaredFields()) System.out.println(@@Super: @@ + f)")
End Sub
(in the above read @@ as ")

The generated Java:
public String  _listsort(anywheresoftware.b4a.objects.collections.List _mylist) throws Exception{
 //BA.debugLineNum = 13;BA.debugLine="Sub listSort(mylist As List)";
 //BA.debugLineNum = 14;BA.debugLine="java(\"_mylist.getObject().sort((a, b) -> ((Compar";
_mylist.getObject().sort((a, b) -> ((Comparable)a).compareTo(b));
 //BA.debugLineNum = 15;BA.debugLine="java(\"System.out.println("Class: " + _mylist.ge";
System.out.println("Class: " + _mylist.getClass());
 //BA.debugLineNum = 16;BA.debugLine="java(\"for (Field f : _mylist.getClass().getDeclar";
for (Field f : _mylist.getClass().getDeclaredFields()) System.out.println("Declared: " + f);
 //BA.debugLineNum = 17;BA.debugLine="java(\"for (Field f : _mylist.getClass().getFields";
for (Field f : _mylist.getClass().getFields()) System.out.println("Public: " + f);
 //BA.debugLineNum = 18;BA.debugLine="java(\"for (Field f : _mylist.getClass().getSuperc";
for (Field f : _mylist.getClass().getSuperclass().getDeclaredFields()) System.out.println("Super: " + f);
 //BA.debugLineNum = 19;BA.debugLine="End Sub";
return "";
}

Just a fun project as it allows java access to local variables inside subs.

Currently working on release , but doesnt break debug, just ignores the java inserts.
 

Daestrum

Expert
Licensed User
Longtime User
Got two ways for the code now, single lines like in above example, and now got multiline working too (still in release not debug yet)


multiline:
    javam($"Integer a = 10;
for (int b=0; b<a;b++){
    System.out.println(b);
}"$)

creates this java


generated java code:
 //BA.debugLineNum = 24;BA.debugLine="javam($\"Integer a = 10; for (int b=0; b<a;b++){";
Integer a = 10;
for (int b=0; b<a;b++){
    System.out.println(b);
}

Only side effect - b4j error line numbers get a bit skewed from the added java code.
 

Daestrum

Expert
Licensed User
Longtime User
Been trying lots of code to see what it breaks.
Can add finally clause to Try - Catch - End Try (Also can add try with resource)

finally added to try:
Private Sub Button2_Click
    Try
    For a = 0 To 10
        Log(a)
    Next
    Catch
        Log(LastException)
    java("}finally { IO.println(@@Done@@);")         ' may need IO -> System.out as its a java 25+ class
    End Try   
End Sub

try with resource:
    javam($"
    try (var ww = java.nio.file.Files.newBufferedWriter(java.nio.file.Path.of(_f))) {
        ww.write(@@Hello from Try-with-resources@@);
    } catch (Exception e){
    IO.println(@@Error Occurred@@);
    } finally {
    IO.println(@@All done@@);
    }
"$)

Java recod:
    javam($"
record Weird(int a, String b) {
    public String shout() { return b.toUpperCase(); }
}
Weird w = new Weird(7, @@hello@@);
IO.println(w.shout());
"$)
 

Peter Simpson

Expert
Licensed User
Longtime User
I like it, I like it a lot 👏👏👏
 

Daestrum

Expert
Licensed User
Longtime User
OK, added a few tweaks here and there, does much more than I planned at first.

java("*** some java code ***") injects into a sub where the line is placed
javam($"*** whole block of java ***"$) injects into sub where line is placed, and adds lines if block is multiline

directive("@test") This will place the annotation before the method definition in the Java source file.

***Note: If you try it, do so on a new install of java - that way it won't break B4A Also only works in Release not Debug.

It's a .net program that sits between the IDE and Javac
build the app in visual studio

1, find javac in the java bin file and rename to xjavac.exe
2, Copy the new app to /bin and rename it javac.exe
3, Change path to point to the new java installation and javac (the one you created)

Use the commands in B4J code to insert java.

Any variables you create in the injected java cannot be seen by B4J, so if you need a value returned define the variable in B4J then load it in the java you inject.

If it all goes t..s up, don't worry, the IDE will recreate the java again on the next compile, just remove the injected line that broke it.

if you add things to the injector, and rebuild always close the B4J IDE (it seems to cache the compiler).

Source file below, so you can see it does nothing horrible. It never touches the B4J files - only modifies the java source emitted by B4J IDE.
 

Attachments

  • Program.zip
    3.2 KB · Views: 20

Daestrum

Expert
Licensed User
Longtime User
Forgot to add
You need to create 3 subs in the module where you use the calls - they are just dummy subs to ensure the calls get through to the source (JIT will remove them as dead code at run time)

B4X:
Sub java( s As String)
End Sub

Sub javam( s As String)
End Sub

Sub directive( s As String)
End Sub
 
Top