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/2010S/labs/code/jde/Factorial.java .
cp ~weinman/public_html/courses/CSC207/2010S/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 Configuration Commands
;; Include the speedbar (GNU emacs)
(unless (string-match "XEmacs" emacs-version)
(define-key-after (lookup-key global-map [menu-bar tools])
[speedbar] '("Speedbar" . speedbar-frame-mode) [calendar])
)
; Include pwd of a source file in the sourcepath for compilation
(setq jde-sourcepath (quote (".")))
;; Tell JDE which JDK to use
(setq jde-jdk (quote ("1.6")))
;; 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.6" . "/usr/lib/jvm/java-6-openjdk"))))
; 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))
;; JDE Config
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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 clicking 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 somewhere on 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). Starting documentation is this easy. You
have no excuses henceforth.
-
Now, place your cursor at the end 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, add a new line beginning
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.e
with the cursor placed just after the e.
-
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 ~
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 then reopen it. You can
decide whether or not you like this amnestic 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 you 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 JDE'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 (assuming you
still have the cursor focus in the bottom frame).
-
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 white arrow should now 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), repeat the
details of exercise 7, replacing the variable
name
jde-db-read-app-args
with
jde-run-read-app-args. Do this now.
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 on this pink region 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 so that you may 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 variables 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.