Summary: In this lab, you will learn how to configure the
Java Development Environment for Emacs (JDEE or just JDE) and use
its built-in debugger.
Preparation
-
Make a directory for the code you will be using in this lab:
mkdir somewhere/jdelab
cd somewhere/jdelab
-
Copy the source files for this lab to your new
directory:
cp ~weinman/public_html/courses/CSC207/2009S/labs/code/jde/Factorial.java .
cp ~weinman/public_html/courses/CSC207/2009S/labs/code/jde/Fibonacci.java .
Exercises
Exercise 1
-
Edit (or create) a configuration file for emacs in your home directory:
emacs ~/.emacs &
-
Add the following lines to your
.emacs file.
dotemacs.el
;;;;;;;;;;;;;;;;;;;;;;;;
;; JDE Enabling Commands
(add-to-list 'load-path
(expand-file-name "~weinman/share/emacs/jde/lisp"))
(add-to-list 'load-path
(expand-file-name "~weinman/share/emacs/cedet/common"))
(add-to-list 'load-path
(expand-file-name "~weinman/share/emacs/site-lisp/elib"))
(load-file (expand-file-name "~weinman/share/emacs/cedet/common/cedet.el"))
; Include pwd of a source file in the sourcepath for compilation
(setq jde-sourcepath (quote (".")))
;; Include pwd of a source file in the classpath for compilation
(setq jde-global-classpath (quote (".")))
; Always include debug info when using JDE to compile
(setq jde-compile-option-command-line-args (quote ("-g")))
; Tell JDE where to find the JDK (i.e., javac, java, and jdb)
(setq jde-jdk-registry
(quote (("1.5" . "/usr/lib/jvm/java-1.5.0-sun"))))
; In case we use emacs for other things, delay the (lengthy) loading
; of JDE until a Java file is actually opened
(setq defer-loading-jde t)
(if defer-loading-jde
(progn
(autoload 'jde-mode "jde" "JDE mode." t)
(setq auto-mode-alist
(append
'(("\\.java\\'" . jde-mode))
auto-mode-alist)))
(require 'jde))
Exercise 2
If you already had a
.emacs file, you may want to check
and see whether the commands you'll add in this exercise are already
present. It won't harm anything to add them twice, but there's
certainly no need to .
-
Add the following lines to enable syntax highlighting on any file
you open in Emacs:
;; Enable syntax highlighting
(global-font-lock-mode t)
-
Add the following lines to enable parenthesis/brace matching in
your source code (very handy!)
;; Show matching paren or bracket when cursor is on or after it
(show-paren-mode 1)
-
Close emacs.
Exercise 3
-
Open the file
Factorial.java in Emacs. This should
cause syntax highlighting to automatically come on (if it didn't
already), and you might also notice it will take slightly
longer to load, because the Java Development Environment is being
loaded.
-
You should see several new menus appear at the top of Emacs. Specifically:
-
Click on the menu Classes. What does it show you? What happens if
you choose a function name from the drop down menus?
-
Add a class variable to
Factorial.java:
private static String foo;
-
Now click on the Classes menu again. What is different about it?
Does click on different things from the menu give you the behavior
you might expect?
-
Click on the JDE menu and examine some of the options in the menu
and its submenus.
-
Place your cursor at the beginning of the line for your new
variable
foo. Click on the menu JDE ~
Documentation ~ Add. What happens?
Note that you can accomplish the same thing with C-c C-v
j (which means type Control-c, Control-v, and then j).
-
Again ensure your cursor is at the beginning of the line for your
variable
foo. Click on the menu JDE ~
Code Generation ~ Wizards ~ Generate Get/Set
Methods. What happens?
-
Do your new methods show up in the Classes menu?
Exercise 4
-
Inside one of the methods you just created a skeleton of, type
foo.
as if you were going to call a member method of the variable foo.
-
With the cursor still placed right after the "dot" type C-c C-v C-.
(that is, control-C, control-V, and control-. (period)). What happens?
-
Explore the menu(s).
-
Find the entry
subSequence(int, int) : java.lang.CharSequence
and select it.
-
What do you suppose are the arguments to this method? What is the
return type?
-
Delete what was just added and add an a so that you are left with just
foo.a
with the cursor placed just after the a.
-
Do another "auto-complete" (C-c C-v C-.)
-
How are the options different? Are they consistent with what you'd
already typed?
This so-called auto-completion of fields (member variables) or methods
is one of the most convenient properties of an integrated development
environment, such as JDE. In JDE, auto-complete will work with any
Java API type
or a type you have defined, so long as
- it has been compiled into a
.class file, and
-
the class file resides in the JDE's class path (which it should if
you've used JDE to compile it or it is in the same directory as
the file you are editing).
In addition, methods of the current object can be autocompleted if
they are preceded by a
this.,
super. or even
just a
. prefix (though the latter is not acceptable
syntax).
Exercise 5
-
Open the Speedbar by going to the menu Tools ~ Display
Speedbar. A new window should appear near your emacs frame
that shows the files in your current directory.
-
Notice that each file has a
[+] next to it,
indicating that it can be "opened," just like folders in many file
browsers. Using your middle mouse button (which may be a wheel),
click on the [+] next
to Factorial.java. What do you see?
-
The speedbar understands Java (and many other kinds of
files). What appears is a list of the classes inside the file you
"opened." Middle-click again on the
+> to "open"
that class and see what's inside.
-
Middle-click on the
+> next
to foo. What appears? Suppose you hadn't added that
variable but were investigating someone else's code (or code that
you had written long ago). Do you suppose easily accessing this
information could be useful?
-
Middle-click on the
{+} next to Methods. It should
not be too surprising what you see.
-
What do you expect to appear when you open a method? (What might
one want to know about a method?)
-
Open (by middle-clicking the
+> next to it) the
method setFoo(). What appears? Is there anything new
that appears you can also open? If so, open it! Does it show what
you might expect?
-
Now, "close" the
Methods section by middle-clicking
on the {-} next to it, and the reopen it. You can
decide whether or not you like this feature.
-
In the speedbar, middle click on the method
calc()
(that is, on the name itself, not the +> next to
it). What happens?
-
What do yo suppose happens if you click on the
variable
foo in the Speedbar? Try it and see!
-
Hopefully by now you should see that the Speedbar, which functions
as your code navigator, can be very handy, especially when you've
got much bigger files (which of course shouldn't be too big,
because that would violate the tenets of OOP!), with many methods
and variables.
Exercise 6
-
Now that we've spent all this time poking around the code, let's
try to compile and run it! Go to the menu JDE and
choose Compile. (If you haven't already saved the
modifications you've made, it will probably ask you to. Go ahead
and save them.)
-
You should see a new buffer appear that shows the result of
compiling the class. Hey, no more hunting for a terminal and
typing
javac what-was-my-file-again!
(That is, unless you prefer to.)
-
If your class has a static main method, you can also run the
program from within emacs. Click on JDE ~ Run App. What do
you see?
-
Ok, so if your program requires interactivity, that doesn't
exactly work. You'll still have to remember where it is and go
run
java manually.
-
Go back to your command line and run the program
java Factorial n
for some small values of n (e.g. 3-6). Do these agree with what you
know about the factorial function?
-
Run the program with n equal to 9. Does this give you an
answer you expect?
-
Why do you suppose the program outputs the result you're getting?
Perhaps it's already quite obvious, but if it weren't, in the next
exercise we'll do a little poking that may help shed some light on
the matter.
Exercise 7
One of the greatest things about a debugger is that it allows you to
inspect variables, and step through code one line (or operation) at a
time. In this exercise, we'll look at JDEE's methods for doing this.
-
In the source file for
Factorial.java, place the
cursor on the line inside main that
declares facArg.
-
If the debugger is going to allow us to step through code line by
line, it might be very tedious for us to step through many lines
before we reach the one we're interested in. Therefore, we can set
what are called breakpoints. The program may continue its
normal behavior until it reaches one of these breakpoints, and
then we have the option of inspecting some variables, stepping,
and/or telling the program continue (perhaps until it reaches
another breakpoint).
With your cursor at the aforementioned line, go to the Jdb
menu and select "Toggle Breakpoint". You should see the
breakpointed line change to green. We can set as many breakpoints
as we like, but for now we'll stick with this one.
-
Now let's run our program in debug mode. Go to the JDE menu
and choose Debug App. Your emacs frame should split in two,
and in the top half you should see the
main function,
and in the bottom half the debugger output.
-
The debugger has actually begun running your program, and it
should have hit the breakpoint you set for it, which is why the
breakpoint line should be red and have a little right-facing arrow
next to it on the left side.
-
When JDE started the debugger for you, it also transferred the
cursor to that buffer. Let's make sure we can see the updates from
the debugger as they are happening by placing the cursor at the
end of this buffer. You can do this by pressing the End key
on your keyboard.
-
Return the cursor to the Java file (either by clicking, or
using
C-x o. Now you can step the debugger, but we
have a few options for stepping. Let's explore each in turn.
-
From the Jdb menu, choose Step Over. (Or you may
type the shortcut
C-c C-a C-s. What
happens to the cursor next to the breakpoint line? What do you see in the debugger buffer below?
-
Do a Step Over again (either from the menu or the keyboard
shortcut). Where is the arrow now? You should see it next to the
expression
printUsage();. The arrow indicates
the next line that will be executed when we continue
stepping.
-
Step Over one more time. What appears in the debugger window?
-
The program ended up running the
printUsage();, which
results in termination. The debugger communicates this to us by
saying "The application exited."
-
Now let's try a different version of "stepping." Return the cursor
to the Java file and start the debug process again with JDE ~
Debug App. This should leave us at our breakpoint once again,
with the debugger output below. Don't forget to make sure that
you're seeing the most recent output by going to the debugger
buffer and pressing the "End" key.
-
Return to the Java window, and this time use the command Jdb ~
Step Into (or the keyboard equivalent
C-c C-a
C-n). Do you notice anything different?
-
Do another Step Into. Presumably, the arrow (indicating the
next expression) has moved along happily down the code and should
now once again be pointing at the
printUsage();
expression.
-
Do yet another Step Into. Now what happens? Where in the code are you?
-
Describe the difference between stepping "over" and stepping
"into" a function call.
Exercise 8
Clearly, if we are going to do any useful debugging, we are going to
want our program to accept command line arguments. Fortunately, JDE
has provided a way to do this. We are going to do it two ways, one
that only affects our current emacs session (so that we don't have to
quit and restart emacs), and another that makes the change "permanent" (or at least automatic) in our
.emacs file
-
Type
M-x set-variable (the M means the "meta" key
which is usually Alt or Esc).
-
At the
Set variable: prompt,
type jde-db-read-app-args and press enter.
-
At the
Set jde-db-read-app-args to value: prompt,
type t and press enter. These steps should take care
of your current session.
-
To make this behavior permanent (you can always type nothing when
the debugger asks you for command line arguments), add the
following line to your
.emacs file with the other JDE
configuration lines.
;; Read command line arguments for debugging
(setq jde-db-read-app-args t)
-
Now when you go to JDE ~ Debug App you should get a prompt
(at the bottom, in what is called the "minibuffer" window)
for Application args: . Here you would type the normal
command line arguments that would ordinarily
follow
java Factorial, or whatever the
command line invocation may be for your program.
-
Type
9 (the input that gives us a strange factorial),
and press enter.
Exercise 9
-
Now that you have entered some command line arguments, the program
should proceed without error past all the command-line procesing
steps. Do a Step Into until you are actually at the first
line of the
calc method.
-
Before you step any further, go to the Jdb menu and
select Display ~ Locals. What do you see in the debugger
window?
-
Now take one more step (either step into or step over should
achieve the same thing, since the variable declaration does not
involve a function call). Display the local variables once again
(the keyboard shortcut is
C-c C-a C-l. Do you see
anything different in the debugger window?
-
The arrow should not be at the left of the
for
loop. Take one more step and then display the local variables once
again. Now what has been added in the debugger window?
-
Take another step and display the locals. Has any thing changed?
-
Continue to step over these two lines of code and watch the
variables. For what value of
i do things begin to go
"haywire"?
-
To exit the debugger, you can simply go to that window and close
it like you would any other file (i.e.,
C-x k). Go
ahead and close it now.
-
In case you don't remember you can get back to "one window" in
your emacs frame by typing
C-x 1. Do that now.
Exercise 10
If you want to use command line arguments to run the program from
within JDE normally (without debugging), you may wish to repeat the
details of exercise 7, replacing the variable
name
jde-db-read-app-args
with
jde-run-read-app-args.
Exercise 11
The debugger has one other useful feature we'll look at today: looking
at the stack of function calls.
-
You can also use the speedbar to actually open files in
emacs. Middle-click on the file
Fibonacci.java in the
speedbar to open it.
-
Compile this file. What do you see?
-
Using JDE for development can also help you track down your errors
more quickly. While it gives you the same textual output (file,
line number), it can do more. Hover your mouse over the first pink
line at the top of the compile output in the bottom half of your
emacs frame. What does it tell you?
-
Middle-click to go to the problematic line.
-
It looks as though we made a typo when we were creating our
recursive version for calculating Fibonacci numbers. Knowing that
the function is actually called
calc, fix this
problem and recompile.
-
Now run the program and give it the input 2. What happens?
-
Let's see if we can use the debugger to figure out what's going
on. Add a breakpoint to the first line of the
function
calc.
-
Start the debugging process.
-
The program will start, but actually pause at the first line, we
can use the command Jdb ~ Continue to keep running the
program until our next breakpoint. Do that.
-
Use Step Into as many times as you need to forget how many
times you've done it.
-
If you need to get something of a handle on where you are in the
program, you can look at the sequence of function calls that have
brought you to the current place by looking at the "call stack."
In Jdb, you can do this by choosing Jdb ~ Stack ~ Where. Do
that now.
-
You should see that you're several levels deep into the recursive
calls. What is the current value of the variable (which in this
case is the argument to the function). Are they surprising in any way?
-
You can navigate the call stack as well, to query variable values
in any of the calling functions. This is very useful for testing
assumptions you may be making about them. Go up a level in the
call stack by choosing Jdb ~ Stack ~ Up from the menu.
-
Inspect the local variable here. Are any of them problematic?
-
Keep navigating up the call stack just until you get to a place
where the input is not problematic. What is the value of that
input and why is the recursive call an issue?
-
Add the missing test to the recursive procedure and re-run your program (not in debug mode) for several values to ensure that it works correctly.
For those with extra time
If there is still time left, I encourage you to explore some of the
other options in JDE and Jdb. Particularly in the debugger. Open some
of your previous files (especially those with objects), set some break
points and look around. Especially poke a bit at
Jdb ~ Display ~
Object.