Source code for this tutorial is available on github as a single zip archive, as a Team Project Set or you can browse the files online.
Step 1: Creating the builder
This is the easy part. Create a new Plug-in project named com.codeandme.custombuilder and switch to the Extensions tab of the plugin.xml.
Add an extension for org.eclipse.core.resources.builders. Set the ID to com.codeandme.custombuilder.myBuilder, leave the builder settings empty and create a run entry below. There set the class to com.codeandme.custombuilder.MyBuilder. Implement the class with following code:
package com.codeandme.custombuilder.builders; import java.util.Map; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; public class MyBuilder extends IncrementalProjectBuilder { public static final String BUILDER_ID = "com.codeandme.custombuilder.myBuilder"; @Override protected IProject[] build(final int kind, final Map<String, String> args, final IProgressMonitor monitor) throws CoreException { System.out.println("Custom builder triggered"); // get the project to build getProject(); switch (kind) { case FULL_BUILD: break; case INCREMENTAL_BUILD: break; case AUTO_BUILD: break; } return null; } }
Do not forget to add a plug-in dependency for org.eclipse.core.runtime.
Your builder is done. Sure you need to add functionality to it, but this is your part. So now what? We need to add the builder to projects. To selectively add a builder eclipse suggests to use the Configure entry in the popup menu of projects.
Step 2: Create context menu entries
First lets create the commands to add and remove our builder.
Add the command definitions to your plugin.xml
<command defaultHandler="com.codeandme.custombuilder.commands.AddBuilder" id="com.codeandme.custombuilder.addBuilder" name="Add Custom Builder"> </command> <command defaultHandler="com.codeandme.custombuilder.commands.RemoveBuilder" id="com.codeandme.custombuilder.removeBuilder" name="Remove Custom Builder"> </command>
At the same time we can add some additional dependencies:
- org.eclipse.core.commands
- org.eclipse.jface
- org.eclipse.ui
package com.codeandme.custombuilder.commands; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.IHandler; import org.eclipse.core.resources.ICommand; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.ui.handlers.HandlerUtil; import com.codeandme.custombuilder.builders.MyBuilder; public class AddBuilder extends AbstractHandler implements IHandler { @Override public Object execute(final ExecutionEvent event) { final IProject project = getProject(event); if (project != null) { try { // verify already registered builders if (hasBuilder(project)) // already enabled return null; // add builder to project properties IProjectDescription description = project.getDescription(); final ICommand buildCommand = description.newCommand(); buildCommand.setBuilderName(MyBuilder.BUILDER_ID); final List<ICommand> commands = new ArrayList<ICommand>(); commands.addAll(Arrays.asList(description.getBuildSpec())); commands.add(buildCommand); description.setBuildSpec(commands.toArray(new ICommand[commands.size()])); project.setDescription(description, null); } catch (final CoreException e) { // TODO could not read/write project description e.printStackTrace(); } } return null; } public static IProject getProject(final ExecutionEvent event) { final ISelection selection = HandlerUtil.getCurrentSelection(event); if (selection instanceof IStructuredSelection) { final Object element = ((IStructuredSelection) selection).getFirstElement(); return (IProject) Platform.getAdapterManager().getAdapter(element, IProject.class); } return null; } public static final boolean hasBuilder(final IProject project) { try { for (final ICommand buildSpec : project.getDescription().getBuildSpec()) { if (MyBuilder.BUILDER_ID.equals(buildSpec.getBuilderName())) return true; } } catch (final CoreException e) { } return false; } }
package com.codeandme.custombuilder.commands; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.eclipse.core.resources.ICommand; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.runtime.CoreException; import com.codeandme.custombuilder.builders.MyBuilder; public class RemoveBuilder extends AbstractHandler implements IHandler { @Override public Object execute(final ExecutionEvent event) throws ExecutionException { final IProject project = AddBuilder.getProject(event); if (project != null) { try { final IProjectDescription description = project.getDescription(); final List<ICommand> commands = new ArrayList<ICommand>(); commands.addAll(Arrays.asList(description.getBuildSpec())); for (final ICommand buildSpec : description.getBuildSpec()) { if (MyBuilder.BUILDER_ID.equals(buildSpec.getBuilderName())) { // remove builder commands.remove(buildSpec); } } description.setBuildSpec(commands.toArray(new ICommand[commands.size()])); project.setDescription(description, null); } catch (final CoreException e) { // TODO could not read/write project description e.printStackTrace(); } } return null; } }
When retrieving the selected project we need to use the AdapterManager as some project types do not directly implement IProject (that is, if I remember correctly). Then we parse the build specification to add or remove our custom builder.
To add those commands to the Configure context menu we create a new menu contribution for popup:org.eclipse.ui.projectConfigure?after=additions
<extension point="org.eclipse.ui.menus"> <menuContribution allPopups="false" locationURI="popup:org.eclipse.ui.projectConfigure?after=additions"> <command commandId="com.codeandme.custombuilder.addBuilder" style="push"> </command> <command commandId="com.codeandme.custombuilder.removeBuilder" style="push"> </command> </menuContribution> </extension>Now you should be able to add and remove your builder.
Step 3: Selectively activate context menu entries
Only one of the commands makes sense regarding the current builder settings of a project. To enrich the user experience we will hide the invalid one.
Therefore we need to use a PropertyTester and some visibleWhen expressions as we did before in Property testers and Expression examples.
Create a new propertyTesters extension.
<extension point="org.eclipse.core.expressions.propertyTesters"> <propertyTester class="com.codeandme.custombuilder.propertytester.TestBuilderEnabled" id="com.codeandme.custombuilder.myBuilderTester" namespace="com.codeandme.custombuilder" properties="isEnabled" type="java.lang.Object"> </propertyTester> </extension>
We leave the type to java.lang.Object as not all project types use a common base class (except Object of course). Implementing the property tester is straight forward:
package com.codeandme.custombuilder.propertytester; import org.eclipse.core.expressions.PropertyTester; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.Platform; import com.codeandme.custombuilder.commands.AddBuilder; public class TestBuilderEnabled extends PropertyTester { private static final String IS_ENABLED = "isEnabled"; @Override public boolean test(final Object receiver, final String property, final Object[] args, final Object expectedValue) { if (IS_ENABLED.equals(property)) { final IProject project = (IProject) Platform.getAdapterManager().getAdapter(receiver, IProject.class); if (project != null) return AddBuilder.hasBuilder(project); } return false; } }
Now add some visibleWhen expressions to your menu entries. View the final version of the plugin.xml online.
You don't need a tester for that, as the core expressions gives you access to the project nature, and natures are the only allowed way to link builders to projects:
ReplyDelete<visibleWhen
checkEnabled="false">
<with
variable="selection">
<count
value="1">
</count>
<iterate>
<and>
<instanceof
value="org.eclipse.core.resources.IProject">
</instanceof>
<test
property="org.eclipse.core.resources.projectNature"
value="your.nature">
</test>
</and>
</iterate>
</with>
</visibleWhen>
hi..
ReplyDeletei have a builder and i need to specify that .. how can i do that with this code. here adding and removing of builder is giver.. how can i tell about my builder.
I do not get your point. This tutorial shows how to register a dedicated builder. Use the MyBuilder.build() method to execute whatever code you need.
DeleteThis tutorial also shows just one way of attaching a builder. You could also create a new project wizard that creates a dedicated project where your special builder class is registered on project creation
actually i have compiler. and in eclipse like jdt .. we are running a code as java aplication like that i need to run my code with my compiler. how can i do that
Deleteif i need to specify a path of my bulder, and i need that builder in that,, how can i do that
ReplyDeletetypically you would put a prefs file to a project folder. ".settings/myprefs" is recommended. For configuration you would have to amend project properties though.
DeleteCan I trigger a builder(ex: jdt or cdt) from custom builder? I wanted to do few modifications before the build starts. Is that possible?
ReplyDeleteI am pretty sure of, however I do not know how exactly to trigger a JDT build programmatically. Best ask that on the jdt mailing list.
DeleteYou might want to check out the TEA project which allows great flexibility in defining your build process:
https://projects.eclipse.org/proposals/eclipse-tea-tasking-engine-advanced
I don't understand how the AddBuilder command registers the MyBuilder class as a builder. The only reference it makes to it is MyBuilder.BUILDER_ID, but this value does not identify the MyBuilder class. Is there an error in the tutorial, and this String is supposed to be the fully qualified class name? If not, then how is the MyBuilder class actually being registered?
ReplyDeleteSee step 1 of the tutorial. There we create an extension for the builder in our plugin.xml. The extension uses an ID which we store in the BUILDER_ID. That is how eclipse is able to find our builder later on.
DeleteThanks. Sorry I missed that paragraph.
DeleteNice article. There is more arraylist examples collection Arraylist Examples
ReplyDeleteHaving these professionals hired can make a huge difference. It is always necessary that you make the right Architectural Builders Eastern Suburbs choices. Through internet you can compare and find out the best architecture designing services. Hope to serve you the best!
ReplyDeleteThanks for sharing this great construction post! but I highly recommend Activa Homes Group they offer Custom Builders Perth service at affordable prices.
ReplyDelete