Since version 2.0 Spring supports an XSD-based configuration approach that allows integrating your own DSL for configuration into Spring. How to implement such namespace extension has been documented and the approach has been adopted by several Spring sub-projects and others, e.g. Spring Web Flow and DWR.
In response to an issue in our ticketing system and some comments I got recently, I’m going to introduce Spring IDE’s extension points for plugging in support for your own configuration namespace. These extension points allow you – as a custom namespace developer – to add support for navigation, content assist and validation to Spring IDE.
If you are familiar with the Eclipse architecture you might know that the platform uses so called extension points to dynamically add functionality. Every Eclipse plugin can define extension points and other plugins can contribute a custom implementation to that extension point. At runtime the plugin that exposes a certain extension point can then load the contribution and call into the implementation.
From an architectural view this is very similar to adding your XSD mapping and NamespaceHandler to Spring’s spring.schemas and spring.handlers files and let Spring call your NamespaceHandler to do the parsing your for custom configuration elements.
Spring IDE’s Namespace Extensions
To make a long story short, Spring IDE (currently) exposes three extension points to which you might want to contribute.
org.springframework.ide.eclipse.beans.core.namespaces
By contributing to this extension point you can add your Spring core NamespaceHandler implementation to Spring IDE. That is required because Spring IDE uses a Spring XmlBeanDefinitionParser internally and this parser does not pick up your Eclipse project classpath. Therefore even though you have your NamespaceHandler on the classpath of the project, it will not be picked by Spring IDE and your custom configuration elements will not be parsed. This contribution is required if you want your elements to show up in the Spring Explorer and Open Beans Dialog.org.springframework.ide.eclipse.beans.ui.namespaces
This extension point allows you to add UI related aspects to your configuration elements. You can add a label and custom images that will show up in the Spring Explorer and Beans Cross References View as well as in the Open Beans Dialog.org.springframework.ide.eclipse.beans.ui.editor.namespaces
Allows adding support for your custom namespace to the Beans XML Editor. The extension point declares several artefacts that enable you to add content assist and hyperlink navigation as well as some advanced features.
For those of you who have experience with developing Eclipse plugins have a look the Web Flow XML Editor which uses the above extension points to contribute support for the
A simple Example to start with
If you are not yet familiar with Eclipse plug-in development this is now the time you will implement your first plug-in. As a jumpstart I have prepared a sample plug-in that adds support for a very basis sample namespace. The namespace defines a
Let’s start with the following Spring configuration. The source for the NamespaceHandler and the XSD is available here.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:db="http://www.springframework.org/schema/db"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.sfw.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/db
http://www.sfw.org/schema/db/spring-db-2.0.xsd">
<db:driver-manager-data-source id="db1"
driver-class-name="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@host:port:sid" />
</beans>
In order to add support for that namespace we need to create an Eclipse Plug-in Project. You can download the sample plug-in project here. Import the project into an Eclipse installation that has Spring IDE (at least M3) installed.
Looking at the MANIFEST.MF in the META-INF directory will reveal the plug-in’s dependencies.
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-SymbolicName: org.sfw….namespace.db;singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: org.sfw.samples.ide.eclipse.namespace.db.Activator
Bundle-Localization: plugin
Bundle-ClassPath: spring-db.jar,
.
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources,
org.eclipse.core.runtime,
org.eclipse.jface.text,
org.eclipse.ui,
org.eclipse.ui.ide,
org.eclipse.ui.workbench.texteditor,
org.eclipse.jdt.core,
org.eclipse.jdt.ui,
org.eclipse.wst.sse.core,
org.eclipse.wst.sse.ui,
org.eclipse.wst.xml.core,
org.eclipse.wst.xml.ui,
org.springframework,
org.springframework.ide.eclipse.core
org.springframework.ide.eclipse.beans.core,
org.springframework.ide.eclipse.beans.ui,
org.springframework.ide.eclipse.beans.ui.editor,
Eclipse-LazyStart: true
Bundle-RequiredExecutionEnvironment: J2SE-1.5
As you can see the sample namespace plug-in requires five OSGi bundles from the Spring IDE project. These plug-ins expose the extension points from above and provide utility classes and functionality that helps implementing a namespace contribution.
The project contains the plugin.xml. That file declares the contributions to the above mentioned extension points.
<?eclipse version="3.0"?>
<plugin>
<!– Contribution to the Eclipse WTP XML Catalog –>
<extension point="org.eclipse.wst.xml.core.catalogContributions">
<catalogContribution>
<public publicId="http://www.sfw.org/schema/db"
uri="jar:spring-db.jar!/org/sfw/config/spring-db-2.0.xsd"
webURL="http://www.sfw.org/schema/db/spring-db-2.0.xsd" />
</catalogContribution>
<catalogContribution>
<system
systemId="http://www.sfw.org/schema/db/spring-db-2.0.xsd"
uri="jar:spring-db.jar!/org/sfw/config/spring-db-2.0.xsd" />
</catalogContribution>
</extension>
<!– Contribution to the Spring Core namespace handler. Required to load the
Spring XML file by Spring IDE. –>
<extension
point="org.sfw.ide.eclipse.beans.core.namespaces">
<namespace
namespaceHandler="org.sfw…config.DbNamespaceHandler"
uri="http://www.sfw.org/schema/db" />
</extension>
<!– Contribution to the Spring IDE UI. Drives image and label in Spring Explorer –>
<extension
point="org.sfw.ide.eclipse.beans.ui.namespaces">
<namespace
labelProvider="org.sfw…db.DbLabelProvider"
uri="http://www.sfw.org/schema/db" />
</extension>
<!– Contribution to the Spring IDE XML Editor. Drives content assist, hyperlink –>
<extension
point="org.sfw.ide.eclipse.beans.ui.editor.namespaces">
<namespace
contentAssistProcessor="org.sfw…db.DbContentAssistProcessor"
elementLocator="org.sfw….DefaultReferenceableElementsLocator"
hyperLinkDetector="org.sfw…db.DbHyperLinkDetector"
labelProvider="org.sfw…db.DbOutlineLabelProvider"
name="Spring DB Config"
uri="http://www.sfw.org/schema/db" />
</extension>
</plugin>
Contributing to org.eclipse.wst.xml.core.catalogContributions extension point will add your XSD to Eclipse’ internal XML Catalog and enable the internal schema validation and code completion of the WTP XML Edtior.
For more details feel free to have a look at the implementation classes that are referenced in the plugin.xml. You will note that the contained logic is very basic. Usually the most complex class is the contentAssistProcessor of the ...beans.ui.editor.namespaces extension point.
Next you will find the code required to add content assist proposals for the driver-class-name and the connection-properties-ref attribute. The completion proposals for the driver-class-name attribute certainly should only contain implementations of the java.sql.Driver interface.
extends AbstractContentAssistProcessor {
/**
* Adds content assist proposals for attribute value requests
* @param request the content assist request
* @param node the node
* @param matchString the prefix the user has entered
* @param attributeName the attributeName
*/
@Override
protected void computeAttributeValueProposals(
ContentAssistRequest request, IDOMNode node,
String matchString, String attributeName) {
String nodeName = node.getLocalName();
if ("driver-manager-data-source".equals(nodeName)) {
if ("driver-class-name".equals(attributeName))
{
BeansJavaCompletionUtils
.addTypeHierachyAttributeValueProposals(request,
matchString, Driver.class.getName());
}
else if ("connection-properties-ref".equals(attributeName))
{
BeansCompletionUtils.addBeanReferenceProposals(request,
matchString, node.getOwnerDocument(), true);
}
}
}
Notes about Custom NamespaceHandler Implementations
Your NamespaceHandler and especially our BeanDefinitionParser implementations needs to be good citizens in order to get full support by Spring IDE. That is because Spring IDE relies on the Spring Tooling API. Even if you don’t plan to add your NamespaceHandler to Spring IDE it is a very good idea to keep the following rules of thumb in mind while implementing a custom namespace.
Don’t fail fast - Do not throw any IllegalArgumentException or other kind of Exceptions in order to propagate missing attribute values while parsing. There is an API that should be used for that. By using the ParserContext you can get hold of an ErrorReporter instance to report errors and warnings.
The following example is taken from SWF’s ExecutorBeanDefinitionParser:
parserContext.getReaderContext().error(
"The ‘repositoryType’ attribute of the ‘executor’" +
"element must not have a value if there is a " +
‘repository’ element", element);
}
Attach source information - If you want exact navigation support your need to attach the source information to the BeanDefintion while parsing. Doing so will allow Spring IDE to directly navigate to the XML source location if the user double-clicks your custom Bean in e.g. the Spring Explorer or the Open Beans Dialog.
Again there is an API to achieve this. Use the BeanDefinitionBuilder.setSource() method to set the source information. The source information is accessible by using the ParserContext.extractSource() method.
Element element, ParserContext parserContext) {
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(FlowExecutorFactoryBean.class);
definitionBuilder.setSource(parserContext.
extractSource(element));
…
return definitionBuilder.getBeanDefinition();
}
Don’t load classes - To construct Spring Bean Definitions - and that is what a BeanDefinitionParser is meant for - it should not be required to load classes from your application; use Strings in order define the bean class and not something like MyApplication.class.getName(). Spring IDE does not have access to classes that are part of your application and therefore your namespace extension will fail to load.
Conclusion
Using Spring IDE’s extension points should enable you to add support for your custom namespace and therefore help streamlining your development experience with the Eclipse Platform.
The extension points as well as the other features of Spring IDE version 2.0 are still a moving target. Nevertheless you shouldn’t expect a major API change in the extension points or involved interfaces. If you have questions or concerns leave us a comment or open a issue report in our ticket system.
Disclaimer: The Spring IDE team will certainly support every namespace developer that wants to add their namespace to Spring IDE. But we will not add support for any namespace other than the ones defined in core Spring or official Spring sub-projects by ourself.
Update: With version 2.0.5 of Spring some of the API of BeanDefinitionBuilder and AbstractSingleBeanDefinitionParser has been improved to better suite Spring IDE. Read more here.


Hi, i’ve been trying with no luck to reproduce the example here. I’ve download the plugin and it throws several (100) items on the problems view. I’ve tried to extract the libraries required from the M3 release of the Spring IDE plugin with no luck. It seems that it relays on later versions of the code in order to work.
I’ve also tried to download all the projects from the repository in order
to make the plugin work but also without luck. Code throws errors about methods that must override a superclass methods…. and when i solve one problem another shows up.
Is the example presented here still valid or is there any hint you can give me in order to get the example to work?
many thanks in advance.
Angel
Here are some usage and installation instructions for the sample namespace plugin:
springide_updatesite_dev_2.0-m4_v200704170600or greater as I fixed some packaging issue that prevented plugin developers to import classes from Spring IDE OSGi bundles.Hope that helps. Thanks for addressing the issue with the sample plugin as it brought up issues with our bundle packaging.
In example:
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder .rootBeanDefinition(FlowExecutorFactoryBean.class);And then follows:
Don’t load classes - To construct Spring Bean Definitions - and that is what a BeanDefinitionParser is meant for - it should not be required to load classes from your application; use Strings in order define the bean class and not something like MyApplication.class.getName().
Is it wrong example? Besides AbstractSingleBeanDefinitionParser requires to use overrided method
protected abstract Class getBeanClass(Element element);
where loaded class returns, not String as suggested in article.
Indeed the example is not really clever… Although it makes a difference if we are talking about a third-party namespace or one that is shipped with Spring. Spring IDE has access to every class from Spring and Spring Web Flow. So therefore the example works with Spring IDE, but wouldn’t work with classes from your own application.
The AbstractSingleBeanDefinitionParser will get another method getBeanClassName (both methods will not be abstract and at least one must return a value) in Spring 2.1. Until then you shouldn’t use the class for your own custom namespace.
BTW. There is the http://www.springframework.org/schema/tool namespace with tags for annotating schema elements for custom namespaces with meta information. This information can cover about 80% of typical cases needed for namespace tooling like completion and navigation of custom tags, without a custom IDE plugin. Will Spring IDE support the http://www.springframework.org/schema/tool xsd annotations?
Yes, I was thinking about that a while ago. Feel free to open an enhancement request in our ticketing system. I think that could be added in a after-2.0 release.
But still you would need to provide the XSD either as a plugin or a XML catalog extension.
bonjour,
je viens d’installer Spring IDE mais malheureusement, tous les flows sont indiqués en erreur(ex: Referenced action method “affichageInfosArticle” cannot be found or is not a valid action method”)
Que puis-je faire ?
Excellent article. Does Spring IDE namespace provide support for content assistance on just the interfaces. I know right know it supports the classes.