- Debugging in the Java Development Tooling Environment
- The Debug Perspective
- Debugging Standalone Java Code
- Remote Debugging
- In Brief
Debugging Standalone Java Code
Start Eclipse if it is not already running. Create a new project, a Java class, and a JUnit test to go with it. If you created the Calculator project from Chapter 2, "Writing and Running a Java Application," then simply refer to that project for the next few pages. If you have not created the Calculator project, perform the following steps:
Press Ctrl+N and from the New dialog select Java Project and click Next. In the Project Name field enter "Calculator".
Leave the Location section set to its default workspace location.
In the Project Layout section, select Create Separate Source and Output Folders and click Configure Defaults. When the Preferences dialog opens, click the Folders button. Leave the Source Folder Name set to src, but change the Output Folder Name to classes. Click OK.
Click Finish.
Now you need to create two classes: the class to be run and the class that tests it. In order to create them, perform the following steps:
Press Ctrl+N to open the New dialog. If only two selections appear, put a check next to Show All Wizards toward the lower-left corner of the dialog. When the remaining resource wizards appear, select Java, Class and click Next.
On the Java Class page, enter a Package of eclipse.kickstart.example and Class Name of SimpleCalculator. Click Finish.
Select SimpleCalculator in the Package Explorer view.
Press Ctrl+N again to open the New dialog. Select Java, JUnit, JUnit Test Case and click Next.
On the JUnit Test Case page, all the test case information should be filled in. If it is not, click Cancel, select SimpleCalculator, and return to step 4. If the JUnit Test Case page is filled in, check setUp() and tearDown() and click Finish.
If you did not implement the SimpleCalculator class from Chapter 2, open the SimpleCalculator class and add the following code:
package eclipse.kickstart.example; import java.text.DecimalFormat; public class SimpleCalculator implements Calculator { private static final String USAGE = "java eclipse.kickstart.example.SimpleCalculator val1 val2"; public int add(int i, int j) { return I + j; } }
If you did not implement SimpleCalculatorTest in Chapter 2, open the SimpleCalculatorTest class and add the following methods (if you already implemented this class then just add the code in bold):
package eclipse.kickstart.example; import junit.framework.TestCase; public class SimpleCalculatorTest extends TestCase { private Calculator _calculator; public void testAdd() { int expected = 0; int actual = _calculator.add(0, 0); assertEquals(expected, actual); expected = 1; actual = _calculator.add(0, 1); assertEquals(expected, actual); try { actual = _calculator.add(Integer.MAX_VALUE, 1); fail("add() passed on an overflow value."); } catch (RuntimeException e) { // If we come here then an exception was // thrown and the test passed. } } protected void setUp() throws Exception { _calculator = new SimpleCalculator(); } protected void tearDown() throws Exception { _calculator = null; } }
The code in the try/catch block is checking if SimpleCalculator's add() method can handle an integer value overflow. The expected behavior is for the method to throw an exception if the value is too large to contain in an int, and the caller then needs to do something about it. If the test passes, you should get a green bar in the JUnit GUI. (It will fail, of course. Make the code changes, select SimpleCalculatorTest, and then select Run, Run As, JUnit Test. Red bar!)
Let's set a simple breakpoint in SimpleCalculator's add() method at the line that reads return i + j. Double-click in the editor margin to the far left, just past the line numbers. A blue dot appears. Press F11 or select from the main menu Run, Debug As, JUnit Test. The debugger stops the code in add() and displays the various stack frames in the Debug view. Select the stack frame for SimpleCalculator.testAdd() (see Figure 3.3). The selected code is for the first of the three tests run in testAdd(). Because you want the debugger to stop on the third test, you have two choices on how to proceed: You can either set the breakpoint in the testAdd() method of SimpleCalculatorTest or you can modify the breakpoint to become activated based on a condition. For the purposes of this example, you are going to do the latter.
Figure 3.3 The Debug perspective with the stack frame for SimpleCalculatorTest selected.Go to the Breakpoints view in the upper-right corner (see Figure 3.4). If it is not visible, click the Breakpoints tab. Double-click the breakpoint in the Breakpoints view to bring the editor forward with the breakpoint line selected. Because you are debugging the code and you are at the particular line, you will also see an arrow pointing toward the line in question. Right-click where the blue dot is to open a pop-up menu and then select the Breakpoint Properties menu item. This menu item will open a Properties dialog (see Figure 3.5) for this breakpoint, allowing you to do the following:
Disable the breakpoint.
Set the breakpoint to be called only after it has been accessed a certain number of times.
Set the breakpoint to halt execution when a condition has been met.
Figure 3.4 The Breakpoints view displaying the single available breakpoint.
Figure 3.5 The Breakpoint Properties dialog.
Let's try all three. Uncheck Enabled and click OK. To resume execution, go to the Debug view and click the right-pointing triangle or just press F8. The breakpoint, now disabled, was ignored, and the test completed with the red bar.
Reenable the breakpoint by right-clicking the breakpoint and, when the Properties dialog opens, checking Enabled. Now check Hit Count and enter 3 into its input field. Click OK. Press F11 to restart the debug session.
Now, when the breakpoint is hit in the add() method, it will only stop the third time the breakpoint is accessed. To prove it, select the stack frame just below the breakpoint frame (the one for SimpleCalculatorTest.testAdd()). Instead of stopping at the first call to add() in testAdd(), it has stopped at the third call. This is useful when you have a bug that only surfaces when a piece of code executes a certain number of times. Press F8 to resume and complete the test run (still a red bar!).
What about those situations where you need to stop only after a particular condition is met? For example, when the value of a variable enters a certain range, you would like the breakpoint to activate. Once again, right-click the breakpoint and open the Breakpoint Properties dialog. Uncheck Hit Count and check Enable Condition. In the text area, enter i == Integer.MAX_VALUE. Code Assist is active in this text area, so feel free to use it in completing Integer and MAX_VALUE. Click OK and press F11 to restart the debugging session. Click the Variables tab to bring the Variables view forward. The variable i is set to 2147483647, which, not coincidentally, equals Integer.MAX_VALUE. Just to double-check, click the stack frame for SimpleCalculatorTest.testAdd() again. The breakpoint stopped at the third test once again. Press F8 to complete the test run.
In case you are tired of seeing the red bar, add the following code to SimpleCalculator's add() method:
public int add(int i, int j) { int result = 0; long op1 = i; long op2 = j; long longResult = op1 + op2; if (longResult > Integer.MAX_VALUE) { throw new RuntimeException( "The addition of the values would result in an overflow."); } else { result = (int) longResult; } return result; }
Let's look at the Expressions view before we move away from the SimpleCalculator example. Set a breakpoint at the first line of the add() code and another at the if statement. Press F11 to restart the debug session. When the breakpoint stops at the top of add(), select the variable longResult, right-click to open the pop-up menu, and select Watch. Because longResult is a local variable, the debugger complains that it cannot evaluate the expression. Press F8 to resume execution to the next breakpoint. Now that longResult is declared, the Expressions view shows the variable set to 0 (which is correct because the first JUnit test checked that 0 + 0 equals 0). Press F8 again, and the Expressions view once again complains that longResult has encountered evaluation errors. Press F8 again, and now longResult equals 1.
Continue pressing F8 until the program completes. If you want to clear the Debug view of all the terminated processes you created, click the fifth icon from the left in the menu bar of the Debug view (the one that looks like a stack of rectangles). To remove the breakpoints, click the Breakpoints tab, right-click in the Breakpoints view, and select Remove All from the pop-up menu.
Close all the editors.
Debugging Server-Side Java
Server-side debugging of Java code is not supported in Eclipse, but it can be added through additional plug-ins. The section titled "Debugging Servlets, JSPs, and EJBs" of Chapter 9, "J2EE and the MyEclipse Plug-In," covers J2EE development using the MyEclipse plug-in, including the installation of the plug-in, how to set up the configuration of a server, implementing a servlet and JSP, and debugging server-side components within Eclipse.
Once the plug-in J2EE support is installed and the server configuration is entered, debugging proceeds as before. Set breakpoints, examine variables, edit files, and observe the various views in the same way you would for a standalone.