Resource markers
We know that plug-ins can define specialized file extensions and contribute editors that provide
specialized editing features for these file types. During the course of editing (or building) a resource, a plug-in may need to tag resources to communicate problems or other information to the user. The resource marker mechanism is used to manage this kind of information.
A marker is like a yellow sticky note stuck to a resource. On the marker you can record information about a
problem (e.g., location, severity) or a task to be done. Or you can simply
record a location for a marker as a bookmark.
Users can quickly jump to the marked location within a resource. The workbench UI supports presentation of
bookmarks, breakpoints, tasks, and problems along the side of the editor.
These markers can also be shown as items in views, such as the tasks or bookmarks view.
The platform resources API defines methods for creating markers, setting marker values, and extending the platform with new marker types. While the platform manages markers, it is the plug-ins that control their creation, removal and attribute values.
Markers are intended to be small, lightweight objects. There could be hundreds, even thousands of markers in a single
project. For example, the Java compiler uses a marker to flag each problem
it finds in source code.
The platform will throw away markers attached to resources that are deleted, but plug-ins are responsible for removing
their stale markers when they no longer apply to a resource that still exists.
Marker operations
Manipulating a marker is similar to manipulating a resource. Markers are handle
objects. You can obtain a marker handle from a resource, but you don't
know if it actually exists until you use exists()
protocol or otherwise try to manipulate it. Once you've established that a
marker exists, you can query named attributes that may have been assigned to it.
Markers are owned and managed by the platform, which takes care of making
markers persistent and notifying listeners as markers are added, deleted, or
changed. Plug-ins are responsible for creating any necessary markers, changing their attributes, and removing them when they are
no longer needed.
Marker creation
Markers are not directly created using a constructor. They are created using a factory method
(IResource.createMarker()) on the associated resource.
IMarker marker = file.createMarker(IMarker.TASK);
To create a marker that has global scope (not associated with any specific resource), you can use
the workspace root
(IWorkspace.getRoot()) as the resource.
Marker deletion
The code for deleting a marker is straightforward.
try {
marker.delete();
} catch (CoreException e) {
// Something went wrong
}
When a marker is deleted, its marker object (handle) becomes "stale." Plug-ins should use the
IMarker.exists() protocol to make sure a marker object is still valid.
Markers can be deleted in batch by asking a resource to delete its markers. This method is useful when removing
many markers at once or if individual marker references or ids are not available.
int depth = IResource.DEPTH_INFINITE;
try {
resource.deleteMarkers(IMarker.PROBLEM, true, depth);
} catch (CoreException e) {
// something went wrong
}
When deleting a group of markers, you specify a marker type to delete, such as IMarker.PROBLEM, or
null to delete all markers. The second argument
indicates whether you want to delete subtype markers. (We'll look a
subtypes in a moment when we define new marker types.) The depth argument controls the depth of deletion.
You can also delete markers using IWorkspace.deleteMarkers(IMarker
[]).
Marker attributes
Given a marker, you can ask for its associated resource, its id (unique relative to that resource), and its type. You can also access additional information
via generic attributes.
Each type of marker has a specific set of attributes that are defined by the
creator of the marker type using naming conventions. The
IMarker
interface defines a set of constants containing
the standard attribute names (and some of the expected values) for the platform marker types. The following method manipulates attributes using the platform constants.
IMarker marker = file.createMarker(IMarker.TASK);
if (marker.exists()) {
try {
marker.setAttribute(IMarker.MESSAGE, "A sample marker message");
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
} catch (CoreException e) {
// You need to handle the case where the marker no longer exists }
}
Attributes are maintained generically as name/value pairs, where the names are strings and a value can be any one of the supported value types
(boolean, integer, string). The limitation on value types allows the platform to persist the markers quickly and simply.
Querying markers
Resources can be queried for their markers and the markers of their children. For example, querying the workspace root with infinite depth considers all of the markers in the workspace.
IMarker[] problems = null;
int depth = IResource.DEPTH_INFINITE;
try {
problems = resource.findMarkers(IMarker.PROBLEM, true, depth);
} catch (CoreException e) {
// something went wrong
}
The result returned by findMarkers depends on
the arguments passed. In the snippet above, we are looking for all markers
of type PROBLEM that appear on the resource and
all of its direct and indirect descendants.
If you pass
null as the marker type, you will get all the
marker types associated with the resource. The second argument specifies whether
you want to look at the resource's children. The
depth argument controls the depth of the search
when you are looking at the resource's children. The depth can be DEPTH_ZERO
(just the given resource), DEPTH_ONE (the resource and all
of its direct children) or
DEPTH_INFINITE (the resource and all of its direct and indirect
descendants).
Marker persistence
The platform standard markers (task, problem, and bookmark) are persistent. This means that their state will be saved across workbench shutdown and startup.
However, markers of a persistent type may be selectively made transient by setting the reserved attribute transient to true.
New marker types declared by plug-ins are not persistent unless they are declared as such.
Plug-ins can declare their own marker types using the
org.eclipse.core.resources.markers
extension point. The standard marker types for problems, tasks and bookmarks are declared by the platform in the resources plug-in's markup.
<extension
id="problemmarker"
point="org.eclipse.core.resources.markers"
name="%problemName">
<super type="org.eclipse.core.resources.marker"/>
<persistent value="true"/>
<attribute name="severity"/>
<attribute name="message"/>
<attribute name="location"/>
</extension>
<extension
id="taskmarker"
point="org.eclipse.core.resources.markers"
name="%taskName">
<super type="org.eclipse.core.resources.marker"/>
<persistent value="true"/>
<attribute name="priority"/>
<attribute name="message"/>
<attribute name="done"/>
<attribute name="userEditable"/>
</extension>
<extension
id="bookmark"
point="org.eclipse.core.resources.markers"
name="%bookmarkName">
<super type="org.eclipse.core.resources.marker"/>
<persistent value="true"/>
<attribute name="message"/>
<attribute name="location"/>
</extension>
New marker types are derived from existing ones using multiple inheritance. New marker types inherit all of the attributes from their
super types and add any new attributes defined as part of the declaration. They also transitively inherit
attributes from the super types of their super types. The following markup defines a new kind of marker in a hypothetical
com.example.markers plug-in.
<extension
id="mymarker"
point="org.eclipse.core.resources.markers" />
<extension
id="myproblem"
point="org.eclipse.core.resources.markers">
<super type="org.eclipse.core.resources.problemmarker"/>
<super type="com.example.markers.mymarker"/>
<attribute name="myAttribute" />
<persistent value="true" />
</extension>
Note that the type org.eclipse.core.resources.problemmarker is actually one of the pre-defined types (aka
IMarker.PROBLEM).
The only aspect of a marker
super type that is not inherited is its persistence flag.
The default value for persistence is false, so any marker type that should be
persistent must specify <persistent
value="true"/>.
After declaring the new marker type in your plug-in manifest file, you can create instances of
com.example.markers.myproblem marker type and freely set or get the
myAttribute attribute.
Declaring new attributes allows you to associate data with markers that you plan to use elsewhere (in your
views and editors). Markers of a particular type do not have to have values for all of the declared attributes. The attribute declarations are more for solving naming convention problems (so everyone uses "message" to talk about a marker's description) than
for constraining content.
public IMarker createMyMarker(IResource resource) {
try {
IMarker marker = resource.createMarker("com.example.markers.myproblem");
marker.setAttribute("myAttribute", "MYVALUE");
return marker;
} catch (CoreException e) {
// You need to handle the cases where attribute value is rejected
}
}
You can query your own marker types in the same way you query the platform marker
types. The method below finds all mymarkers associated with the given target resource and all
of its descendents. Note that this will also find all
myproblems since true is passed for the includeSubtypes
argument.
public IMarker[] findMyMarkers(IResource target) {
String type = "com.example.markers.mymarker";
IMarker[] markers = target.findMarkers(type, true, IResource.DEPTH_INFINITE);
}