Java Technology Home Page
A-Z Index

Java Developer Connection(SM)
Technical Tips

Downloads, APIs, Documentation
Java Developer Connection
Tutorials, Tech Articles, Training
Online Support
Community Discussion
News & Events from Everywhere
Products from Everywhere
How Java Technology is Used Worldwide
Print Button
 
Tech Tips archive

Tech Tips
September 07, 1999

This issue presents tips, techniques, and sample code for the following topics:


ERROR CHECKING WITH JNI

The JavaTM Native Interface (JNI) is a mechanism that enables Java to call functions written in other languages such as C++. JNI supports the use of existing code libraries.

One important aspect of JNI is error handling. Consider the following scenario. Suppose you have a Java application that passes a string to a C++ function, and the string is further processed in some way. The Java code looks like this:

public class err {
  static {
    System.loadLibrary("clib");
  }
  public static native void print(String s);
  public static void main(String args[]) {
    print("testing\n");
    print(null);
  }
}
In this example, print is a native method, that is, a method coded in some other language. It accepts a string argument. The implementation of this method is in a shared library, clib, that is loaded using System.loadLibrary when the Java program starts.

If you haven't used JNI before, you might wonder how to actually build a JNI-based application. The first step is to compile the Java program:

    $ javac err.java

Then you specify:

    $ javah -jni -o clib.cpp err
javah is a utility program that comes with the JDKTM software. It generates a C++ function prototype for the native method (function) found in the example above. In other words, if you have a Java program that calls a native function, you need to create a shared library containing a C++ implementation of that function. The function in the library needs to have a specific name or signature.

The implementation of the native function looks like this:

// clib.cpp


extern "C" {

  JNIEXPORT void JNICALL
  Java_err_print(JNIEnv* env, jclass c, jstring s) {
    if (s == NULL) {
      jclass exc =
        env->FindClass(
        "java/lang/NullPointerException");
      if (exc != NULL)
        env->ThrowNew(exc, "(in C++ code)");
      return;
    }
    const jbyte* str = env->GetStringUTFChars(s, NULL);
    if (str == NULL)
      return;
    printf("%s", str);
    env->ReleaseStringUTFChars(s, str);
  }

}
The 'extern "C"' is a C++ notation saying that the function should have a C external name instead of a C++ one. C++ compilers vary in the way they generate function names, due to differences in encoding of overloaded argument lists and so on. The function needs to have a C external name to ensure name consistency.

The sequence for building a shared library varies. For example, using Borland C++Builder 4, you specify:

$ bcc32 -c -Ic:/java/include 
  -Ic:/java/include/win32 clib.cpp
$ bcc32 -tWD clib.obj

where c:/java is the directory where the JavaTM 2 SDK is installed.

Once you've built the shared library, the program is run as usual:

    $ java err
There are several interesting aspects of the C++ function worth mentioning. One is that C++ doesn't automatically check for null pointers (references) in the way that the Java language does. If you pass a null string to the function and don't check for it, you'll probably get a "Segmentation violation" error.

So you must check whether the passed-in pointer is null. If it is, an exception is raised using the JNI ThrowNew function. This doesn't immediately trigger the exception, but propagates it to the calling Java program. The Java program treats it as a normal exception originating in Java code.

Once the pointer is checked, the program retrieves the passed-in string. Low-level C/C++ strings and Java strings are represented differently. Because of this, a JNI call is used to retrieve a pointer to the string characters. The string is in UTF-8 format, which is equivalent to 7-bit ASCII if (and only if) the string is composed entirely of 7-bit characters. Once the pointer is retrieved, the string can be printed using printf.

Here's another point about error handling. GetStringUTFChars returns NULL if it cannot allocate space to copy the string. If this JNI function does return NULL, then it has already raised a java.lang.OutOfMemoryError exception which will be propagated back to the Java program. In this case, there's no need to detect a NULL return value and raise an exception yourself.

Let's run the program. The output is:

testing
Exception in thread "main" 
  java.lang.NullPointerException:
    (in C++ code)
    at err.print(Native Method)
    at err.main(err.java:8)
The book "The Java Native Interface" by Sheng Liang covers the JNI in depth. For information about this book, see http://java.sun.com/docs/books/jni/index.html


USING JTEXTPANE

The JavaTM Foundation Classes (JFC) Project Swing classes JTextArea and JTextField are used as GUI components for text entry and text display. JEditorPane and JTextPane are also used for plain text, but they go further. You can use them for styled text, HTML, and RTF, or to insert arbitrary images and components into the pane.

JEditorPane is a subclass of JTextComponent, and you can use it to edit various kinds of content based on an "editor kit". An editor kit is a class that contains functions for text handling. For example, you can use it to perform standard text editor actions (such as, cut/copy/paste), or read text documents from a file. JTextPane is a subclass of JEditorPane, combined with StyledEditorKit. It allows you to edit styled text. Examples of styled text include underlining, italicized text, and inclusion of images and components in the text.

One application of JTextPane might be in a customized word processor, in particular, where you want special symbols to mark the text. Here is an example:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class MyComponent extends JComponent {
  public Dimension getPreferredSize() {
    return new Dimension(10, 15);
  }
  public Dimension getMaximumSize() {
    return getPreferredSize();
  }
  public void paint(Graphics g) {
    Dimension d = getSize();
    g.setColor(Color.red);
    g.fillRect(0, 0, d.width, d.height);
  }
}

public class panedemo {
  public static void main(String args[]) {
    JFrame frame = new JFrame("JTextPane demo");
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });

    final JTextPane pane = new JTextPane();
    pane.setPreferredSize(new Dimension(600, 400));

    JButton insbutton = new JButton("Insert Component");
    insbutton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        pane.insertComponent(new MyComponent());
        pane.requestFocus();
      }
    });

    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout());
    panel.add("North", insbutton);
    panel.add("Center", pane);

    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);
  }
}
This example sets up a JTextPane area, where you can enter text in a normal way. If you click on "Insert Component", an instance of a custom component is inserted into the text. In this example, the component is an instance of MyComponent. The component consists of a 10 x 15 red filled box, representing markup that you'd like to insert into the text. In other words, you can insert arbitrary components interspersed with text.

You can also use the InsertIcon method to insert images into the text pane.

Note: JDKTM 1.2.2 fixes a number of bugs, some of them associated with the use of JFC Swing. If you have trouble running the JTextPane example (or any other code that includes JFC Swing components), try running it with JDK 1.2.2.

— Note —

The names on the JDCSM mailing list are used for internal Sun MicrosystemsTM purposes only. To remove your name from the list, see Subscribe/Unsubscribe below.

— Feedback —

Comments? Send your feedback on the JDC Tech Tips to: jdc-webmaster

— Subscribe/Unsubscribe —

The JDC Tech Tips are sent to you because you elected to subscribe when you registered as a JDC member. To unsubscribe from JDC email, go to the following address and enter the email address you wish to remove from the mailing list:

http://developer.java.sun.com/unsubscribe.html

To become a JDC member and subscribe to this newsletter go to:

http://java.sun.com/jdc/

This issue of the JDC Tech Tips is written by Patrick Chan, the author of the publication "The JavaTM Developers Almanac".


Print Button
[ This page was updated: 21-Sep-2000 ]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Glossary | Feedback | A-Z Index
For more information on Java technology
and other software from Sun Microsystems, call:
(800) 786-7638
Outside the U.S. and Canada, dial your country's AT&T Direct Access Number first.
Sun Microsystems, Inc.
Copyright © 1995-2000 Sun Microsystems, Inc.
All Rights Reserved. Terms of Use. Privacy Policy.