This chapter is to help Java developers get their sea legs using Spring.NET. It is not intended to be a comprehensive comparison between .NET and Java. Rather, it highlights the day-to-day differences you will experience when you start to use Spring.NET.
There are some simple name changes, basically everywhere you saw the word 'bean' you will now see the word 'object'. A comparison of a simple Spring configuration file highlights these small name changes. Here is the application.xml file for the sample MovieFinder application in Spring.Java
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="MyMovieLister" class="MovieFinder.MovieLister"> <property name="finder" ref="MyMovieFinder"/> </bean> <bean id="MyMovieFinder" class="MovieFinder.SimpleMovieFinder"/> </beans>
Here is the corresponding file in Spring.NET
<objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects-1.1.xsd"> <object name="MyMovieLister" type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder"> <property name="movieFinder" ref="MyMovieFinder"/> </object> <object name="MyMovieFinder" type="Spring.Examples.MovieFinder.SimpleMovieFinder, Spring.Examples.MovieFinder"/> </objects>
As you can easily see the <beans> and <bean> elements are replaced by <objects> and <object> elements. The class definition in Spring.Java contains the fully qualified class name. The Spring.NET version also contains the fully qualified classname but in addition specifies the name of the assembly where that type is located. This is necessary since .NET does not have a 'classpath' concept. Assembly names in .NET can have up to four parts to describe the exact version.
The other XML Schema elements in Spring.NET are the same as in Spring.Java's DTD except for specifying string based key value pairs. In Java this is represented by the java.util.Properties class and the xml element is name <props> as shown below
<property name="people"> <props> <prop key="PennAndTeller">The magic property</prop> <prop key="GeorgeCarlin">The funny property</prop> </props> </property>
In .NET the analogous class is System.Collections.Specialized.NameValueCollection and is represented by the xml element <name-values>. The listing of the elements also follows the .NET convention of application configuration files using the <add> element with 'key' and 'value' attributes. This is show below
<property name="people"> <name-values> <add key="PennAndTeller" value="The magic property"/> <add key="GeorgeCarlin" value="The funny property"/> </name-values> </property>
PropertyEditors from the java.beans package provide the ability to convert from a string to an instance of a Java class and vice-versa. For example, to set a string array property, a comma delimited string can be used. The Java class that provides this functionality is the appropriately named StringArrayPropertyEditor. In .NET, TypeConverters from the System.ComponentModel namespace provide the same functionality. The type conversion functionality in .NET also allows for TypeConverters to be explicitly registered with a data type. This allows for transparent setting of complex object properties. However, some classes in the .NET framework do not support the style of conversion we are used to from Spring.Java, such as setting of a string[] with a comma delimited string. The type converter, StringArrayConverter in the Spring.Objects.TypeConverters namespace is therefore explicitly registered with Spring.NET in order to provide this functionality. As in the case of Spring.Java, Spring.NET allows user defined type converters to be registered. However, if you are creating a custom type in .NET, using the standard .NET mechanisms for type conversion is the preferred approach.
Exceptions in Java can either be checked or unchecked. .NET supports only unchecked exceptions. Spring.Java prefers the use of unchecked exceptions, frequently making conversions from checked to unchecked exceptions. In this respect Spring.Java is similar to the default behavior of .NET
In Spring.Java it is very common to create an ObjectFactory or ApplicationContext from an external XML configuration file This functionality is also provided in Spring.NET. However, in .NET the System.Configuration namespace provides support for managing application configuration information. The functionality in this namespace depends on the availability of specially named files: Web.config for ASP.NET applications and <MyExe>.exe.config for WinForms and console applications. <MyExe> is the name of your executable. As part of the compilation process, if you have a file name App.config in the root of your project, the compiler will rename the file to <MyExe>.exe.config and place it into the runtime executable folder.
These application configuration files are XML based and contain
configuration sections that can be referenced by name to retrieve custom
configuration objects. In order to inform the .NET configuration system
how to create a custom configuration object from one of these sections, an
implementation of the interface, IConfigurationSectionHandler, needs to be
registered. Spring.NET provides two implementations, one to create an
IApplicationContext from a <context>
section and
another to configure the context with object definitions contained in an
<objects>
section. The
<context>
section is very powerful and
expressive. It provides full support for locating all
IResource
via Uri syntax and hierarchical contexts
without coding or using more verbose XML as would be required in the
current version of Spring.Java
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="spring"> <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/> <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" /> </sectionGroup> </configSections> <spring> <context> <resource uri="config://spring/objects"/> </context> <objects> <description>An example that demonstrates simple IoC features.</description> <object name="MyMovieLister" type="Spring.Examples.MovieFinder.MovieLister, MovieFinder"> <property name="movieFinder" ref="AnotherMovieFinder"/> </object> <object name="MyMovieFinder" type="Spring.Examples.MovieFinder.SimpleMovieFinder, MovieFinder"/> <!-- An IMovieFinder implementation that uses a text file as it's movie source... --> <object name="AnotherMovieFinder" type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, MovieFinder"> <constructor-arg index="0" value="movies.txt"/> </object> </objects> </spring> </configuration>
The <configSections> and <section> elements are a standard part of the .NET application configuration file. These elements are used to register an instance of IConfigurationSectionHandler and associate it with another xml element in the file, in this case the <context> and <objects> elements.
The following code segment is used to retrieve the IApplicationContext from the .NET application configuration file.
IApplicationContext ctx = ConfigurationUtils.GetSection("spring/context") as IApplicationContext;
In order to enforce the usage of the named configuration section
spring/context
the preferred instantiation mechanism is
via the use of the registry class ContextRegistry as shown below
IApplicationContext ctx = ContextRegistry.GetContext();
When configuring the list of interceptor names on a
ProxyFactoryObject
instance (or object
definition), one cannot specify the name of the
target (i.e. the object being proxied) at the end of the list of
interceptor names. This shortcut is valid in Spring
Java, where the ProxyFactoryBean
will
automatically detect this, and use the last name in the interceptor
names list as the target of the ProxyFactoryBean
.
The following configuration, which would be valid in Spring Java
(barring the obvious element name changes), is not valid in Spring.NET (so don't do it).
<?xml version="1.0" encoding="utf-8" ?> <objects xmlns="http://www.springframework.net"> <object id="target" type="Spring.Objects.TestObject"> <property name="name" value="Bingo"/> </object> <object id="nopInterceptor" type="Spring.Aop.Interceptor.NopInterceptor"/> <object id="prototypeTarget" type="Spring.Aop.Framework.ProxyFactoryObject"> <property name="interceptorNames" value="nopInterceptor,target"/> <!-- not valid! --> </object> </objects>
In Spring.NET, the InterceptorNames
property of
the ProxyFactoryObject
can
only be used to specify the names of interceptors.
Use the TargetName
property to specify the name of
the target object that is to be proxied.
The main reason for not supporting exactly the same style of configuration as Spring Java is because this 'feature' is regarded as a legacy holdover from Rod Johnson's initial Spring AOP implementation, and is currently only kept as-is (in Spring Java) for reasons of backward compatibility.