All Projects → tweag → Inline Java

tweag / Inline Java

Licence: other
Haskell/Java interop via inline Java code in Haskell modules.

Programming Languages

java
68154 projects - #9 most used programming language
haskell
3896 projects

Projects that are alternatives of or similar to Inline Java

jvm-dump-proxy
A proxy DLL for Windows to dump JVM classes at JNI level
Stars: ✭ 53 (-73.1%)
Mutual labels:  jvm, jni
sbt-jni
SBT Plugin to ease working with JNI
Stars: ✭ 110 (-44.16%)
Mutual labels:  jvm, jni
jni
V wrapper around the C Java Native Interface
Stars: ✭ 15 (-92.39%)
Mutual labels:  interoperability, jni
Android
Swift library for Android
Stars: ✭ 48 (-75.63%)
Mutual labels:  jvm, jni
Rucaja
Calling the JVM from Rust via JNI
Stars: ✭ 35 (-82.23%)
Mutual labels:  jni, ffi
jni-bind
JNI Bind is a set of advanced syntactic sugar for writing efficient correct JNI Code in C++17 (and up).
Stars: ✭ 42 (-78.68%)
Mutual labels:  jvm, jni
jni-bindgen
Generate Rust JVM FFI wrappers around APIs defined by .jar or .class files, because maintaining your own hand-written bindings is an exercise in boredom, soundness bugs, and pain.
Stars: ✭ 55 (-72.08%)
Mutual labels:  jvm, jni
imgui-java
JNI based binding for Dear ImGui
Stars: ✭ 270 (+37.06%)
Mutual labels:  jvm, jni
Fake Jni
An implementation of the JNI and JVMTI with support for direct interaction between natively registered classes and JVM objects.
Stars: ✭ 20 (-89.85%)
Mutual labels:  jvm, jni
Dart native
Write iOS&Android Code using Dart. This package liberates you from redundant glue code and low performance of Flutter Channel.
Stars: ✭ 564 (+186.29%)
Mutual labels:  jni, ffi
eta-ffi
A command line tool to automate the generation of ffi import code for the bindings of various Java libraries.
Stars: ✭ 19 (-90.36%)
Mutual labels:  jvm, ffi
Stackparam
JVM agent to add method parameters to Java stack traces
Stars: ✭ 90 (-54.31%)
Mutual labels:  jvm, jni
Haskellr
The full power of R in Haskell.
Stars: ✭ 491 (+149.24%)
Mutual labels:  ffi, interoperability
Android Luajit Launcher
Android NativeActivity based launcher for LuaJIT, implementing the main loop within Lua land via FFI
Stars: ✭ 87 (-55.84%)
Mutual labels:  jni, ffi
Jni By Examples
🎇Fun Java JNI By Examples - with CMake and C++ (or C, of course!) ‼️ Accepting PRs
Stars: ✭ 99 (-49.75%)
Mutual labels:  jvm, jni
Boot Actuator
基于SpringBoot2.0 实现的jvm远程监工图形化工具,可以同时监控多个web应用,支持远程监控
Stars: ✭ 180 (-8.63%)
Mutual labels:  jvm
Sgx Lkl
SGX-LKL Library OS for running Linux applications inside of Intel SGX enclaves
Stars: ✭ 187 (-5.08%)
Mutual labels:  jvm
Blocknet
Official Blocknet cryptocurrency wallet
Stars: ✭ 179 (-9.14%)
Mutual labels:  interoperability
Rust Bindgen
Automatically generates Rust FFI bindings to C (and some C++) libraries.
Stars: ✭ 2,453 (+1145.18%)
Mutual labels:  ffi
Adi
ADI(Android Debug Intensive) 是通过 JVMTI 实现的 Android 应用开发调试的增强工具集,目前主要提供性能相关的监控能力。
Stars: ✭ 194 (-1.52%)
Mutual labels:  jni

inline-java: Call any JVM function from Haskell

CircleCI Build status

The Haskell standard includes a native foreign function interface (FFI). Using it can be a bit involved and only C support is implemented in GHC. inline-java lets you call any JVM function directly, from Haskell, without the need to write your own foreign import declarations using the FFI. In the style of inline-c for C and inline-r for calling R, inline-java lets you name any function to call inline in your code. It is implemented on top of the jni and jvm packages using a GHC Core plugin to orchestrate compilation and loading of the inlined Java snippets.

Example

Graphical Hello World using Java Swing:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where

import Data.Text (Text)
import Language.Java
import Language.Java.Inline

main :: IO ()
main = withJVM [] $ do
    message <- reflect ("Hello World!" :: Text)
    [java| {
      javax.swing.JOptionPane.showMessageDialog(null, $message);
      } |]

Building it

Requirements:

  • the Bazel build tool, and
  • the Nix package manager.

To build:

$ nix-shell --pure --run "bazel build //..."

To test:

$ nix-shell --pure --run "bazel test //..."

Building the safe interface

There is an experimental interface which catches common memory management mistakes at compile time. This interface currently needs a fork of GHC which supports the LinearTypes language extension. Both the GHC fork and the safe interface can be built with:

$ nix-shell --pure --run "bazel build //:inline-java --config ghc_9_0_1" shell-linear-types.nix

For examples of how to use the safe interface you can check the directory server and the wizzardo-http benchmark.

Further reading

Check the tutorial on how to use inline-java. If you want to know more about how it is implemented, look at our post on the plugin implementation.

There is also a post which gives an overview of the safe interface.

Debugging

The generated java output can be dumped to stderr by passing to GHC

-fplugin-opt=Language.Java.Inline.Plugin:dump-java

If -ddump-to-file is in effect, the java code is dumped to <module>.dump-java instead.

Troubleshooting

Build-time error package or class Blah does not exist

inline-java is going to invoke the javac compiler, and any classes used in java quotations need to be reachable via the CLASSPATH environment variable. For instance,

CLASSPATH=/path/to/my.jar:/some/other/path ghc --make program.hs

Run-time error ThreadNotAttached

Haskell threads need to be attached to the JVM before making JNI calls. Foreign.JNI.withJVM attaches the calling thread, and other threads can be attached with Foreign.JNI.runInAttachedThread. When the JVM calls into Haskell, the thread is already attached.

Run-time error ThreadNotBound

JNI calls need to be done from bound threads. The thread invoking the main function of a program is bound. Threads created with forkOS are bound. In other threads, Control.Concurrent.runInBoundThread can be used to run a computation in a bound thread.

Run-time error java.lang.NoClassDefFoundError

Classes might not be found at runtime if they are not in a folder or jar listed in the parameter -Djava.class.path=<classpath> passed to withJVM.

withJVM ["-Djava.class.path=/path/to/my.jar:/some/other/path"] $ do
  ...

Additionally, classes might not be found if a thread other than the one calling main is trying to use them. One solution is to have the thread calling main load all the classes in advance. Then the classes will be available in the JVM for other threads that need them. Calling Language.Java.Inline.loadJavaWrappers will have the effect of loading all classes needed for java quotations, which will suffice in many cases.

Another option is to set the context class loader of other threads, so they earn the ability to load classes on their own. This might work when the thread was attached to the JVM via the JNI, and the context class loader is just null.

loader <- [java| Thread.currentThread().getContextClassLoader() |]
            `Language.Java.withLocalRef` Foreign.JNI.newGlobalRef
...
forkOS $ runInAttachedThread $ do
  [java| { Thread.currentThread().setContextClassLoader($loader); } |]
  ...

Run-time error JVMException

Any java exception that goes from Java to Haskell will be wrapped as a value of type JVMException with a reference to the Java object representing the exception. The message and the stack trace of the exception can be retrieved from the exception object with more JNI calls, e.g.

\(JVMException e) -> [java| { $e.printStackTrace(); } |]

or with JNI.Foreign.showException.

License

Copyright (c) 2015-2016 EURL Tweag.

All rights reserved.

inline-java is free software, and may be redistributed under the terms specified in the LICENSE file.

Sponsors

         Tweag I/O              LeapYear

inline-java is maintained by Tweag I/O.

Have questions? Need help? Tweet at @tweagio.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].