UP | HOME

Support via Liberapay, GitHub or PayPal

Java Source Code Blocks in Org Mode

Table of Contents

Org Mode support for Java

Introduction

Java is a general purpose, object oriented computer language. When a java source code block is evaluated, the code is written as a java class, compiled to a class file, and executed.

Requirements and Setup

Add Java Support to Babel

  1. Install the java compiler and runtime environment
  2. Configure java source code blocks for Org mode by adding the appropriate dotted pair to org-babel-load-languages
(org-babel-do-load-languages
 'org-babel-load-languages
 '((java . t)))

Configure Defaults

Default behavior for ob-java differs from most babel languages in two ways:

  1. ob-java defaults to scripting mode (:results output)
  2. ob-java writes tempfiles to the current directory instead of the babel temporary directory

Both defaults are set in org-babel-default-header-args:java, and can be changed by modifying that variable. To change both defaults to make ob-java consistent with the rest of babel, add this to your init file after initializing babel:

(nconc org-babel-default-header-args:java
       '((:dir . nil)
         (:results . value))

Note that this adds the overrides to the end of the list. This is important because the list is processed in order and the last value is used.

Org Mode Features for Java Source Code Blocks

Header Arguments

Java source code blocks accept the following header arguments. All headers arguments are optional.

:dir
specify which directory to write source and class files (default is the current directory)
:classname
fully qualified classname (see Class and Main Method Definitions)
:imports
a list of classes to add as imports (see Imports)
:cmpflag
pass command line arguments to the java compiler
:cmdline
pass command line arguments to the java runtime
:cmdarg
pass command line arguments to the source code block (see Arguments)

Simple Example

This is hello world:

#+begin_src java :results output
  public class Main {
      public static void main(String[] args) {
          System.out.print("hello, world");
      }
  }
#+end_src

Class and Main Method Definitions

It is not necessary to include the class statement or define a main method. ob-java will wrap a source code block in boilerplate class and main method definitions if they are omitted. If :classname and the class definition in the source code block are both omitted, the class will be named Main.

This is exactly equivalent to the above hello world:

#+begin_src java :results output
  System.out.print("hello, world");
#+end_src

Classname and Package Name

The package and classname of a class can be defined in the source code block or by the :classname header argument or both. If they are defined in both places, then they must match.

:classname can just be a classname, like Greeter or it could contain the package name, such as com.package.Greeter. This example names the class Greeter and puts it in the com.package package.

#+begin_src java :results output :classname com.package.Greeter
  System.out.print("hello, world");
#+end_src

Source Files and Tangling

By default, when a source code block is evaluated the source files and class files are written directly to babel's temporary directory. If a package was specified, it is removed so that babel doesn't have to create subdirectories under its temporary directory. In the above com.package.Greeter example, the default behavior is to remove the com.package and write Greeter.java to babel's temporary directory.

If the :dir header argument is specified, then source files are written within package directories under the specified directory and package names are preserved. In the com.package.Greeter example, if the :dir header is given, the package is preserved.

Tangling works as expected. Package is always preserved when tangling.

Return values

Babel source code blocks can either return a value (this is called functional mode and can be chosen with :results output) or output printed by the source code block (this is called scripting mode and can be chosen with :results value).

To preserve legacy behavior, java source code blocks use scripting mode by default. To switch to functional mode you have to specify :results value in the header.

We've already seen hello world in scripting mode, but here it is again:

#+begin_src java :results output
  System.out.print("hello, world");
#+end_src

This is what hello world looks like in functional mode:

#+begin_src java :results value
  return "hello, world";
#+end_src

Return a List

This example returns a list using scripting mode. For the result to show up as a list in the org buffer, notice that the :results must be set to raw list.

#+begin_src java :results output raw list
  System.out.println("1");
  System.out.println("2");
#+end_src

This is the output:

#+RESULTS:
- 1
- 2

Returning a list in functional mode is straightforward. Simply say :results will return a list and then return a List. This example results in identical output to the previous example.

#+begin_src java :results value list
  List<Integer> a = Arrays.asList(1, 2);
  return a;
#+end_src

Another way to achieve the same result is to use an array, as in the following example.

#+begin_src java :results value list
  Integer[] a = {4, 1};
  return a;
#+end_src

Return a Table

This example returns a table using scripting mode. Notice that the output includes pipe characters to build the table, and the :results header specifies the type is raw.

#+begin_src java :results output raw
  System.out.println("|1|2|3");
  System.out.println("|4|5|6");
#+end_src

This is the output:

#+RESULTS:
| 1 | 2 | 3 |
| 4 | 5 | 6 |

The same output is achieved with the following:

#+begin_src java :results value table
    List<List<Integer>> a = Arrays.asList(Arrays.asList(1, 2, 3),
                                          Arrays.asList(4, 5, 6));
    return a;
#+end_src

Return a Table with Headers

This example returns a table with headers using scripting mode. The hline is created the same way as it is created while editing an org table, by inserting a |- at the start of a line inside the table.

#+begin_src java :results output raw
  System.out.println("|col1|col2|col3");
  System.out.println("|-");
  System.out.println("|1|2|3");
  System.out.println("|4|5|6");
#+end_src

This is the output:

#+RESULTS:
| col1 | col2 | col3 |
|------+------+------|
|    1 |    2 |    3 |
|    4 |    5 |    6 |

The same output is achieved with the following. Note that the hline is represented with a null in the table, and that we had to change to using a List<Object> since the header row items are String but the rest of the data items are int.

#+begin_src java :results value table
  List<List<Object>> a = Arrays.asList(Arrays.asList("col1", "col2", "col3"),
                                       null,
                                       Arrays.asList(1, 2, 3),
                                       Arrays.asList(4, 5, 6));
  return a;
#+end_src

Variables and Arguments

Java source code blocks can take input from the org buffer as variables or arguments. Arguments are more limited and are supported to preserve legacy behavior. Use of variables is preferred.

Variables

Pass variables with the :var header. Variable types are inferred. This example accepts two integers and adds them:

#+begin_src java :var a=1 b=2 :results output
  System.out.print("sum: " + (a+b));
#+end_src

This example passes a string variable:

#+begin_src java :var a="some string" :results output
  System.out.print(a);
#+end_src

Multi-line string literals are not supported in java. To pass a multi-line string as a variable, embed newline characters in a single-line string.

Java source code blocks can accept elisp list or vector. In either case the variables are typed as java.util.List. In this example a is a List<String>.

#+begin_src java :var a='("one" "two") :results output
  System.out.print(a.get(0) + " " + a.get(1));
#+end_src

This example accepts a named list taken from the org buffer. Note that lists appear to be a table with one item in each row. a is a List<List<String>> here, where the outside list contains rows and the inside list contains columns. See Imports to find out how to import List, or why we didn't do it here.

#+name: some-list
- one
- two

#+begin_src java :var a=some-list :results output
  System.out.print(a.get(0).get(0) + " " + a.get(1).get(0));
#+end_src

Another way to accept a list is to slice it when it is assigned. The [,0] in this examples selects the first column of each row so that a is a List<String>.

#+name: some-list
- one
- two

#+begin_src java :var a=some-list[,0] :results output
  System.out.print(a.get(0) + " " + a.get(1));
#+end_src

The following example transposes and doubles the values in a 2x2 table. a is available as a List<List<Integer>>.

#+name: some-table
| 1 | 2 |
| 3 | 4 |

#+begin_src java :var a=some-table :results output
  System.out.println((a.get(0).get(0)*2) + " " + (a.get(1).get(0)*2));
  System.out.println((a.get(0).get(1)*2) + " " + (a.get(1).get(1)*2));
#+end_src

Arguments

All arguments are typed as strings.

Here is an example that passes an argument:

#+begin_src java :results output :cmdargs "argument"
  System.out.print(args[0]);
#+end_src

Pass multiple arguments by separating them by spaces.

#+begin_src java :results output :cmdargs "two arguments"
  System.out.print(args[0] + " " + args[1]);
#+end_src

In order to pass a string with spaces, quote the string twice and escape the inner quotes.

#+begin_src java :results output :cmdargs "\"this is one argument\""
  System.out.print(args[0]);
#+end_src

Imports

Imports can be added at the top of source code blocks or added using the :imports header argument. Imports are allowed in source code blocks that omit the boilerplate class and main method definitions.

The following classes can be used without explicitly importing them:

  • java.util.List
  • java.util.Arrays
  • java.io.BufferedWriter
  • java.io.FileWriter
  • java.io.IOException

This example imports a class using the :imports header argument:

#+begin_src java :results output :imports java.util.Base64
  byte[] encoded = Base64.getEncoder().encode("encoded message".getBytes());
  String decoded = new String(Base64.getDecoder().decode(encoded));
  System.out.print(String.format("encoded=%s, decoded=%s", new String(encoded), decoded));
#+end_src

This is exactly equivalent, but specifies the import within the source code block:

#+begin_src java :results output
  import java.util.Base64;
  byte[] encoded = Base64.getEncoder().encode("encoded message".getBytes());
  String decoded = new String(Base64.getDecoder().decode(encoded));
  System.out.print(String.format("encoded=%s, decoded=%s", new String(encoded), decoded));
#+end_src

Source and Class File Locations

Most babel languages write the source code block to a file in the babel temporary directory and compile there, but originally ob-java used the current directory (the directory containing the org file) instead.

This may be because the java compiler requires the source file to be under java package subdirectories and the babel temporary directory doesn't allow for subdirectories. A benefit of using the current directory is that it allows source code blocks to depend on classes defined in other blocks. When writing to the babel temporary directory, all source code blocks must be independent.

ob-java can write to the babel temporary directory now, but by default it uses the current directory to preseve the previous behavior. It is possible to change this behavior locally or globally. This is a source block that will override the default and compile in the babel temporary directory:

#+begin_src java :dir 'nil :classname com.package.Greeter
  System.out.print("hello, world");
#+end_src

To change the default behavior see Configure Defaults.

Tramp Support

If the org file containing the java source code block is on a remote machine and :dir is either not set (it defaults to the current directory, which would be remote in this case) or is set to a remote path, then the source files will be written to the remote machine, compiled by the remote java compiler and run by the remote java runtime.

If the org file is remote but :dir is set to a local directory, the source file will be written to the local machine and local java binaries will be used.

Non-executable Classes

If a source code block includes methods but doesn't include a main method, a generic main method will be added. This prevents the source code block from erroring when evaluated.

Sessions

There is no support for sessions

Current Issues

TODO Formatting shouldn't be required to return a table in scripting mode

Documentation from the orgmode.org/worg/ website (either in its HTML format or in its Org format) is licensed under the GNU Free Documentation License version 1.3 or later. The code examples and css stylesheets are licensed under the GNU General Public License v3 or later.