ANU The Australian National University



____________________________________________________

[ANU] [DCS] [COMP2100/2500] [Description] [Schedule] [Lectures] [Labs] [Homework] [Assignments] [COMP2500] [Assessment] [PSP] [Java] [Reading] [Help]

____________________________________________________

COMP2100/2500
Lecture 26: The Java/C Interface

Summary

How to incorporate C code into Java projects.

Outline


Introduction

In the real world, we can't restrict ourselves to using nothing but Java (or whatever your favourite language is), no matter how much we'd like to.

One option is just to forget Java and write the system in another language, and this is often the right answer. Language choice should not just be a matter of personal preference, but should be carefully thought out for each project. By the time you finish your degree you should be familiar with several languages and capable of learning a new one in a few weeks.

But what if no language has all the libraries, capabilities and features that we need? We need to be able to make software components written in different languages work together. In practice, large systems often incorporate components written in several different languages.

Today we'll just look at one example of multi-language systems, making Java and C work together. In fact we'll only look at one direction: calling C code from Java.


JNI: The Java Native Interface

The Java Language Specification states that a method may be labelled as native (as you might label other methods abstract), which means that it is "implemented in platform-dependent code, typically written in another programming language such as C, C++, Fortran, or assembly language". But the JLS doesn't specify how to write your e.g. C code and how to connect the two pieces together.

The Java Native Interface (JNI) is Sun's way of connecting the implementations of native methods to its JVM. It specifies what you have to do in your C code to conform to the requirements of the JVM, and what you have to do in your Java code to tell the JVM to access the external code.

Understand that once we start going down the path to using native code we lose platform-independence. Our examples work with Sun's JDK on Linux. With any other combination of platform and JVM changes may (will?) be needed to both the C code and the Java code.


A simple example

Suppose you wanted to access the system clock so as to measure how long your program takes to perform different operations. This is easy to do in C, using a library routine clock() and a macro CLOCKS_PER_SEC, both declared in the standard header file time.h.

Here's the Java code:

public class Timer {

  private native int ticks();
  private native int ticksPerSecond();

  static {
    System.loadLibrary("timer");
  }
}

And here's the C code it calls.

#include <jni.h>
#include <time.h>
#include "Timer.h"

/* The external C part of a Java system stopwatch package */

JNIEXPORT jint JNICALL Java_Timer_ticks (JNIEnv *env,
                                         jobject obj) {
  return (jint) clock();
}

JNIEXPORT jint JNICALL Java_Timer_ticksPerSecond (JNIEnv *env,
                                              jobject obj) {
  return (jint) CLOCKS_PER_SEC;
}

Java routines such as ticks and ticksPerSecond are known as wrappers for the corresponding C routines.

Notice the phenomenon of name mangling -- names in the Java class (e.g. ticks()) have to be matched up with names in the C code (Java_Timer_ticks()). The JNI specification defines how this relationship works.

Because of the mangling, there's no shortcut to accessing C library or system calls. At least, we can stick private on the declaration.

What are the two parameters to the C functions? The first is a means of accessing the JVM if you need it. The second is a reference to this (the object in which the method was invoked). In this example we don't use either of the parameters.

In the Java class Timer (which you will use in this week's lab) there are also attributes for storing the number of 'ticks' when the clock was started and stopped, queries for returning the number of ticks and seconds between starting and stopping it, and commands to start and stop the clock. The excerpt above is just the bit that made the external calls -- those routines aren't even visible to the client.


Issues for external calls


Another example

Also from the lab, a routine to access an array element. First, the fragment of Java:

private native int c_item(int array,int index);

then the implementation in C:

/* Return the element at index i of the array a. */
JNIEXPORT jint JNICALL Java_IntegerArray_c_1item(JNIEnv *env,
                                 jobject obj, jint a, jint i){
  return (jint)(((int *)a)[i]);
}

Note the casts: first, a is cast to the type int *. Then, a is used as an array, and the i'th element is accessed. Finally, the result is cast back to a jint for use by the JVM.


Further thoughts


Implementation with Sun's JDK on Linux

Remember the previous warning that some of the details will be different for other operating systems and JVMs.


How to compile systems with external calls

To compile the system above you need to say

javac Timer.java
javah -jni Timer
gcc -Wall -shared -I/usr/local/java/include \
 -I/usr/local/java/include/linux timer.c -o libtimer.so

You'll be using this library in the lab. For the JVM to pick up libtimer.so you have to tell it where to look. This can be done including the current directory in the environment variable LD_LIBRARY_PATH. You can set variables on a per-command basis using the env command, e.g.:

env LD_LIBRARY_PATH=. java ArrayTester
which is how it's done in the supplied Makefile.

Calling Java from C

So far we have limited ourselves to calling C routines from Java. What if we want the C part of a system to be able to call Java routines?

Why would we want to do this? One reason is if we were trying to write an Java interface to something like GTK+ (a graphics library), where the main loop is running on the C side, and it needs to call Java routines when various events take place.

How do we do it? Not at all in this course. The details are given in Sun's JNI documentation.

____________________________________________________

[ANU] [DCS] [COMP2100/2500] [Description] [Schedule] [Lectures] [Labs] [Homework] [Assignments] [COMP2500] [Assessment] [PSP] [Java] [Reading] [Help]

____________________________________________________

Copyright © 2005, Richard Walker, The Australian National University
Version 2005.4, Sunday, 22 May 2005, 18:04:59 +1000
Feedback & Queries to comp2100@cs.anu.edu.au