Archive

Posts Tagged ‘spring’

Discover Spring authoring

December 29th, 2009 No comments

In this article, I will describe a useful but much underused feature of Spring, the definition of custom tags in the Spring beans definition files.

Spring namespaces

I will begin with a simple example taken from Spring’s documentation. Before version 2.0, only a single XML schema was available. So, in order to make a constant available as a bean, and thus inject it in other beans, you had to define the following:

<bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE"
    class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" />

Spring made it possible, but realize it’s only a trick to expose the constant as a bean. However, since Spring 2.0, the framework let you use the util namespace so that the previous example becomes:

<util:constant static-field="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>

In fact, there are many namespaces now available:

Prefix Namespace Description
bean http://www.springframework.org/schema/bean Original bean schema
util http://www.springframework.org/schema/util Utilities: constants, property paths and collections
util http://www.springframework.org/schema/jee JNDI lookup
lang http://www.springframework.org/schema/lang Use of other languages
tx http://www.springframework.org/schema/tx Transactions
aop http://www.springframework.org/schema/aop AOP
context http://www.springframework.org/schema/context ApplicationContext manipulation

Each of these is meant to reduce verbosity and increase readibility like the first example showed.

Authoring

What is still unknown by many is that this feature is extensible that is Spring API provides you with the mean to write your own. In fact, many framework providers should take advantage of this and provide their own namespaces so that integrating thier product with Spring should be easier. Some already do: CXF with its many namespaces comes to mind but there should be others I don’t know of.

Creating you own namespace is a 4 steps process: 2 steps about the XML validation, the other two for creating the bean itself. In order to illustrate the process, I will use a simple example: I will create a schema for EhCache, the Hibernate’s default caching engine.

The underlying bean factory will be the existing EhCacheFactoryBean. As such, it won’t be as useful as a real feature but it will let us focus on the true authoring plumbing rather than EhCache implementation details.

Creating the schema

Creating the schema is about describing XML syntax and more importantly restrictions. I want my XML to look something like the following:

<ehcache:cache id="myCache" eternal="true" cacheName="foo"
maxElementsInMemory="5" maxElementsOnDisk="2" overflowToDisk="false"
diskExpiryThreadIntervalSeconds="18" diskPersistent="true" timeToIdle="25" timeToLive="50"
memoryStoreEvictionPolicy="FIFO">
  <ehcache:manager ref="someManagerRef" />
</ehcache:echcache>

Since I won’t presume to teach anyone about XML, here’s the schema. Just notice the namespace declaration:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://blog.frankel.ch/spring/ehcache" xmlns="http://blog.frankel.ch/spring/ehcache"
  elementFormDefault="qualified">
  <xsd:complexType name="cacheType">
    <xsd:sequence maxOccurs="1" minOccurs="0">
      <xsd:element name="manager" type="managerType" />
    </xsd:sequence>
    <xsd:attribute name="id" type="xsd:string" />
    <xsd:attribute name="cacheName" type="xsd:string" />
    <xsd:attribute name="diskExpiryThreadIntervalSeconds" type="xsd:int" />
    <xsd:attribute name="diskPersistent" type="xsd:boolean" />
    <xsd:attribute name="eternal" type="xsd:boolean" />
    <xsd:attribute name="maxElementsInMemory" type="xsd:int" />
    <xsd:attribute name="maxElementsOnDisk" type="xsd:int" />
    <xsd:attribute name="overflowToDisk" type="xsd:boolean" />
    <xsd:attribute name="timeToLive" type="xsd:int" />
    <xsd:attribute name="timeToIdle" type="xsd:int" />
    <xsd:attribute name="memoryStoreEvictionPolicy" type="memoryStoreEvictionPolicyType" />
  </xsd:complexType>
  <xsd:simpleType name="memoryStoreEvictionPolicyType">
    <xsd:restriction base="xsd:string">
      <xsd:enumeration value="LRU" />
      <xsd:enumeration value="LFU" />
      <xsd:enumeration value="FIFO" />
    </xsd:restriction>
  </xsd:simpleType>
  <xsd:complexType name="managerType">
    <xsd:attribute name="ref" type="xsd:string" />
  </xsd:complexType>
  <xsd:element name="cache" type="cacheType" />
</xsd:schema>

And for those, like me, that prefer a graphic display:

Mapping the schema

The schema creation is only the first part. Now, we have to make Spring aware of it. Create the file META-INF/spring.schemas and write in the following line is enough:

http\://blog.frankel.ch/spring/schema/custom.xsd=ch/frankel/blog/spring/authoring/custom.xsd

Just take care to insert the backslash, otherwise it won’t work. It maps the schema declaration in the XML to the real file that will be used from the jar!

Before going further, and for the more curious, just notice that in spring-beans.jar (v3.0), there’s such a file. Here is it’s content:

http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd

It brings some remarks:

  • Spring eat their own dogfood (that’s nice to know)
  • I didn’t look into the code but I think that’s why XML validation of Spring’s bean files never complain about not finding the schema over the Internet (a real pain in production environment because of firewall security issues). That’s because the XSD are looked inside the jar
  • If you don’t specify the version of the Spring schema you use (2.0, 2.5, 3.0, etc.), Spring will automatically upgrade it for you with each major/minor version of the jar. If you want this behaviour, fine, if not, you’ll have to specify version

Creating the parser

The previous steps are only meant to validate the XML so that the eternal attribute will take a boolean value, for example. We still did not wire our namespace into Spring factory. This is the goal of this step.

The first thing to do is create a class that implement org.springframework.beans.factory.xml.BeanDefinitionParser. Looking at its hierarchy, it seems that the org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser is a good entry point since:

  • the XML is not overly complex
  • there will be a single bean definition

Here’s the code:

public class EhCacheBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {

  private static final List&amp;amp;amp;amp;amp;amp;lt;String&amp;amp;amp;amp;amp;amp;gt; PROP_TAG_NAMES;

  static {

  PROP_TAG_NAMES = new ArrayList();

    PROP_TAG_NAMES.add("eternal");
    PROP_TAG_NAMES.add("cacheName");
    PROP_TAG_NAMES.add("maxElementsInMemory");
    PROP_TAG_NAMES.add("maxElementsOnDisk");
    PROP_TAG_NAMES.add("overflowToDisk");
    PROP_TAG_NAMES.add("diskExpiryThreadIntervalSeconds");
    PROP_TAG_NAMES.add("diskPersistent");
    PROP_TAG_NAMES.add("timeToLive");
    PROP_TAG_NAMES.add("timeToIdle");
  }

  @Override
  protected Class getBeanClass(Element element) {

    return EhCacheFactoryBean.class;
  }

  @Override
  protected boolean shouldGenerateIdAsFallback() {

    return true;
  }

  @Override
  protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {

    for (String name : PROP_TAG_NAMES) {

      String value = element.getAttribute(name);

      if (StringUtils.hasText(value)) {

        builder.addPropertyValue(name, value);
      }
    }

    NodeList nodes = element.getElementsByTagNameNS("http://blog.frankel.ch/spring/ehcache", "manager");

    if (nodes.getLength() &amp;amp;amp;amp;amp;amp;gt; 0) {

      builder.addPropertyReference("cacheManager",
        nodes.item(0).getAttributes().getNamedItem("ref").getNodeValue());
    }

    String msep = element.getAttribute("memoryStoreEvictionPolicy");

    if (StringUtils.hasText(msep)) {

      MemoryStoreEvictionPolicy policy = MemoryStoreEvictionPolicy.fromString(msep);

      builder.addPropertyValue("memoryStoreEvictionPolicy", policy);
    }
  }
}

That deserves some explanations. The static block fills in what attributes are valid. The getBeanClass() method returns what class will be used, either directly as a bean or as a factory. The shouldGenerateIdAsFallback() method is used to tell Spring that when no id is supplied in the XML, it should generate one. That makes it possible to create pseudo-anonymous beans (no bean is really anonymous in the Spring factory).

The real magic happen in the doParse() method: it just adds every simple property it finds in the builder. There are two interesting properties though: cacheManager and memoryStoreEvictionPolicy.

The former, should it exist, is a reference on another bean. Therefore, it should be added to the builder not as a value but as a reference. Of course, the code doesn’t check if the developer declared the cache manager as an anonymous bean inside the ehcache but the schema validation took already care of that.

The latter just uses the string value to get the real object behind and add it as a property to the builder. Likewise, since the value was enumerated on the schema, exceptions caused by a bad syntax cannot happen.

Registering the parser

The last step is to register the parser in Spring. First, you just have to create a class that extends org.springframework.beans.factory.xml.NamespaceHandlerSupport and register the handler under the XML tag name in its init() method:

public class EhCacheNamespaceHandler extends NamespaceHandlerSupport {

  public void init() {

    registerBeanDefinitionParser("cache", new EhCacheBeanDefinitionParser());
  }
}

Should you have more parsers, just register them in the same method under each tag name.

Second, just map the formerly created namespace to the newly created handler in a file META-INF/spring.handlers:

http\://blog.frankel.ch/spring/ehcache=ch.frankel.blog.spring.authoring.ehcache.EhCacheNamespaceHandler

Notice that you map the declared schema file to the real schema but the namespace to the handler.

Conclusion

Now, when faced by overly verbose bean configuration, you have the option to use this nifty 4-steps techniques to simplify it. This technique is of course more oriented toward product providers but can be used by projects, provided the time taken to author a namespace is a real time gain over normal bean definitions.

You will find the sources for this article here in Maven/Eclipse format.

To go further

  • Spring authoring: version 2.0 is enough since nothing changed much (at all?) with following versions
  • Spring’s Javadoc relative to authoring

Spring can inject Servlets too!

September 28th, 2009 1 comment

In this article, I will show you that Spring dependency injection mechanism is not restricted solely to Spring-managed beans, that is Spring can inject its beans in objects created by the new keywords, servlets instantiated in the servlet container, and pretty anything you like. Spring classical mode is to be an object factory. That is, Spring creates anything in your application, using the provided constructor. Yet, some of the objects you use are outer Spring’s perimeter. Two simple examples:

  • servlets are instantiated by the servlet container. As such, they cannot be injected out-of-the-box
  • some business objects are not parameterized in Spring but rather created by your own code with the new keyword

Both these examples show you can’t delegate to Spring every object instantiation.

There was a time when I foolishly thought Spring was a closed container. Either your beans were managed by Spring, or they didn’t: if they were, you could inject them with other Spring-managed beans. If they weren’t, tough luck! Well, this is dead wrong. Spring can inject its beans into pretty much anything provided you’re okay to use AOP.

In order to do this, there are only 2 steps to take:

Use AOP

It is done in your Spring configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://www.springframework.org/schema/context

	http://www.springframework.org/schema/context/spring-context-2.5.xsd">

  <This does the magic />
  <context:spring-configured />

  <-- These are for classical annotation configuration -->
  <context:annotation-config />
  <context:component-scan base-package="ch.frankel.blog.spring.outcontainer" />

</beans>

You need also configure which aspect engine to use to weave the compiled bytecode. In this cas, it is AspectJ, which is the AOP component used by Spring. Since i’m using Maven as my build tool of choice, this is easily done in my POM. Ant users will have to do it in their build.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/maven-v4_0_0.xsd">
...
  <properties>
    <spring-version>2.5.6.SEC01</spring-version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${spring-version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>${spring-version}</version>
    </dependency>
    <dependency>
      <groupId>aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.5.4</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <configuration>
          <complianceLevel>1.5</complianceLevel>
          <aspectLibraries>
            <aspectLibrary>
              <groupId>org.springframework</groupId>
              <artifactId>spring-aspects</artifactId>
            </aspectLibrary>
          </aspectLibraries>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Configure which object creation to intercept

This is done with the @org.springframework.beans.factory.annotation.Configurable annotation on your injectable object.

@Configurable
public class DomainObject {

  /** The object to be injected by Spring. */
  private Injectable injectable;

  public Injectable getInjectable() {

    return injectable;
  }

  @Autowired
  public void setInjectable(Injectable injectable) {

    this.injectable = injectable;
  }
}

Now with only these few lines of configuration (no code!), I’m able to inject Spring-managed beans into my domain object. I leave to you to implement the same with regular servlets (which are much harder to display as unit test).

You can find the Maven project used for this article here. The unit test packaged shows the process described above.

To go further:

Top Eclipse plugins I wouldn’t go without

August 8th, 2009 4 comments

Using an IDE to develop today is necessary but any IDE worth his salt can be enhanced with additional features. NetBeans, IntelliJ IDEA and Eclipse have this kind of mechanism. In this article, I will mention the plugins I couldn’t develop without in Eclipse and for each one advocate for it.

m2eclipse

Maven is my build tool of choice since about 2 years. It adds some very nice features comparing to Ant, mainly the dependencies management, inheritance and variable filtering. Configuring the POM is kind of hard once you’ve reached a fairly high number of lines. The Sonatype m2eclipse plugin (formerly hosted by Codehaus) gives you a tabs-oriented view of every aspect of the POM:

  • An Overview tab neatly grouped into : Artifact, Parent, Properties, Modules, Project, Organization, SCM, Issue Management and Continuous Integration,
  • m2eclipse Overview tab Read more…

JMX use cases

June 7th, 2009 1 comment

JMX is a Java standard shipped with the JDK since Java 5. Though it enables you to efficiently and dynamically manage your applications, JMX has seen very few productions uses. In this article, I will show you the benefits of using such a technology in a couple of use cases.

Manage your application’s configuration

Even though each application has different needs regarding configuration (one needing a initial thread number attribute, the other an URL), every application needs to be more or less parameterized. In order to do this, countless generations of Java developers (am I overdoing here?) have created two components:

  • the first one is a property file where one puts the name value pairs,
  • the other one is a Java class whose responsibilities are to load the properties in itself and to provide access to the values. This class should be a singleton.

This is good and fine for initialization, but what about runtime changes of those parameters? This is where JMX comes in. With JMX, you can now expose those parameters with read/write authorizations. JDK 6 provides you with the JConsole application, which can connect on JMX-enabled applications. Lets’s take a very simple example, with a configuration having only two properties: there will be one Configuration class and one interface named ConfigurationMBean in order to follow the JMX standard for Standard MBean. This interface will describe all methods available on the MBean instance:

public interface ConfigurationMBean {

    public String getUrl();

    public int getNumberOfThread();

    public void setUrl(String url);

    public void setNumberOfThread(int numberOfThread);
}

Now, you’ll only have to register the singleton instance of this class in you MBean server, and you have exposed your application’s configuration to the outside with JMX!

Manage your application’s Springified configuration

In Spring, every bean that is configured in the Spring configuration file can be registered to the JMX server. That’s it: no need to create an MBean suffixed interface for each class you want to expose. Spring does it for you, using the more powerful DynamicMBean and ModelMBean classes under the hood.

By default, Spring will expose all your public properties and methods. You can still control more precisely what will be exposed through the use of:

  • meta-datas (@@-like comments in the javadocs, thus decoupling your code from Spring API),
  • Spring Java 5 annotations,
  • classical MBean interfaces referenced in the Spring’s definition file,
  • or even using MethodNameBasedMBeanInfoAssembler which describes the interface in the Spring’s definition file.

More importantly, Spring provides your MBeans with notification provider support. This means every MBean will implement NotificationBroadcaster and thus be able to send notifications to subscribers, for example when you change a value to a property or when you call a method.

Following is a snippet for the previous Configuration, using Spring:

<bean id="genericCfg" class="ch.frankel.blog.jmx.GenericConfiguration" />
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
        <map>
            <entry key="bean:type=configuration,name=generic" value-ref="genericCfg" />
        </map>
    </property>
</bean>

Spring uses the MBean’s id to register it under the MBean server.

Change a logger’s level

Logging is a critical functionality since the dawn of software. Now, let’s say you are faced with the following problem: your application keeps throwing exceptions but what is traced is not enough for the developers to diagnose. Luckily, one of the developer did put some trace, but on a very primitive level. Unluckily, in production mode, it’s pretty sure you log only important events, mainly exceptions, not the debug informations that could be so useful here.

The first solution is to change the log level in the configuration file and the restart the application. Ouch, that’s a very crude way, one that won’t make many people happy (depending on the criticity and availability of the application).

Another answer is to use the abilities of the logging framework. For example, Log4J is the legacy logging framework. It provides a way to configure the framework with a configuration file and to listens to changes made to this file in order to reflect it in the in-memory configuration (the static configureAndWatch() method found in both DOMConfigurator and PropertyConfigurator).This runs fine if you have an external file but what about configuration files shipped with the archive? You can argue that Web archives are often deployed in exploded mode but you cannot rely on it.

JMX will prove to be handy for such a case: if you could have exposed your loggers logging level, you could change them at runtime. Since JDK 1.4, Java has an API to log messages. It offers JMX registration for free, so let’s use it. The only thing to do is create a logger for your class. In a business method, use the logger to trace at FINE level. Now using your JMX console, locate the MBean named java.util.logging:type=Logging.

Type Name Description
Attribute LoggerNames Array of all loggers configured
Operation getLoggerLevel Get the level of a logger The root logger is referenced by an empty string
Operation setLoggerLevel Set the level of a logger to a specified value

In order to activate the log, just set the level of the logger used by your class to the value you used in the code. In order to test this, I recomend to create a Spring bean from a Java class using the logger and exporting it to JMX with Spring (see above).

Flush your cache

For the data access layer, Hibernate is the most used framework at the time of this writing. Hibernate enables you to use caching. Hibernate’s first level caching (session cache) is done within Hibernate itself; Hibernate’s second level caching (transsession cache) is delegated to a 3rd party framework. Default framework is Ehcache: it is a very simple, yet efficient solution.

Let’s say some of your application’s table contain repository datas, that is data that won’t be changed by the application. These datas are by definition eligible for second-level caching. Now picture this: your application should be highly available (365/24/7) and the repositories just changed. How can you tell Ehcache to reload the tables in memory without restarting the application?

Luckily, Ehcache provides you with the way to do it. In fact, the net.sf.ehcache.management.Cache class implements the net.sf.ehcache.management.CacheMBean so you can call all of the interface methods: one of such method, aptly named removeAll() empties your cache. Just call it and Hibernate, not finding any data in the cache, will reload them from the database.

You will perhaps object you do not want all of your cache to be reinitialized: now you understand why you should separate your cache instances in the configuration (e.g. one for each table or one for repository datas and one for updatable datas).

Testing JMX

It is legitimate to want to test JMX while developing before bringing in the whole server infrastructure. JDK 6 provides you with the JConsole utility which displays the following informations on any application you can connect to (local and remote):

  • memory usage through time,
  • threads instances through time,
  • number of loaded classes through time,
  • summary of VM (including classpath and properties),
  • all your exposed MBeans.

JConsole MBean view

This view lets you view your MBeans attributes and call your MBeans operations, so this is a very valuable tool (for free). Now try it with a legacy application of yours: notice how many MBeans are registered. Guess you didn’t expect that!

In order to use this tool in development mode, do not forget to launch it with the following arguments (notice the -J):

  • -J-Dcom.sun.management.jmxremote.ssl=false
  • -J-Dcom.sun.management.jmxremote.authenticate=false
  • -J-Djava.class.path="${JDK_HOME}/jdk1.6.0_10/lib/jconsole.jar;${JDK_HOME}/lib/tools.jar;${ADDITIONNAL_CLASSPATH}

The last argument can be omitted in most cases (though this is not the case for managing EhCache).

You can find the sources for all the examples here.

To go further

Mockito’ spy() method and Spring

May 21st, 2009 1 comment

Mockito is a mocking framework (see Two different mocking approaches) that is an offshoot of EasyMock. Whatever the mocking framework one uses, a common feature is the ability to mock interfaces, through the JDK Proxy class. This is well and nice, but one has to explicitly mock every method that one wants to use in the course of the test.

What if I want to mock an already existing implementation, with some methods providing behaviours that suit me ? Today, I ran across this case: Read more…

Age of Spring

January 14th, 2009 No comments

Since it first version, Spring has known success. How is it possible that such an unknown framework (at the time) has become so widespread that companies demand to attendants to have Spring knowledge?

I think they are two main reasons for this. First, the use of Inversion of Control really helps unit testing your classes and since unit tests have become a hot topic, it is natural that a framework that promote independency between classes should win. But they are other IoC frameworks available. Did you hear about Guice? Yes, with a G like Google. Not really a small potatoes player, is it? Yet, it is a previously unkwown company like Interface21 (now renamed SpringSource) that made the reference product.

The second reason, and according to me, the most important, is that Java & JEE development is complex and thus costly. So, when a framework like Spring provides ways to speed up such development by giving integration components, it is natural it becomes the leader in its field.

For example, the following snippet shows how to execute a simple query on a database:

Context ctx = new InitialContext();

DataSource ds = (DataSource) ctx.lookup("jdbc/javadb");

Connection con = ds.getConnection();

PreparedStatement pstmt = con.prepareStatement("SELECT * FROM CUSTOMERS WHERE NAME = ?");

pstmt.setString(1, "KERRY");

ResultSet rs = pstmt.executeQuery();

while (rs.next()) {

    Customer customer = new Customer();

    customer.setName(rs.getString("NAME"));

    customer.setFirstName(rs.getString("FIRST_NAME"));
}

The same thing can be done in Spring like this:

RowMapper mapper = new RowMapper() {

    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {

        Customer customer = new Customer();

        customer.setName(rs.getString("NAME"));

        customer.setFirstName(rs.getString("FIRST_NAME"));

        return customer ;
    }
};

jdbcTemplate.queryForObject("SELECT * FROM CUSTOMERS WHERE NAME = ?", mapper, new Object[] {"KERRY"});

Take a look at lines 13-20 of first snippet compared to lines 1-13 of second snippet: the mapping lines look the same (yet they are not since the Spring version is more object-oriented). On the other hand, the lines 1-11 of classic snippet are sumed up in only one line in the Spring snippet! Boilerplate code is provided by Spring and executed behind the scene.

In conclusion, I think that this integration state of mind is the biggest asset of Spring. It would be nice to see such approach in other API too.

Categories: Java Tags: ,