It's free to join Gamasutra!|Have a question? Want to know who runs this site? Here you go.|Targeting the game development market with your product or service? Get info on advertising here.||For altering your contact information or changing email subscription preferences.
Registered members can log in here.Back to the home page.

Search articles, jobs, buyers guide, and more.

By Bernd Kreimeier
Gamasutra
June 11, 1999

This article originally appeared in the
July, 1999 issue of:


Letters to the Editor:
Write a letter
View all letters


Features

Listing 4. Java Proxy for a C++ object.

Content
Introduction

Talking to the Natives

Code Listing 1

Double Indirection

The Invocation API

Two Architectures

Code Listing 4

Encapsulated Native: A Magic Bullet?

For Further Info
Java for Games

Java Documentation

Tools & Products

Open Source

Sidebar
Java wraps native code in Prax War

id Adandons jave for Quake 3: Arena

Embedded Java in Vampire: The Masquerade

package jni;

class Proxy {

/** Handle to retrieve C++ object, native side. */

private final int handle;

/** Native LUT/constructor. */

private static final native int newNative();

/** Constructor, gets/creates a handle to a native object. */

public Proxy() {

handle = newNative();

}

/** Simplified fieldID. */

private final int SOME_FIELD = 1;

/** Accessor hiding the simplified retrieval. */

public final float getSomeField() {

return getFloat( handle, SOME_FIELD );

}

/** Method that saves us many retrieval() functions. */

private final native float getFloat( int handle, int field );

}

// Minimal C++ object, and JNI glue.

class NativeObject {

public: NativeObject( jobject owner ) {

this.owner = owner;

}

public: jobject getOwner() {return owner;}

public: float someField;

public: jobject owner;

};

#include <jni.h>

extern jclass InvalidProxyOwnerException;

extern jclass InvalidFieldIndexException;

// extern "C" implied

JNIEXPORT jint JNICALL Java_jni_Proxy_getFloat

( JNIEnv* env,

jobject owner)

{

return (jint) (new NativeObject(owner));

}

JNIEXPORT jfloat JNICALL Java_jni_Proxy_getFloat

( JNIEnv* env,

jobject owner,

jint handle,

jint field )

{

// Truly dirty. Trust on blank finals.

NativeObject* obj = (NativeObject*)handle;

if ( obj->getOwner() != owner )

(*env)->ThrowNew(env, InvalidProxyOwnerException, "access attempted by non-owner");

switch( field ) {

// Enums to be kept in sync manually...

case 1: return obj->someField;

default:

(*env)->ThrowNew(env,InvalidFieldIndexException,

"access attempted by non-existing field");

}

}

}

Of course, if you want to avoid switch statements in the native method, or you want to wrap C++ accessor methods instead of exposing fields, you could also implement the public Java accessor as a native method. Incidentally, maintaining the same set of enums in Java and native code is one of the problems that does not yet seem to have an elegant solution. If you are using a look-up table to retrieve pointers for handles, the jobject argument might already be sufficient.

A native proxy implemented as a C++ object or C struct could cache a global jobject reference along with method IDs and field IDs. Caching actual game data inside native code means that your proxies have to be kept synchronized with the master objects, or you will end up with consistency errors that are very difficult to track down.

Alternatively, you could encapsulate the results or take a snapshot of a native object's state in a new Java object created in native code, using the JNI function NewObject() to call a Java constructor. This approach works even better if your native and Java modules communicate by passing event descriptor objects to a queue.


Encapsulated Native: A Magic Bullet?


join | contact us | advertise | write | my profile
news | features | companies | jobs | resumes | education | product guide | projects | store



Copyright © 2003 CMP Media LLC

privacy policy
| terms of service