





















































Eclipse – an IDE for everything and nothing in particular.
Eclipse is a highly modular application consisting of hundreds of plugins, and can be extended by installing additional plugins. Plugins are developed and debugged with the Plugin Development Environment (PDE).
In this article by Dr Alex Blewitt, author of the book, Eclipse Plug-in Development: Beginner's Guide - Second Edition, covers:
(For more resources related to this topic, see here.)
Developing plug-ins requires an Eclipse development environment. This has been developed and tested on Eclipse Mars 4.5 and Eclipse Neon 4.6, which was released in June 2016. Use the most recent version available.
Eclipse plug-ins are generally written in Java. Although it's possible to use other JVM-based languages (such as Groovy or Scala).
There are several different packages of Eclipse available from the downloads page, each of which contains a different combination of plug-ins. This has been tested with:
These contain the necessary Plug-in Development Environment (PDE) feature as well as source code, help documentation, and other useful features.
It is also possible to install the Eclipse PDE feature in an existing Eclipse instance. To do this, go to the Help menu and select Install New Software, followed by choosing the General Purpose Tools category from the selected update site. The Eclipse PDE feature contains everything needed to create a new plug-in.
Eclipse is a Java-based application; it needs Java installed. Eclipse is distributed as a compressed archive and doesn't require an explicit installation step:
Note that Java comes in two flavors: a 32-bit installation and a 64-bit installation. If the running OS is 32-bit, then install the 32-bit JDK; alternatively, if the running OS is 64-bit, then install the 64-bit JDK.
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
Java HotSpot(TM) Client VM
Java HotSpot(TM) 64-Bit Server VM
On Linux, Eclipse requires GTK+ 2 or 3 to be installed. Most Linux distributions have a window manager based on GNOME, which provides GTK+ 2 or 3.
Eclipse needs Java to run, and so the first step involved in installing Eclipse is ensuring that an up-to-date Java installation is available. By default, Eclipse will find a copy of Java installed on the path or from one of the standard locations. It is also possible to specify a different Java by using the -vm command-line argument.
If the splash screen doesn't show, then the Eclipse version may be incompatible with the JDK (for example, a 64-bit JDK with a 32-bit Eclipse, or vice versa). Common error messages shown at the launcher may include Unable to find companion launcher or a cryptic message about being unable to find an SWT library.
On Windows, there is an additional eclipsec.exe launcher that allows log messages to be displayed on the console. This is sometimes useful if Eclipse fails to load and no other message is displayed. Other operating systems can use the eclipse command; and both support the -consolelog argument, which can display more diagnostic information about problems with launching Eclipse.
The Eclipse workspace is a directory used for two purposes: as the default project location, and to hold the .metadata directory containing Eclipse settings, preferences, and other runtime information. The Eclipse runtime log is stored in the .metadata/.log file.
The workspace chooser dialog has an option to set a default workspace. It can be changed within Eclipse by navigating to File | Switch Workspace. It can also be overridden by specifying a different workspace location with the -data command-line argument.
Finally, the welcome screen is useful for first-time users, but it is worth closing (rather than minimizing) once Eclipse has started.
In this task, Eclipse's plug-in wizard will be used to create a plug-in.
In PDE, every plug-in has its own individual project. A plug-in project is typically created with the new project wizard, although it is also possible to upgrade an existing Java project to a plug-in project by adding the PDE nature and the required files by navigating to Configure | Convert to plug-in project.
Creating a plug-in project is the first step towards creating a plug-in for Eclipse. The new plug-in project wizard was used with one of the sample templates to create a project.
Plug-ins are typically named in reverse domain name format, so these examples will be prefixed with com.packtpub.e4. This helps to distinguish between many plug-ins; the stock Eclipse IDE for Eclipse Committers comes with more than 450 individual plug-ins; the Eclipse-developed ones start with org.eclipse.
Conventionally, plug-ins that create additions to (or require) the use of the UI have .ui. in their name. This helps to distinguish those that don't, which can often be used headlessly. Of the more than 450 plug-ins that make up the Eclipse IDE for Eclipse Committers, approximately 120 are UI-related and the rest are headless.
The project contains a number of files that are automatically generated based on the content filled in the wizard. The key files in an Eclipse plug-in are:
This is one of the reasons Eclipse starts so quickly; by not needing to load or execute classes, it can scale by showing what's needed at the time, and then load the class on demand when the user invokes the action. Java Swing's Action class provides labels and tooltips programmatically, which can result in slower initialization of Swing-based user interfaces.
Q1. What is an Eclipse workspace?
Q2. What is the naming convention for Eclipse plug-in projects?
Q3. What are the names of the three key files in an Eclipse plug-in?
To test an Eclipse plug-in, Eclipse is used to run or debug a new Eclipse instance with the plug-in installed.
Eclipse can launch a new Eclipse application by clicking on the run icon, or via the Run menu:
Upon clicking on run in the toolbar (or via Run | Run As | Eclipse Application) a launch configuration is created, which includes any plug-ins open in the workspace. A second copy of Eclipse—with its own temporary workspace—will enable the plug-in to be tested and verify that it works as expected.
The run operation is intelligent, in that it launches an application based on what is selected in the workspace. If a plug-in is selected, it will offer the opportunity to run as an Eclipse Application; if a Java project with a class with a main method, it will run it as a standard Java Application; and if it has tests, then it will offer to run the test launcher instead.
However, the run operation can also be counter-intuitive; if clicked a second time, and in a different project context, then something other than the expected launched might be run.
A list of the available launch configurations can be seen by going to the Run menu, or by going to the dropdown to the right of the run icon. The Run | Run Configurations menu shows all the available types, including any previously run:
By default, the runtime workspace is kept between runs. The launch configuration for an Eclipse application has options that can be customized; in the preceding screenshot, the Workspace Data section in the Main tab shows where the runtime workspace is stored, and an option is shown that allows the workspace to be cleared (with or without confirmation) between runs.
Launch configurations can be deleted by clicking on the red delete icon on the top left, and new launch configurations can be created by clicking on the new icon. Each launch configuration has a type:
The launch configuration can be thought of as a pre-canned script that can launch different types of programs. Additional tabs are used to customize the launch, such as the environment variables, system properties, or command-line arguments. The type of the launch configuration specifies what parameters are required and how the launch is executed.
When a program is launched with the run icon, changes to the project's source code while it is running have no effect. However, as we'll see in the next section, if launched with the debug icon, changes can take effect.
If the target Eclipse is hanging or otherwise unresponsive, in the host Eclipse instance, the Console view (shown by navigating to Window | View | Show View | Other | General | Console menu) can be used to stop the target Eclipse instance.
Q1. What are the two ways of terminating a launched Eclipse instance?
Q2. What are launch configurations?
Q3. How are launch configurations created and deleted?
Now that the Eclipse plug-in is running, try the following:
Since it's rare that everything works first time, it's often necessary to develop iteratively, adding progressively more functionality each time. Secondly, it's sometimes necessary to find out what's going on under the cover when trying to fix a bug, particularly if it's a hard-to-track-down exception such as NullPointerException.
Fortunately, Eclipse comes with excellent debugging support, which can be used to debug both standalone Java applications as well as Eclipse plug-ins.
Debugging an Eclipse plug-in is much the same as running an Eclipse plug-in, except that breakpoints can be used, the state of the program can be updated, and variables and minor changes to the code can be made. Rather than debugging plug-ins individually, the entire Eclipse launch configuration is started in debug mode. That way, all the plug-ins can be debugged at the same time.
Although run mode is slightly faster, the added flexibility of being able to make changes makes debug mode much more attractive to use as a default.
Start the target Eclipse instance by navigating to Debug | Debug As | Eclipse Application, or by clicking on debug in the toolbar:
The debugger perspective will open whenever a breakpoint is triggered and the program will be paused. While it is paused, the target Eclipse is unresponsive. Any clicks on the target Eclipse application will be ignored, and it will show a busy cursor.
The built-in Eclipse debugger was used to launch Eclipse in debug mode. By triggering an action that led to a breakpoint, the debugger was revealed, allowing the local variables to be inspected.
When in the debugger, there are several ways to step through the code:
There is also a Run | Step into Selection menu item; it does not have a toolbar icon. It can be invoked with Ctrl + F5 (Alt + F5 on macOS) and is used to step into a specific expression.
When an Eclipse instance is launched in run mode, changes made to the source code aren't reflected in the running instance. However, debug mode allows changes made to the source to be reflected in the running target Eclipse instance:
By default, Eclipse ships with the Build Automatically option in Project menu enabled. Whenever changes are made to Java files, they are recompiled along with their dependencies if necessary.
When a Java program is launched in run mode, it will load classes on demand and then keep using that definition until the JVM shuts down. Even if the classes are changed, the JVM won't notice that they have been updated, and so no differences will be seen in the running application.
However, when a Java program is launched in debug mode, whenever changes to classes are made, Eclipse will update the running JVM with the new code if possible. The limits to what can be replaced are controlled by the JVM through the Java Virtual Machine Tools Interface (JVMTI). Generally, updating an existing method and adding a new method or field will work, but changes to interfaces and superclasses may not be.
The Hotspot JVM cannot replace classes if methods are added or interfaces are updated. Some JVMs have additional capabilities that can substitute more code on demand. Other JVMs, such as IBM's, can deal with a wider range of replacements.
Note that there are some types of changes that won't be picked up, for example, new extensions added to the plugin.xml file. In order to see these changes, it is possible to start and stop the plug-in through the command-line OSGi console, or restart Eclipse inside or outside of the host Eclipse to see the change.
When debugging using Step Into, the code will frequently go into Java internals, such as the implementation of Java collections classes or other internal JVM classes. These don't usually add value, so fortunately Eclipse has a way of ignoring uninteresting classes.
Step filters allow for uninteresting packages and classes to be ignored during step debugging:
Step Filters allows uninteresting packages to be skipped, at least from the point of debugging. Typically, JVM internal classes (such as those beginning with sun or sunw) are not helpful when debugging and can easily be ignored. This also avoids debugging through the ClassLoader as it loads classes on demand.
Typically it makes sense to enable all the default packages in the Step Filters dialog, as it's pretty rare to need to debug any of the JVM libraries (internal or public interfaces). This means that when stepping through code, if a common method such as toString is called, debugging won't step through the internal implementation.
It also makes sense to filter out simple setters and getters (those that just set a variable or those that just return a variable). If the method is more complex (like the getVariable method previously), then it will still stop in the debugger.
Constructors and static initializers can also be filtered specifically.
Although it's possible to place a breakpoint anywhere in a method, a special breakpoint type exists that can fire on method entry, exit, or both. Breakpoints can also be customized to only fire in certain situations or when certain conditions are met.
Method breakpoints allow the user to see when a method is entered or exited:
The breakpoint triggers at the time the method enters and subsequently when the method's return is reached. Note that the exit is only triggered if the method returns normally; if an uncaught exception is raised, it is not treated as a normal method exit, and so the breakpoint won't fire.
Other than the breakpoint type, there's no significant difference between creating a breakpoint on method entry and creating one on the first statement of the method. Both give the ability to inspect the parameters and do further debugging before any statements in the method itself are called.
The method exit breakpoint will only trigger once the return statement is about to leave the method. Thus any expression in the method's return value will have been evaluated prior to the exit breakpoint firing. Compare and contrast this with the line breakpoint, which will wait to evaluate the argument of the return statement.
Note that Eclipse's Step Return has the same effect; this will run until the method's return statement is about to be executed. However, to find when a method returns, using a method exit breakpoint is far faster than stopping at a specific line and then doing Step Return.
Breakpoints are useful since they can be invoked on every occasion when a line of code is triggered. However, they sometimes need to break for specific actions only—such as when a particular option is set, or when a value has been incorrectly initialized. Fortunately, this can be done with conditional breakpoints.
Normally breakpoints fire on each invocation. It is possible to configure breakpoints such that they fire when certain conditions are met; these are known as conditional breakpoints:
((org.eclipse.swt.widgets.Event)event.trigger).stateMask==65536
When a breakpoint is created, it is enabled by default. A breakpoint can be temporarily disabled, which has the effect of removing it from the flow of execution. Disabled breakpoints can be easily re-enabled on a per breakpoint basis, or from the Breakpoints view. Quite often it's useful to have a set of breakpoints defined in the code base, but not necessarily have them all enabled at once.
It is also possible to temporarily disable all breakpoints using the Skip All Breakpoints setting, which can be changed from the corresponding item in the Run menu (when the Debug perspective is shown) or the corresponding icon in the Breakpoints view. When this is enabled, no breakpoints will be fired.
Conditional breakpoints must return a value. If the breakpoint is set to break whether or not the condition is true, it must be a Boolean expression. If the breakpoint is set to stop whenever the value changes, then it can be any Java expression. Multiple statements can be used provided that there is a return keyword with a value expression.
Sometimes when debugging a program, an exception occurs. Typically this isn't known about until it happens, when an exception message is printed or displayed to the user via some kind of dialog box.
Although it's easy to put a breakpoint in the catch block, this is merely the location where the failure was ultimately caught, not where it was caused. The place where it was caught can often be in a completely different plug-in from where it was raised, and depending on the amount of information encoded within the exception (particularly if it has been transliterated into a different exception type) may hide the original source of the problem. Fortunately, Eclipse can handle such cases with a Java Exception Breakpoint:
window = null;
Caused by: java.lang.NullPointerException
at com.packtpub.e4.hello.ui.handlers.SampleHandler.execute
at org.eclipse.ui.internal.handlers.HandlerProxy.execute
at org.eclipse.ui.internal.handlers.E4HandlerProxy.execute
The Java Exception Breakpoint stops when an exception is thrown, not when it is caught. The dialog asks for a single exception class to catch, and by default, the wizard has been pre-filled with any class whose name includes *Exception*. However, any name (or filter) can be typed into the search box, including abbreviations such as FNFE for FileNotFoundException. Wildcard patterns can also be used, which allows searching for Nu*Ex or *Unknown*.
By default, the exception breakpoint corresponds to instances of that specific class. This is useful (and quick) for exceptions such as NullPointerException, but not so useful for ones with an extensive class hierarchy, such as IOException. In this case, there is a checkbox visible on the breakpoint properties and at the bottom of the breakpoints view, which allows the capture of all Subclasses of this exception, not just of the specific class.
There are also two other checkboxes that say whether the debugger should stop when the exception is Caught or Uncaught. Both of these are selected by default; if both are deselected, then the breakpoint effectively becomes disabled. Caught means that the exception is thrown in a corresponding try/catch block, and Uncaught means that the exception is thrown without a try/catch block (this bubbles up to the method's caller).
Finally, it's worth seeing what the Variables view can do:
The Eclipse debugger has many powerful features, and the ability to inspect (and change) the state of the program is one of the more important ones.
Watch expressions, when combined with conditional breakpoints, can be used to find out when data becomes corrupted or used to show the state of a particular object's value.
Expressions can also be evaluated based on objects in the variables view, and code completion is available to select methods, with the result being shown with Display.
Q1. How can an Eclipse plug-in be launched in debug mode?
Q2. How can certain packages be avoided when debugging?
Q3. What are the different types of breakpoints that can be set?
Q4. How can a loop that only exhibits a bug after 256 iterations be debugged?
Q5. How can a breakpoint be set on a method when its argument is null?
Q6. What does inspecting an object do?
Q7. How can the value of an expression be calculated?
Q8. How can multiple statements be executed in breakpoint conditions?
Using a conditional breakpoint to stop at a certain method is fine if the data is simple, but sometimes there needs to be more than one expression. Although it is possible to use multiple statements in the breakpoint condition definition, the code is not very reusable. To implement additional reusable functionality, the breakpoint can be delegated to a breakpoint utility class:
public class Utility {
public static boolean breakpoint() {
System.out.println("Breakpoint");
return false;
}
}
Utility.breakpoint(
((org.eclipse.swt.widgets.Event)event.trigger).stateMask != 0, "Breakpoint")
Utility.breakpoint(
((org.eclipse.swt.widgets.Event)event.trigger).stateMask != 0,
"Breakpoint %s %h",
event,
java.time.Instant.now())
In this article, we covered how to get started with Eclipse plug-in development. From downloading the right Eclipse package to getting started with a wizard-generated plug-in.
Specifically, we learned these things:
Now that we've learned how to get started with Eclipse plug-ins, we're ready to look at creating plug-ins that contribute to the IDE, starting with SWT and Views.
Further resources on this subject: