Java: Preventing a child window's close operation from exiting the app.

I included a second JFrame in NetBeans, which I used as a child window. When the child window was closed, all windows were closed. I finally figured out that the default close operation needed to be either HIDE_ON_CLOSE or DISPOSE_ON_CLOSE. The default in Java is HIDE_ON_CLOSE, but in NetBeans is EXIT_ON_CLOSE.

I first changed this property in the main window code that invokes the child window, but then I looked at the Properties page for the child window. "defaultCloseOperation" is the first property. "DISPOSE" can be selected here.

From Sun Java Documentation

setDefaultCloseOperation

public void setDefaultCloseOperation(int operation)
Sets the operation that will happen by default when the user initiates a "close" on this frame. You must specify one of the following choices:

  • DO_NOTHING_ON_CLOSE (defined in WindowConstants): Don't do anything; require the program to handle the operation in the windowClosing method of a registered WindowListener object.
  • HIDE_ON_CLOSE (defined in WindowConstants): Automatically hide the frame after invoking any registered WindowListener objects.
  • DISPOSE_ON_CLOSE (defined in WindowConstants): Automatically hide and dispose the frame after invoking any registered WindowListener objects.
  • EXIT_ON_CLOSE (defined in JFrame): Exit the application using the System exit method. Use this only in applications.

The value is set to HIDE_ON_CLOSE by default.

Link to Random Image Password Generation

Captchas.net

Reducing redundant code by wrapping JNI functions.

My HelloWorldNative.c, with the "nativePrintObject" function reduced by wrapping the object and integer field retrieval:


JNIEXPORT void JNICALL Java_helloworld_Main_nativePrintObject(JNIEnv *env, jobject ths, jobject wsv)
{
jint ipAddress;
jstring jPageVisited;
char *pageVisited;
jstring jRefererURL;
char *refererURL;
jobject ipObject;

ipAddress = getIntegerField(env, wsv, "ipAddress");
printf(" wsv.ipAddress = %d.%d.%d.%dn",
( ipAddress & 0xff000000 ) >> 24,
( ipAddress & 0x00ff0000 ) >> 16,
( ipAddress & 0x0000ff00 ) >> 8,
ipAddress & 0x000000ff);

if(!(jPageVisited = getStringField(env, wsv, "pageVisited"))) {
return;
}

pageVisited = (*env)->GetStringUTFChars(env, jPageVisited, 0);

if(!pageVisited) {
return;
}
printf(" wsv.pageVisted = %sn", pageVisited);
(*env)->ReleaseStringUTFChars(env, jPageVisited, pageVisited);

if(!(jRefererURL = getStringField(env, wsv, "refererURL"))) {
return;
}

if(!(refererURL = (*env)->GetStringUTFChars(env, jRefererURL, 0))) {
return;
}
printf(" wsv.refererURL = %sn", refererURL);
(*env)->ReleaseStringUTFChars(env, jRefererURL, refererURL);

if(!(ipObject = getObjectField(env, wsv, "ipAddr", "helloworld", "IPAddress"))) {
return;
}

printf(" wsv.ipAddr = %d.%d.%d.%dn",
getIntegerField(env, ipObject, "byte1"),
getIntegerField(env, ipObject, "byte2"),
getIntegerField(env, ipObject, "byte3"),
getIntegerField(env, ipObject, "byte4")
);
}

jniUtils.h, the header for the JNI wrapper:


/*
* File: jniUtils.h
* Author: thomas
*
* Created on February 10, 2007, 5:30 PM
*/
#include <jni.h>

#ifndef _jniUtils_H
#define _jniUtils_H

#ifdef __cplusplus
extern "C" {
#endif
jint getIntegerField(JNIEnv *env, jobject ths, char *fieldName);
void putIntegerField(JNIEnv *env, jobject ths, char *fieldName, jint ji);
jstring getStringField(JNIEnv *env, jobject ths, char *fieldName);
jobject getObjectField(JNIEnv *env, jobject ths, char *fieldName,
char *objectPackage, char *objectClass);

#ifdef __cplusplus
}
#endif


#endif /* _jniUtils_H */

jniUtils.c, the wrapper for the JNI C interface. Note that not all types have been implemented. Also, error checking may not be performed in all scenarios. See that the "signature" for objects is broken up into package and class name.


#include <stdlib.h>
#include <string.h>
#include "jniUtils.h"

jint getIntegerField(JNIEnv *env, jobject ths, char *fieldName)
{
jclass c;
jfieldID fid;

c = (*env)->GetObjectClass(env, ths);
fid = (*env)->GetFieldID(env, c, fieldName, "I");
return (*env)->GetIntField(env, ths, fid);
}

void putIntegerField(JNIEnv *env, jobject ths, char *fieldName, jint ji)
{
jclass c;
jfieldID fid;

c = (*env)->GetObjectClass(env, ths);
fid = (*env)->GetFieldID(env, c, fieldName, "I");
(*env)->SetIntField(env, ths, fid, ji);
}

jstring getStringField(JNIEnv *env, jobject ths, char *fieldName)
{
jclass c;
jfieldID fid;

return (jstring) getObjectField(env, ths, fieldName, "java/lang", "String");
}

jobject getObjectField(JNIEnv *env, jobject ths, char *fieldName,
char *objectPackage, char *objectClass)
{
char *objectSignature;
jclass c;
jfieldID fid;
jobject objectField = 0;

objectSignature = (char *) malloc(strlen(objectPackage) + strlen(objectClass) + 10);

strcpy(objectSignature, "L");
strcat(objectSignature, objectPackage);
strcat(objectSignature, "/");
strcat(objectSignature, objectClass);
strcat(objectSignature, ";");
c = (*env)->GetObjectClass(env, ths);
fid = (*env)->GetFieldID(env, c, fieldName, objectSignature);

if(!fid) {
return 0;
}
objectField = (*env)->GetObjectField(env, ths, fid);

free(objectSignature);

return objectField;
}

Passing an object including java Objects to a C library.

Very similar to including Java Strings:
The passed object, WebSiteVisit:

package helloworld;

/**
*
* @author thomas
*/
public class WebSiteVisit {
/** URL of the web page that linked user to this one */
public String refererURL;
public String pageVisited;
public int ipAddress;
IPAddress ipAddr;

/** Creates a new instance of WebSiteVisit */
public WebSiteVisit() {
}

public WebSiteVisit(String referer, String page, int ip) {
this.refererURL = referer;
this.ipAddress = ip;
this.pageVisited = page;
this.ipAddr = new IPAddress(ip);
}
}

The embedded object, IPAddress:

package helloworld;

/**
*
* @author thomas
*/
public class IPAddress {
public int byte1, byte2, byte3, byte4;
/** Creates a new instance of IPAddress */
public IPAddress() {
}
public IPAddress(int address) {
byte1 = (address & 0xff000000) >> 24;
byte2 = (address & 0x00ff0000) >> 16;
byte3 = (address & 0x0000ff00) >> 8;
byte4 = address & 0x000000ff;
}

}

The C source to the dynamic library, including the IPAddress object access.

JNIEXPORT void JNICALL Java_helloworld_Main_nativePrintNumber
(JNIEnv *env, jobject obj, jint ji)
{
jfieldID fid;
jint version;
jclass c;
c = (*env)->GetObjectClass(env, obj);
fid = (*env)->GetFieldID(env, c, "version_number", "I");
version = (*env)->GetIntField(env, obj, fid);
(*env)->SetIntField(env, obj, fid, ji*ji);
printf("::: %d, %dn", fid, version);
hello_number(ji);
}
JNIEXPORT void JNICALL Java_helloworld_Main_nativePrintObject
(JNIEnv *env, jobject ths, jobject wsv)
{
jfieldID fid;
jint ipAddress;
jstring jPageVisited;
char *pageVisited;
jstring jRefererURL;
char *refererURL;
jclass c;
jobject ipObject;
jclass ipObjectClass;
jint byte1, byte2, byte3, byte4;

c = (*env)->GetObjectClass(env, wsv);

.
.
.

fid = (*env)->GetFieldID(env, c, "ipAddr", "Lhelloworld/IPAddress;");
if(!fid) {
return;
}
ipObject = (*env)->GetObjectField(env, wsv, fid);
ipObjectClass = (*env)->GetObjectClass(env, ipObject);

fid = (*env)->GetFieldID(env, ipObjectClass, "byte1", "I");
byte1 = (*env)->GetIntField(env, ipObject, fid);

fid = (*env)->GetFieldID(env, ipObjectClass, "byte2", "I");
byte2 = (*env)->GetIntField(env, ipObject, fid);

fid = (*env)->GetFieldID(env, ipObjectClass, "byte3", "I");
byte3 = (*env)->GetIntField(env, ipObject, fid);

fid = (*env)->GetFieldID(env, ipObjectClass, "byte4", "I");
byte4 = (*env)->GetIntField(env, ipObject, fid);

printf("wsv.ipAddr = %d.%d.%d.%dns", byte1, byte2, byte3, byte4);
}

Passing an object including java Strings to a C library using JNI.

Main.java, the class which calls the C function, passing the WebSiteVisit object

/**
*
* @author thomas
*/
public class Main {

private native void nativePrintObject(WebSiteVisit wsv);
/** Creates a new instance of Main */
public Main() {
}

static {
System.load("/home/thomas/testlib/HelloWorldNative/dist/HelloWorldNative.so");
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Main me = new Main();
WebSiteVisit a, b;
a = new WebSiteVisit("index.html", "subpage.html", 0x32389283);
b = new WebSiteVisit("subpage.html", "pagetwo.html", 0x32399283);

me.nativePrintObject(a);
me.nativePrintObject(b);
}

}

WebSiteVisit.java, the passed object:

package helloworld;

/**
*
* @author thomas
*/
public class WebSiteVisit {
/** URL of the web page that linked user to this one */
public String refererURL;
public String pageVisited;
public int ipAddress;

/** Creates a new instance of WebSiteVisit */
public WebSiteVisit() {
}

public WebSiteVisit(String referer, String page, int ip) {
this.refererURL = referer;
this.ipAddress = ip;
this.pageVisited = page;
}

}

The c function which receive the object:

JNIEXPORT void JNICALL Java_helloworld_Main_nativePrintObject
(JNIEnv *env, jobject ths, jobject wsv)
{
jfieldID fid;
jint ipAddress;
jstring jPageVisited;
char *pageVisited;
jstring jRefererURL;
char *refererURL;
jclass c;

c = (*env)->GetObjectClass(env, wsv);
fid = (*env)->GetFieldID(env, c, "ipAddress", "I");
ipAddress = (*env)->GetIntField(env, wsv, fid);
printf(" wsv.ipAddress = %d.%d.%d.%dn",
( ipAddress & 0xff000000 ) >> 24,
( ipAddress & 0x00ff0000 ) >> 16,
( ipAddress & 0x0000ff00 ) >> 8,
ipAddress &amp; 0x000000ff);
fid = (*env)->GetFieldID(env, c, "pageVisited", "Ljava/lang/String;");
if(!fid) {
return;
}
jPageVisited = (*env)->GetObjectField(env, wsv, fid);
pageVisited = (*env)->GetStringUTFChars(env, jPageVisited, 0);

if(!pageVisited) {
return;
}
printf(" wsv.pageVisted = %sn", pageVisited);

(*env)->ReleaseStringUTFChars(env, jPageVisited, pageVisited);

fid = (*env)->GetFieldID(env, c, "refererURL", "Ljava/lang/String;");
if(!fid) {
return;
}
jRefererURL = (*env)->GetObjectField(env, wsv, fid);
refererURL = (*env)->GetStringUTFChars(env, jRefererURL, 0);
printf(" wsv.refererURL = %sn", refererURL);

(*env)->ReleaseStringUTFChars(env, jRefererURL, refererURL);
}

Passing an object including java Strings to a C library.

Main.java, the class which calls the C function, passing the WebSiteVisit object

/**
*
* @author thomas
*/
public class Main {

private native void nativePrintObject(WebSiteVisit wsv);
/** Creates a new instance of Main */
public Main() {
}

static {
System.load("/home/thomas/testlib/HelloWorldNative/dist/HelloWorldNative.so");
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Main me = new Main();
WebSiteVisit a, b;
a = new WebSiteVisit("index.html", "subpage.html", 0x32389283);
b = new WebSiteVisit("subpage.html", "pagetwo.html", 0x32399283);

me.nativePrintObject(a);
me.nativePrintObject(b);
}

}

WebSiteVisit.java, the passed object:

package helloworld;

/**
*
* @author thomas
*/
public class WebSiteVisit {
/** URL of the web page that linked user to this one */
public String refererURL;
public String pageVisited;
public int ipAddress;

/** Creates a new instance of WebSiteVisit */
public WebSiteVisit() {
}

public WebSiteVisit(String referer, String page, int ip) {
this.refererURL = referer;
this.ipAddress = ip;
this.pageVisited = page;
}

}

The c function which receive the object:

JNIEXPORT void JNICALL Java_helloworld_Main_nativePrintObject
(JNIEnv *env, jobject ths, jobject wsv)
{
jfieldID fid;
jint ipAddress;
jstring jPageVisited;
char *pageVisited;
jstring jRefererURL;
char *refererURL;
jclass c;

c = (*env)->GetObjectClass(env, wsv);
fid = (*env)->GetFieldID(env, c, "ipAddress", "I");
ipAddress = (*env)->GetIntField(env, wsv, fid);
printf(" wsv.ipAddress = %d.%d.%d.%dn",
( ipAddress & 0xff000000 ) >> 24,
( ipAddress & 0x00ff0000 ) >> 16,
( ipAddress & 0x0000ff00 ) >> 8,
ipAddress & 0x000000ff);
fid = (*env)->GetFieldID(env, c, "pageVisited", "Ljava/lang/String;");
if(!fid) {
return;
}
jPageVisited = (*env)->GetObjectField(env, wsv, fid);
pageVisited = (*env)->GetStringUTFChars(env, jPageVisited, 0);

if(!pageVisited) {
return;
}
printf(" wsv.pageVisted = %sn", pageVisited);

(*env)->ReleaseStringUTFChars(env, jPageVisited, pageVisited);

fid = (*env)->GetFieldID(env, c, "refererURL", "Ljava/lang/String;");
if(!fid) {
return;
}
jRefererURL = (*env)->GetObjectField(env, wsv, fid);
refererURL = (*env)->GetStringUTFChars(env, jRefererURL, 0);
printf(" wsv.refererURL = %sn", refererURL);

(*env)->ReleaseStringUTFChars(env, jRefererURL, refererURL);
}

Java Native Interface - setting and retrieving object fields

My reference: Java Native Interface

This table was specifically handy:

Java Type JNI Type machine dependent
C/C++ typedef
Signature Call...Method
Get...Field
boolean jboolean unsigned char Z Boolean
byte jbyte signed char B Byte
char jchar unsigned short C Char
short jshort short S Short
int jint int I Int
long jlong long J Long
float jfloat float F Float
double jdouble double D Double
void void V Void
nonprimitive jobject *... L...; Object


Examples

method definition signature
int m1 () ()I
double m2 (long l, char c) (JC)D
void m3 (String s, int[] a) (Ljava/lang/String;[I)V
String m4 (boolean b) (Z)Ljava/lang/String;
Object m4 (BigDecimal b) (Ljava/math/BigDecimal;)Ljava/lang/Object;

My code testing implementing this field access:

HelloWorldNative.c (builds into .so linked from Java)

JNIEXPORT void JNICALL Java_helloworld_Main_nativePrintNumber
(JNIEnv *env, jobject obj, jint ji)
{
jfieldID fid;
jint version;
jclass c;
c = (*env)->GetObjectClass(env, obj);
fid = (*env)->GetFieldID(env, c, "version_number", "I");
version = (*env)->GetIntField(env, obj, fid);
(*env)->SetIntField(env, obj, fid, ji*ji);
printf("::: %d, %dn", fid, version);
hello_number(ji);
}

My Main.java, which the version_number integer field:

package helloworld;

/**
*
* @author thomas
*/
public class Main {
public int version_number;
private native void nativePrint();
private native void nativePrintNumber(int i);
/** Creates a new instance of Main */
public Main() {
version_number = 5;
}

static {
System.load("/home/thomas/testlib/HelloWorldNative/dist/HelloWorldNative.so");
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Main me = new Main();
me.nativePrint();
me.nativePrintNumber(2);
me.nativePrintNumber(5);
me.nativePrintNumber(3);
// TODO code application logic here
}
}

Linking a static library to Java using JNI

Beginning JNI Linux tutorial for Netbeans

Once I had accomplished the above with complete success, I extended the experiment by linking my static library (.a) to the dynamic library, and calling the static library function from the dynamic library function.

My HelloWorldNative.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class helloworld_Main */

#ifndef _Included_helloworld_Main
#define _Included_helloworld_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: helloworld_Main
* Method: nativePrint
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_helloworld_Main_nativePrint
(JNIEnv *, jobject);

/*
* Class: helloworld_Main
* Method: nativePrintNumber
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_helloworld_Main_nativePrintNumber
(JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif

My HelloWorldNative.c:
#include <jni.h>

#include <stdio.h>

#include "../HelloWorldNative.h"

void hello();
void hello_number(int i);

JNIEXPORT void JNICALL Java_helloworld_Main_nativePrint(JNIEnv *env, jobject obj)
{
hello();
}

JNIEXPORT void JNICALL Java_helloworld_Main_nativePrintNumber
(JNIEnv *env, jobject obj, jint ji)
{
hello_number(ji);
}

My Main.java:
/*
* Main.java
*
* Created on February 9, 2007, 3:48 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/

package helloworld;

/**
*
* @author thomas
*/
public class Main {

private native void nativePrint();
private native void nativePrintNumber(int i);
/** Creates a new instance of Main */
public Main() {
}

static {
System.load("/home/thomas/src/c/testlib/HelloWorldNative/dist/HelloWorldNative.so");
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Main me = new Main();
me.nativePrint();
me.nativePrintNumber(2);
me.nativePrintNumber(5);
// TODO code application logic here
}

}