JJava 1.0-a6 released · dflib/jjava · Discussion #101

Happy to announce a new a6 milestone of DFLib JJava 1.0. JJava is a Java / JVM kernel for Jupyter. This is a pretty significant update primarily focused on the "kernel-as-platform" aspect. What we mean by "platform" is how JJava allows running custom extensions, helps with creation of custom distributions and even bespoke JVM-based kernels. Key improvements:

Kernel modularity, lifecycle and flexible bootstrap

If you are planning to write your own special JVM Jupyter kernel or, maybe, build a custom distro of JJava with own collection of magics, it is now fairly simple to reuse JJava foundation libraries:

  1. BaseKernel and JavaKernel were refactored, separating kernel assembly logic into builders instead of hardcoding it in the constructor.
  2. Maven integration (%maven magic and friends) was moved into a submodule. JJava distro still bundles it of course, but your own custom assembly doesn't have to.
  3. Removed all the environment variables from either kernel or builders. Processing of the JJAVA_ vars is now done in the main class of the distro (outside the kernel). Downstream implementations can implement their own main, providing own configuration.
  4. Kernel lifecycle was redesigned and expanded. Now kernel has an onStartup() method in addition to the existing onShutdown(..), separating construction from startup. Not doing everything in constructor simplifies subclassing and testing.

Extensions improvements

  1. Expanded Extension lifecycle. It was aligned with that of its kernel. In addition to install(..), there's now an uninstall(..) method called from the kernel onShutdown(..). Thus extensions are properly stopped at the end, allowing them to clear statics and such. This is very useful for testing.
  2. Extensions are loaded from the extra startup classpath (defined by JJAVA_CLASSPATH). We fixed a bug that previously prevented this from happening.
  3. Extensions are now loaded using notebook ClassLoader. While this may look obscure, this feature is very consequential. Previously Extension.install(..) was serverly limited in what it could do, as it could only access the kernel classpath. So you'd resort to kernel.eval("...") calls to load something to a notebook. Now it can reference the full notebook classpath, so implementing complex logic is much easier.

Magics as objects

  1. Previously, "magics" where implemented as annotations on methods of arbitrary classes. Not anymore. Now LineMagic and CellMagic are interfaces. This makes managing them in the kernel and, more importantly, creating custom ones a much easier process. We rewrote all the built-in magics to follow the new contract and were able to get rid of tons of plumbing code.
  2. Magics now have auto-completion in notebooks (thanks to @maxandersen)
  3. The API for adding magics is very simple: kernel().getMagicsRegistry().registerCellMagic("mymagic", MyMagic.class). You can do it in the notebook or an Extension.

Logging

We fixed internal logging for better user experience:

  1. The kernel now outputs single-line logs formatted in the same way Jupyter formats its own logs. So the console output looks consistent
  2. Internal SLF4J is now properly configured in the distro to route logs to java.util.logging`, preventing startup console warnings
  3. Internal SLF4J jars are "relocated" into JJava package namespace, so there's no conflict if you'd like to use your own SLF4J in the notebook.

Licensing

Instead of the original MIT, we changed the license to Apache 2.0. Very little practical consequences for the users (both licenses are very permissive), but we are more confortable and familiar with Apache and will continue using this license.

Deprecation, bug fixes

There are other bug fixes, as well as deprecations of redundant magics (%jars, %addMavenDependency), as well as Ivy artifact syntax for %maven.