Programming Tutorials Browser Tutorials Articles Struts Tutorials Hibernate Tutorials

  Tutorial: Integrate Java and C++ with Jace

Integrate Java and C++ with Jace

Tutorial Details:

Integrate Java and C++ with Jace
Integrate Java and C++ with Jace
By: By Toby Reyelts
The open source Jace toolkit helps simplify JNI programming
f you didn't know better, you might believe that Sun Microsystems had designed the JNI (Java Native Interface) API with the goal of discouraging Java developers from using it. After all, type safety is nearly nonexistent, error checking is absent, and making a single Java method call requires four or more JNI calls. In addition, you have to manage JNIEnv pointers, you can't use JNI references from multiple threads, you must choose between nine different functions for each possible operation, and retrieving exception information is difficult. I've probably left out a few other problems as well.
Many of these limitations result from JNI's binding to the C language, which itself suffers from poor support for type safety, exception-handling mechanisms, and genericity. While most of today's developers can develop in the more robust language C++, Sun couldn't leave those poor C developers out in the cold, which explains why JNI is the way it is today. Unfortunately, that leaves developers with a difficult and unwieldy API?but there is hope.
Jace is a free, open source toolkit designed to make JNI programming easy. It supports automatic generation of C++ proxy classes from Java classfiles and C++ integration of Java exceptions, arrays, packages, and objects. It manages the lifetimes and thread bindings of Java references transparently. Most importantly, it reduces development costs by allowing you to write code modules that are smaller, easier to understand, and compile-time type safe.
Warning: This article is not for the JNI uninitiated. I make references to JNI's nitty-gritty details, from function calls like NewGlobalRef() and GetFieldID() to the nuances of JNI thread and exception safety. If you're new to JNI, I strongly suggest you check out The Java Tutorial, the JNI specification, and JavaWorld' s JNI resources (see Resources for links).
The JNI type system
Jace's fundamental strength is its use of C++ proxy classes to represent Java types. To truly understand the benefit of proxy classes, you first need to review the JNI type system. Sun uses 24 C types in JNI to represent the entire set of possible Java types. JNI has nine primitive types:
jboolean
jbyte
jchar
jshort
jint
jlong
jdouble
jfloat
void
JNI has 14 reference types, as Figure 1 illustrates.
Figure 1. The 14 JNI reference types (Source: Sun Microsystems)
And, finally, JNI has the composite type jvalue , which represents the entire set of primitive and reference types.
The Jace type system
Figure 2 shows a class diagram representing the basic set of Jace types. These classes are your primary interface into the Jace runtime. Not surprising, Jace classes correspond closely with JNI types.
Figure 2. The Jace object model. Click on thumbnail to view full-size image.
The Jace type system is built directly on the 24 JNI types. For every JNI type, Jace has a matching C++ proxy class. The nine JNI primitive types, along with jvalue , jclass , jobject , jstring , and jthrowable , all map directly to corresponding Jace proxy classes. The JNI type jarray and its nine derivative array types all collapse down to one template-based JArray type. In the following sections, I examine each of these C++ proxy classes in detail.
The primitive classes
The nine primitive classes act as the wrappers for the nine primitive JNI values. You use these classes as arguments and return values from other C++ proxy classes:
/* Retrieve the hashcode for the java.lang.String, "A String"
*/
JInt hashCode = String( "A String" ).hashCode();
You also use these classes as template parameters to JArray :
/* Create a byte buffer of size 512
*/
JArray buffer( 512 );
JValue
JValue is the base class for all the proxy classes. It represents the total set of Java primitive and reference types. Therefore, each JValue has a JClass instance that represents the corresponding jclass for the jvalue . You can only construct a JValue by providing it with a JNI jvalue type. JValue then acts as a holder for that jvalue . Most developers don't need to interact with JValue s directly.
JClass
JClass represents the JNI type jclass . JClass provides methods to retrieve its jclass and the strings that represent that jclass in different JNI calls (for example, java/lang/Object and Ljava/lang/Object; ). The framework uses JClass instances to provide the information necessary to make JNI calls, like GetMethodID() , GetFieldID() , and NewObjectArray() . Most developers don't need to interact with JClass es directly.
JObject
The JObject class, which represents the JNI type jobject , serves as the base class for all reference types. In addition to overriding JValue::getJavaValue() , JObject also provides getJavaObject() . These two methods are functionally equivalent, except that getJavaObject() unwraps the jvalue and places it into a jobject .
Things become interesting with JObject , because Java reference types have some features that Java primitive types don't:
Reference types don't own values; they merely refer to them. You can construct JObject subclasses in two ways. First, you can construct them as a reference to an existing Java object. You can do this by using the constructor that takes a jobject (or a jvalue containing a jobject ) or by using the C++ copy constructor.
When you instantiate a JObject subclass, the subclass instance refers itself to the jobject reference provided as the argument. (The instance creates a new global reference to the jobject using NewGlobalRef() ):
using jace::java::net::URL;
/**
* @param jurl - A java.net.URL
*/
JNIEXPORT void JNICALL Java_foo_Bar_someMethod( JNIEnv *env, jobject jURL ) {
/* You create a reference to jURL; not a new URL
*/
URL url( jurl );
/* Now that you've instantiated this C++ proxy object, you can call methods
* on jURL with ease?like toString()
*/
std::string urlString = url.toString();
}
Second, you can construct a JObject subclass by creating a new Java object. You can create a new object by calling any other subclass constructor. When that happens, the subclass calls the appropriate Java constructor using JNI. After constructing the Java object, the subclass creates a new global reference to it:
/* Creates a new FileOutputStream on foo.txt.
*/
jace::java::io::FileOutputStream output( "foo.txt" );
Regardless of how you create a JObject subclass, the subclass's only action upon leaving scope is to call DeleteGlobalRef() on the global reference it created at construction.
Reference types may be null. You can detect if a C++ proxy class refers to a null Java object by calling JObject::isNull() :
/**
* @param jstring - A java.lang.String
*/
JNIEXPORT void JNICALL Java_foo_Bar_someMethod( JNIEnv *env, jstring
javaString ) {
String str( javaString );
if ( str.isNull() ) {
cout << "Error - The argument, javaString, must not be
null." << endl;
}
}
Throwable and String
Both the Throwable and String C++ proxy classes derive from JObject (as do all reference-type proxy classes). These classes are included (along with a few others) as a core part of the Jace library to provide users with a tighter integration between the C++ and Java languages. (I discuss this in more detail in the "C++ Integration" section.)
Jace features
Jace sports several features, including thread management, exception management, and automatic type conversions, among others. Let's examine those features and more.
Thread management
In JNI, a few thread issues exist:
JNIEnv pointers are only valid on the thread from which they are obtained
Similarly, most JNI types are only valid on the thread from which they are obtained
C++ threads must be attached to the JVM before calling JNI functions
Jace addresses all these issues. First, every function in the Jace library automatically retrieves a JNIEnv pointer that is valid for the current thread.
Second, Jace creates global references to the necessary JNI types. For example, upon construction, a JClass creates a global reference to its jclass member, and a JObject creates a global reference to its jobject member. Unlike local references, which are only valid for the current thread, global references are valid across all threads.
Finally, every function in Jace ensures that the current thread is attached to the JVM before calling any JNI functions.
Exception management
Exception handling is one bane of JNI programming. Jace has two policies for exception handling:
Jace checks the return code of every JNI function it executes. If an error occurs, Jace clears the JNI exception and then throws Jace's JNIException .
If Jace determines that a Java method's invocation has failed because the method has thrown an exception, Jace clears the JNI exception, examines the thrown exception, creates a C++ proxy instance for that exception, and throws the C++ proxy:
using namespace jace::java::net;
void readGoogle() {
try {
/* When Jace internally executes NewObject, it checks to
* see if an exception is thrown. If the JNI function
* ExceptionOccurred, returns an exception, Jace clears the
* exception, creates a corresponding C++ proxy, and throws it.
*/
URL url( "http://www.google.com" );
}
/* Here, you catch the Jace thrown C++ proxy exception.
*/
catch ( MalformedURLException& e ) {
cout << e;
}
}
Automatic type conversion
Jace provides automatic type conversions between C++ and Java primitive types. You may use a C++ std::string or char* anywhere a C++ proxy requires a java::lang::String . You may also use C++ types, like bool , int , and char , where C++ proxy methods require primitive JNI types, like JBoolean , JInt , and JChar :
using jace::javax::swing::JFrame;
JFrame createFrame( const std::string& title, int x, int y ) {
/* The prototype for JFrame is JFrame( java::lang::String str );.
* Jace automat


 

Read Tutorial at: Click here to view the tutorial

Rate Tutorial:
Integrate Java and C++ with Jace

View Tutorial:
Integrate Java and C++ with Jace

Related Tutorials:

Integrating Databases
Integrating Databases
 
C# : A language alternative or just J--? (part1)
C# : A language alternative or just J--? (part1)
 
C#: A language alternative or just J--?, Part 2 - JavaWorld December 2000
C#: A language alternative or just J--?, Part 2 - JavaWorld December 2000
 
Embed Java code into your native apps - JavaWorld May 2001
Embed Java code into your native apps - JavaWorld May 2001
 
Integrate EJBs with CORBA
Integrate EJBs with CORBA
 
Integrate Java and C++ with Jace
Integrate Java and C++ with Jace
 
Bridge the gap between Java and Twain
Bridge the gap between Java and Twain
 
Profiling CPU usage from within a Java application
Profiling CPU usage from within a Java application
 
Test email components in your software
Test email components in your software
 
Java Floating License Enforcer Developer Package
Java Floating License Enforcer for Java Developer Package
 
YourKit Java Profiler 2.5.2 Released
YourKit Java Profiler 3.2 Released With help of YourKit Java Profiler, an outstanding tool for Java professionals, you can easily solve wide range of CPU and memory related performance problems in J2EE and J2SE applications.
 
Jython
Get to know Jython, in this first article in a new series introducing alternate languages for the Java Runtime Environment, alt.lang.jre. Jython is an implementation of the popular scripting language Python, but running on a JVM. For Python developers Jyt
 
Put JSF to work
Build a real-world Web application with JavaServer Faces, the Spring Framework, and Hibernate Summary Building a real-world Web application using JavaServer Faces is not a trivial task. This article shows you how to integrate JSF, the Spring Framewor
 
Mandarax
Mandarax is an open source java class library for deduction rules. It provides an infrastructure for defining, managing and querying rule bases.
 
YourKit Java Profiler 3.2 Released
With help of YourKit Java Profiler, an outstanding tool for Java professionals, you can easily solve wide range of CPU and memory related performance problems in J2EE and J2SE applications.
 
JTwain
JTwain will implement a Java interface to the the Win32 C DLL TWAIN acquire methods.
 
Lucene in Action
Lucene in Action Lucene is a gem in the open-source world--a highly scalable, fast search engine. It delivers performance and is disarmingly easy to use. Lucene in Action is the authoritative guide to Lucene. It describes how to index your data, includin
 
J2J - Java to JavaScript integration.
It is a development tool lets you to integrate Java classes and JavaScript within your HTML pages. The main idea behind this product is how to call methods of Java classes right from JavaScript functions.
 
Developing Distributed application using Enterprise Java Beans, J2EE Architecture, EJB Tutorial, WebLogic Tutorial.
Developing Distributed application using Enterprise Java Beans, J2EE Architecture, EJB Tutorial, WebLogic Tutorial. Distributed Architecture Two-tier application: In the past two-tier applications were used. Two-tier applications are also know as
 
Parisonz Solutions!
Parisonz Solutions! W elcome to Parisonz Solutions . The purpose of this web is to Develop and Distribute Projects to Businesses and Individuals though Web. We have a wide range of projects completed online — including software development, web
 
Site navigation
 

 

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2006. All rights reserved.