Spring in Practice

Willie Wheeler's Spring blog

The Spring Constructor Namespace

| Comments

You know the p namespace? It’s the one that cleans up your Spring configuration files by providing a shorthand for injecting beans and values:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation=
       "http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
        p:dataSource-ref="dataSource"
        p:packagesToScan="com.springinpractice.ch10.model" />

    ... other beans ...

</beans>

Did you know that Spring 3.1 introduces an analogous namespace for constructor injection? Yup—it’s the c namespace:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation=
       "http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
        
    <bean id="connectionFactoryLocator"
        class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
        <property name="connectionFactories">
            <list>
                <bean class="org.springframework.social.github.connect.GitHubConnectionFactory"
                    c:clientId="${gitHub.clientId}"
                    c:clientSecret="${gitHub.clientSecret}" />
            </list>
        </property>
    </bean>
    
    <bean id="usersConnectionRepository"
        class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository"
        c:dataSource-ref="dataSource"
        c:connectionFactoryLocator-ref="connectionFactoryLocator"
        c:textEncryptor-ref="textEncryptor" />
    
    ... other beans ...

</beans>

It works pretty much the same way, but for constructors. You can inject values, or else you can inject references using the -ref suffix.

With p, the XML element name comes from the bean property name, but with constructors that’s not available. Instead, for c we use the name of the constructor parameter itself. So for JdbcUsersConnectionRepository we’re calling a constructor that looks like this:

public JdbcUsersConnectionRepository(DataSource dataSource, ConnectionFactoryLocator connectionFactoryLocator, TextEncryptor textEncryptor)

where it’s the parameter names themselves (rather than the parameter types) driving the XML element names.

But keep this in mind…

The c namespace is great, but there’s something you may not have considered. Because the XML element names come from the constructor parameter names, we have to compile the app in debug mode if we want to use this feature (otherwise the local variable names aren’t in the class files), and we want to pay attention to the parameter names we choose. So, for instance, ds, cfl and te wouldn’t be very good constructor parameter names.

Note that Spring (especially Spring Web MVC) has been using parameter names in this fashion for a long time, so that’s nothing new. The @PathVariable and @RequestParam annotations, for example, default to using parameter names when explicit names aren’t specified. But in the case of the c namespace, a bean that supports c-based injection ought to publish the constructor parameter names, and they become in effect part of the API.

Update

I’ve had a bit of a change of heart regarding the constructor namespace. Here’s why I think the Spring constructor namespace is a bad idea.

Comments