{"id":13546539,"url":"https://github.com/tweag/inline-java","last_synced_at":"2025-04-04T06:07:08.301Z","repository":{"id":46766303,"uuid":"71336225","full_name":"tweag/inline-java","owner":"tweag","description":"Haskell/Java interop via inline Java code in Haskell modules.","archived":false,"fork":false,"pushed_at":"2023-11-25T19:14:28.000Z","size":1108,"stargazers_count":231,"open_issues_count":11,"forks_count":15,"subscribers_count":48,"default_branch":"master","last_synced_at":"2025-03-28T05:08:59.236Z","etag":null,"topics":["ffi","haskell","interoperability","java","jni","jvm"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tweag.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-10-19T08:36:42.000Z","updated_at":"2025-02-14T23:09:45.000Z","dependencies_parsed_at":"2023-02-18T10:00:33.956Z","dependency_job_id":"da90875c-8614-4c4a-acc5-21776222ee09","html_url":"https://github.com/tweag/inline-java","commit_stats":{"total_commits":779,"total_committers":23,"mean_commits":"33.869565217391305","dds":0.4736842105263158,"last_synced_commit":"81768558746dede0850bb6e839d8efd5cae66bbb"},"previous_names":[],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tweag%2Finline-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tweag%2Finline-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tweag%2Finline-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tweag%2Finline-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tweag","download_url":"https://codeload.github.com/tweag/inline-java/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247128744,"owners_count":20888235,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ffi","haskell","interoperability","java","jni","jvm"],"created_at":"2024-08-01T12:00:39.836Z","updated_at":"2025-04-04T06:07:08.280Z","avatar_url":"https://github.com/tweag.png","language":"Haskell","readme":"# inline-java: Call any JVM function from Haskell\n\n[![Build](https://github.com/tweag/inline-java/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/tweag/inline-java/actions/workflows/build.yml)\n\nThe Haskell standard includes a native foreign function interface\n(FFI). Using it can be a bit involved and only C support is\nimplemented in GHC. `inline-java` lets you call any JVM function\ndirectly, from Haskell, without the need to write your own foreign\nimport declarations using the FFI. In the style of `inline-c` for\nC and `inline-r` for calling R, `inline-java` lets you name any\nfunction to call inline in your code. It is implemented on top of the\n[jni][jni] and [jvm][jvm] packages using a [GHC Core plugin][ghc-plugins]\nto orchestrate compilation and loading of the inlined Java snippets.\n\n[jni]: jni/\n[jvm]: jvm/\n[ghc-plugins]: https://downloads.haskell.org/~ghc/8.0.2/docs/html/users_guide/extending_ghc.html#core-plugins-in-more-detail\n\n## Example\n\nGraphical Hello World using Java Swing:\n\n```Haskell\n{-# LANGUAGE DataKinds #-}\n{-# LANGUAGE QuasiQuotes #-}\n{-# LANGUAGE OverloadedStrings #-}\nmodule Main where\n\nimport Data.Text (Text)\nimport Language.Java\nimport Language.Java.Inline\n\nmain :: IO ()\nmain = withJVM [] $ do\n    message \u003c- reflect (\"Hello World!\" :: Text)\n    [java| {\n      javax.swing.JOptionPane.showMessageDialog(null, $message);\n      } |]\n```\n\n## Building it\n\n**Requirements:**\n* the [Bazel][bazel] build tool, and\n* the [Nix][nix] package manager.\n\nTo build:\n\n```\n$ nix-shell --pure --run \"bazel build //...\"\n```\n\nTo test:\n\n```\n$ nix-shell --pure --run \"bazel test //...\"\n```\n\n[bazel]: https://bazel.build\n[nix]: http://nixos.org/nix\n\n## Using the safe interface\n\nThere is [an experimental interface][safe-inline-java] which catches\ncommon memory management mistakes at compile time via the\n[LinearTypes][linear-types-proposal] language extension.\n\nFor examples of how to use the safe interface you can check the\n[tests][tests], the [directory server][directory-server] example and the\n[wizzardo-http benchmark][wizzardo-http-benchmark].\n\n[directory-server]: examples/directory-server\n[linear-types-ghc]: https://github.com/tweag/ghc/tree/linear-types#ghc-branch-with-linear-types\n[linear-types-proposal]: https://github.com/tweag/ghc-proposals/blob/linear-types2/proposals/0000-linear-types.rst\n[safe-inline-java]: https://github.com/tweag/inline-java/blob/master/src/linear-types/Language/Java/Inline/Safe.hs\n[tests]: tests/linear-types/Language/Java/Inline/SafeSpec.hs\n[wizzardo-http-benchmark]: benchmarks/wizzardo-http\n\n## Further reading\n\nCheck the [tutorial][inline-java-tutorial] on how to use `inline-java`.\nIf you want to know more about how it is implemented, look at\n[our post][inline-java-plugin] on the plugin implementation.\n\nThere is also a post which gives an overview of the\n[safe interface][safe-interface-post].\n\n[inline-java-tutorial]: https://www.tweag.io/posts/2017-09-15-inline-java-tutorial.html\n[inline-java-plugin]: https://www.tweag.io/posts/2017-09-22-inline-java-ghc-plugin.html\n[safe-interface-post]: https://www.tweag.io/blog/2020-02-06-safe-inline-java\n\n## Debugging\n\nThe generated java output can be dumped to stderr by passing to GHC\n```\n-fplugin-opt=Language.Java.Inline.Plugin:dump-java\n```\n\nIf `-ddump-to-file` is in effect, the java code is dumped to\n`\u003cmodule\u003e.dump-java` instead.\n\n## Troubleshooting\n\n### Build-time error `package or class Blah does not exist`\n\n`inline-java` is going to invoke the `javac` compiler, and any classes\nused in `java` quotations need to be reachable via the `CLASSPATH`\nenvironment variable. For instance,\n```\nCLASSPATH=/path/to/my.jar:/some/other/path ghc --make program.hs\n```\n\n### Run-time error `ThreadNotAttached`\n\nHaskell threads need to be attached to the JVM before making JNI calls.\n`Foreign.JNI.withJVM` attaches the calling thread, and other threads\ncan be attached with `Foreign.JNI.runInAttachedThread`. When the JVM\ncalls into Haskell, the thread is already attached.\n\n### Run-time error `ThreadNotBound`\n\nJNI calls need to be done from bound threads. The thread invoking the\n`main` function of a program is bound. Threads created with `forkOS`\nare bound. In other threads, `Control.Concurrent.runInBoundThread`\ncan be used to run a computation in a bound thread.\n\n### Run-time error `java.lang.NoClassDefFoundError`\n\nClasses might not be found at runtime if they are not in a folder or\njar listed in the parameter `-Djava.class.path=\u003cclasspath\u003e` passed\nto `withJVM`.\n\n```Haskell\nwithJVM [\"-Djava.class.path=/path/to/my.jar:/some/other/path\"] $ do\n  ...\n```\n\nAdditionally, classes might not be found if a thread other than the one\ncalling `main` is trying to use them. One solution is to have the thread\ncalling `main` load all the classes in advance. Then the classes will\nbe available in the JVM for other threads that need them.\nCalling `Language.Java.Inline.loadJavaWrappers` will have the effect of\nloading all classes needed for `java` quotations, which will suffice in\nmany cases.\n\nAnother option is to set the context class loader of other threads,\nso they earn the ability to load classes on their own. This might\nwork when the thread was attached to the JVM via the JNI, and\nthe context class loader is just `null`.\n\n```Haskell\nloader \u003c- [java| Thread.currentThread().getContextClassLoader() |]\n            `Language.Java.withLocalRef` Foreign.JNI.newGlobalRef\n...\nforkOS $ runInAttachedThread $ do\n  [java| { Thread.currentThread().setContextClassLoader($loader); } |]\n  ...\n```\n\n### Run-time error `JVMException`\n\nAny java exception that goes from Java to Haskell will be wrapped\nas a value of type `JVMException` with a reference to the Java object\nrepresenting the exception. The message and the stack trace of the\nexception can be retrieved from the exception object with more JNI\ncalls, e.g.\n\n```Haskell\n\\(JVMException e) -\u003e [java| { $e.printStackTrace(); } |]\n```\nor with `JNI.Foreign.showException`.\n\n## License\n\nCopyright (c) 2015-2016 EURL Tweag.\n\nAll rights reserved.\n\ninline-java is free software, and may be redistributed under the terms\nspecified in the [LICENSE](LICENSE) file.\n\n## Sponsors\n\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n[![Tweag I/O](http://i.imgur.com/0HK8X4y.png)](http://tweag.io)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n[![LeapYear](http://i.imgur.com/t9VxRHn.png)](http://leapyear.io)\n\ninline-java is maintained by [Tweag I/O](https://www.tweag.io/).\n\nHave questions? Need help? Tweet at\n[@tweagio](http://twitter.com/tweagio).\n","funding_links":[],"categories":["Haskell"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftweag%2Finline-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftweag%2Finline-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftweag%2Finline-java/lists"}