< Zurück | Inhalt | Weiter >

5.5.3 Javadoc Comments

There’s more to Javadoc than just documenting the types and names of classes, methods, and arguments. A developer can annotate or supplement the docu- mentation by placing specially formatted comments in his or her code.

A Javadoc comment begins with the C-style open comment plus at least one more asterisk. It ends with a C-style close comment. In other words:


/* This is a C-style comment, but it is _not_ a Javadoc comment. */


/** This is a C-style comment, but it is also a Javadoc comment. */


This isn’t a part of the Java programming language. It is merely a lexical hack to allow the javadoc program to recognize a comment it should pick up and process. Javadoc is fairly intelligent about where to place the text extracted from a Javadoc comment. For example, a Javadoc comment placed just before the start of a class will appear in the class summary on the package page and at the top of the class detail page. A Javadoc comment placed just before a method will appear in the method’s box on the class detail page, and so on.

We encourage you to discover for yourself the relationship between Javadoc comments and the output of the standard doclet. Use it. Experiment. Or, you can go and read the official Sun Microsystems documentation on Javadoc.5 That’s your choice.

Since comment text is extracted and placed into certain positions in an HTML document, you may use HTML tags in your comments to affect how they are rendered. Be aware that when you do so, you may get unexpected results if you use any custom doclets.

There’s more to it than that, however. There are a number of macros that you can place in Javadoc comments to mark data of particular significance. For example, @author should appear just before the name of the author of a particular piece of code.

These at-tags must appear after all descriptive text in a Javadoc comment.6

A tag must be at the beginning of a line within the comment (ignoring any


image

5. http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/javadoc.php

6. The exception is embedded tags, which we will discuss in a moment.


image

Example 5.6 Sample Javadoc comment with at-tags

/**

* addWait - adds in the given wait time to all the counters;

* we could say much more about the method here, but let me say

* that we sometimes include HTML tags directly in our comments.

* Since Javadoc will run all our text together, we may need: <br>

* break tags <br>

* or paragraph tags <br>

* for spacing and separation.

* <p>We also add <i>other</i> HTML tags for <b>emphasis</b>.

* <p>You should still try to make the comment readable, though,

* for the programmer who is editing the source, not

* just for those looking at the formatted Javadoc.

* @author John Q. Programmer

* @version $Id$

*

* @param delay - elapsed time, in milliseconds

* @throws TakesTooLongException

* @returns total time, in milliseconds

*

* @see net.multitool.util.TakesTooLongException, net.multitool.ctrl.Time#count

*

*/

public long addWait(long delay)

{

// ...

}


image


preceding whitespace or asterisks). The tag’s data is everything from the end of the tag to the end of the line (Example 5.6.)

Here are the standard at-tags:

@author

Everything from the tag to the end of the line is taken as the name of the code’s author.

@deprecated

Marks the method or class deprecated. This tag may be optionally followed by explanatory text. If present, this text should describe when and why the class or method was deprecated and what programmers should use instead.


@exception or @throws

Only valid in the comment for a method or constructor. This tag is followed by the name of an exception class (a descendant of java.lang.Exception) and optionally by additional explanatory text. The intent is to list the exceptions that the method throws.

@param

Only valid in the comment for a method or constructor. This tag should be followed by the name of a parameter to the method followed by descrip- tive text. This is used to document method and constructor parameters.

@return

Only valid in the comment for a method.7 This tag is followed by descriptive text meant to document the return value of the method.

@see

Populates a “See Also” section in the documentation that will provide hyperlinks to related content. There is a general format for linking to any URL, but the most common use is to refer to other elements in the same Java program. See below for the general format of such links.

In addition to these standard at-tags, there are other at-tags that may be embedded in any comment text—either the comment itself or in text that is an argument to a standard at-tag.

Such tags are placed within curly braces, for example {@example}, within a Javadoc comment. The one we use the most is the @link tag, which allows you to make a reference to another package, class, method, or class member. The general format is the same as that for the @see tag:


package_name.class_name#member_or_method_name


Any of these elements is optional. The embedded at-tags include:

@docRoot

This tag may be used when embedding HTML anchor or image tags (A or IMG tags) in a Javadoc comment to supply the root part of the


image

7. But not a constructor in this case, because constructors cannot return a value.

5.6 Dispensing with Applets 131

image


documentation path. You should always use this instead of hard-coding the full URL, or a change in directory structure or server configuration might break all of your links.

@link

Allows you to embed a cross-reference to another section of the program’s documentation directly in comment text. The format of a reference is the same as that for the @see tag.

This list is not complete. As always, see the official documentation8 for details.


5.6 DISPENSING WITH APPLETS


image

While this book does not cover writing applets, we should mention that, since an applet does not (generally) have a main() method, you need something else to launch it outside of a browser. Enter appletviewer. This program provides an execution environment for applets.



Why No Applets?

The decision to not cover applets was based both on limited space and on some deployment issues with applets. A surprisingly large number of people are running with either very old browsers that support only Java 1.1.x features, or that support Java runtime plug-ins but do not have them installed or enabled. Also, applets have severe limitations (for sound security reasons), and enabling various features requires a good under- standing of the SecurityManager Java classes, which could fill a book by themselves. We chose to minimize coverage of applets for these reasons.



image

8. http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/javadoc.php


5.7 GOING NATIVE


Now we come to the deeper darker mysteries. Let us take a look at javah. No, javah is not a Hebrew word. It is not some lost mystical text from the days be- fore science supplanted magic. It is the Java C header and stub file generator.

If you are not already fairly experienced in writing, compiling, and build- ing shared libraries in C on a Linux system, we would suggest that you skip this section, at least until you have developed intermediate skills in these areas. Otherwise, feel free to proceed.

We’re going to walk you very quickly through building a Java native method here.9 Don’t worry if you don’t quite follow it all. We will cover this topic at greater length elsewhere in the book. For now, we’re giving you the highlights. Also be sure to check out Section 5.15. We’ll point you to many additional resources on JNI (Java Native Interface) in that section.

Sounds pretty intimidating, huh? Well, depending upon your background and experience, it can be a bit intimidating. As much as this will hurt some die- hard Java purists, Java is not the right language for everything. Java’s size and semiinterpreted nature in particular make Java ill-suited for the “close to the metal” tasks, such as device drivers and raw socket networking.

Fortunately, Java’s designers were of this rocket-scientist breed (and so, for that matter, are your bending authors), so they gave Java programmers a back door: native methods. A native method is a class method whose name, ar- guments, and return type are declared in Java, but whose underlying implemen- tation is written in “native code” (usually C, but it could be any compiled language that can match C’s stack frame conventions).

As an example, let’s implement a native method that will use the native Linux C library calls to get the current program’s effective user ID and the name associated with that user.

First, we will write the Java class (Example 5.7).

You may never have seen code like that at the start of a class definition.

The block declared


static { ... }


image

9. You might be tempted to call our comments in the introduction where we mentioned that we did not like purely pedagogical examples and that we would provide real, useful code. Well, we have to confess that there are some features of the Java language that we couldn’t cram into our real-world examples. This JNI sample is one such. We admit our failure, and we apologize.


image

Example 5.7 Java application with a native method (GetUser.java)

public class GetUser { static {

System.loadLibrary("getuser");

}

public native String getUserName(); public static void main(String[] args)

{

GetUser usr = new GetUser();


System.out.println(usr.getUserName());

}

}


image


is called a static initializer and we’ll discuss it in a moment.

Once you have the Java code, compile it with javac. You now have the compiled class. The next step is to use the javah tool to build the header file for your C code.


$ javah GetUser


Example 5.8 shows the header file thus produced.

Note that you run javah on the class file, not on the source file. The nor- mal class name to classpath mappings apply. The file produced as a result is called, in this case, GetUser.h. The next step is to write the C code that implements the method (Example 5.9).

There’s a lot going on here. First, the constant, L_cuserid, is defined in stdio.h; it represents the number of characters required to hold a user name. We’re defining a char array to hold that number of characters plus one.10 We are then calling the cuserid() function (see the manpage of cuserid(3)) to get the user name of the effective user ID of the process.

That much is familiar C. But what is the argument list? Our method took no arguments. And what’s with the functions being called through the pointer argument?


image

10. What can we say? We’re paranoid about the trailing null. Sue us.


image

Example 5.8 Header file for GetUser native methods (GetUser.h)

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class GetUser */


#ifndef _Included_GetUser

#define _Included_GetUser

#ifdef cplusplus extern "C" {

#endif

/*

* Class: GetUser

* Method: getUserName

* Signature: ()Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_GetUser_getUserName (JNIEnv *, jobject);


#ifdef cplusplus

}

#endif

#endif


image


image

Example 5.9 Native method’s C implementation file (GetUser.c)

#include "GetUser.h"

#include <stdio.h>


JNIEXPORT jstring JNICALL Java_GetUser_getUserName(JNIEnv *jenv, jobject obj)

{

char buffer[L_cuserid + 1]; cuserid(buffer);

return (*jenv)->NewStringUTF(jenv, buffer);

}


image


All of the Java class member data and Java class methods may be reached through the JNIEnv pointer argument. There are also methods provided by JNI itself. One of those is NewStringUTF(). Remember that Java Strings are Unicode, not 8-bit ASCII, so you must convert to and from Unicode (UTF-8


is an 8-bit encoding for Unicode that coincides with ASCII in the low 7 bits, so it is often used for such conversions). You can think of the JNIEnv as a C++ class pointer, or you can think of it as a structure of data and function pointers (that’s really what a C++ class is, after all). The bottom line is, it provides the means to access and manipulate the Java environment from your native code. The second argument, jobject, is the “this” pointer. It points to the GetUser class, and it is upcast to the JNI equivalent of the Java Object type. If our method took parameters, they would follow these two constant

arguments.

JNI is a huge topic. You can read more about it in the Sun Microsystems JNI Tutorial,11 or in Java 2 SDK JNI FAQ,12 or in the JNI 1.1 Specification,13 or in the associated JDK 1.2 Update14 or the JDK 1.4 Update.15

Even with all of this “We’re too busy to explain things to you” going on here, we’ve got a lot more to cover before we are done. The next step in our little demo is to compile the C program and create a shared library of the code.


$ cc -c GetUser.c

$ cc -shared -o libgetuser.so GetUser.o

$ export LD_LIBRARY_PATH=.


The first line compiles the native method to a .o (object) file. The second command makes a shared library out of it. Now, refer back to the static initial- izer in Example 5.7. A static initializer is run before everything else in a class, even before main(). In this case, it uses the loadLibrary() method of the System class to load the shared library we just created. Note that library naming rules of the target OS are applied. The library is named getuser and on a Linux system it is assumed that that library will be in a file named libgetuser.so.

The last line sets an environment variable, LD_LIBRARY_PATH, to provide a path where Java will search for libraries. This is behavior inherited from So- laris. Linux uses ldconfig to maintain a list of shared libraries. Usually, a library is placed in a directory named in the file ld.so.conf and a memory cache of


image

11. http://java.sun.com/docs/books/tutorial/native1.1/index.php

12. http://java.sun.com/products/jdk/faq/jni-j2sdk-faq.php

13. http://java.sun.com/products/jdk/1.2/docs/guide/jni/spec/jniTOC.doc.php

14. http://java.sun.com/j2se/1.4.1/docs/guide/jni/jni-12.php

15. http://java.sun.com/j2se/1.4.1/docs/guide/jni/jni-14.php


these libraries is built and maintained with the ldconfig program. The library loader in the JVM, however, works as the shared library system in Solaris, where the LD_LIBRARY_PATH is searched for shared libraries. If you try a JNI method and get library errors, check your LD_LIBRARY_PATH first. Here, we used “.”, meaning “current directory.” In practice, you wouldn’t do this. You would de- ploy your shared library to a standard location and have LD_LIBRARY_PATH preset to that directory or directories. We just wanted to show you how it works here.

Let’s see our class in action now.


$ java GetUser mschwarz

$ su Password:

# export LD_LIBRARY_PATH=.

# java GetUser root

# exit exit

image

$



To JNI or Not to JNI

We dislike religious debates. We have no desire to nail down what taints the purity of Java and what does not. A warning we do want to give you is, if you are an experienced UNIX C/C++ developer, you must resist the temptation to use JNI and native methods all over the place. The Java APIs are extensive, and there are probably classes that already do what you want to do. You will be tempted to use native methods because “you know how to do it in C.” Resist. Find the Java way. JNI is a great way to introduce subtle and hard to find bugs into your Java programs. Leave that to the API and JVM coders. ;-)

That said, we don’t want to discourage you from making use of JNI when it is the right way, or the only way, for what you need to do. The tool is there. Use it. Just remember what it does cost you in portability and what it may cost you in maintenance and debugging. Design decisions have costs and benefits. Try to find the balance.


Here you see the class being run, and, sure enough, it displays our user- name. We then run su to become root and (after setting that library path) run it again—and, sure enough, it tells us we are “root.”

We’ll talk more about JNI later in the book, but now you know enough to be dangerous.


5.8 INTRODUCING RMI


Remote Method Invocation (RMI) is a system for distributing application code over multiple hosts. It is a small part of multitier computing. Much of this book will be devoted to the how’s and why’s of multitier client/server computing. Here we are concerned only with the SDK tool rmic, the RMI compiler.