Spring

Multiple select with Spring MVC

During our coding night (there’s be a separate blog for it), we committed ourselves to use only Spring technologies. But a simple requirement had a rather dramatic effect.

How do you create a multiple select box with Spring MVC? You should be able to select multiple elements, which then get added to a collection of the backing bean.

We are implementing a simple time tracking application. The domain model contains projects, which can have staff members assigned. Projects have tasks, which also have staff members assigned to. So in the task creation view we need a select box that contains all available employees.

Model

Here are the most important extracts from Tasks and Staff members:

Task

@Entity
public class Task implements Serializable {
	@Id
	@GeneratedValue
	private long id;
 
	@ManyToMany
	private Set<Staff> staffs = new HashSet<Staff>(0);
 
	//...
}

Staff

@NamedQuery(name = "staff.activeStaff", query = "select s from Staff s where s.disabled = false")
@Entity
@DiscriminatorValue("STAFF")
public class Staff extends Person {
 
	//...
}

Person

@NamedQuery(name = "person.findByUsername", query = "from Person p where p.login.username = :username")
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public abstract class Person implements Serializable {
 
	@Id
	@GeneratedValue
	private long id;
 
	//...
}

View

In the task creation view, we need a select box that shows all available employees. The selected employees shall then be assigned to the task when the form is submitted.

@Controller
@SessionAttributes("project")
public class ProjectController {
	@RequestMapping(method = RequestMethod.GET, value = "/project/createTask.action")
	public void createTaskView(@ModelAttribute Task task, Model model) {
		List<Staff> activeStaff = timetrackingService.getActiveStaff();
		model.addAttribute("activeStaff", activeStaff);
	}
 
	//...

The JSP that belongs to the controller contains this snippet for the select box:

<td><label for="staffs">Chose Staff: </label></td>
<td><form:select path="staffs" multiple="true" items="${activeStaff}" itemLabel="fullName" itemValue="id"/></td>
<td><form:errors path="staffs" /></td>

The problem is, as soon as you submit the form, you will get a ServletRequestBindingException, because Spring has no idea how to map a String (or String[] when multiple staff members have been selected) to a Set.

org.springframework.web.bind.ServletRequestBindingException: Errors binding onto object 'task'; nested exception is org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'task' on field 'staffs': rejected value [3]; codes [typeMismatch.task.staffs,typeMismatch.staffs,typeMismatch.java.util.Set,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [task.staffs,staffs]; arguments []; default message [staffs]]; default message [Failed to convert property value of type [java.lang.String] to required type [java.util.Set] for property 'staffs'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [de.codecentric.timetracking.model.Staff] for property 'staffs[0]': no matching editors or conversion strategy found]

Additionally, the generated HTML is missing the ID for staff members!

<select id="staffs" multiple="multiple" name="staffs">
<option value="">firstname lastname</option>
<option value="">aaaa aaaa</option>
<option value="">firstname lastName</option>
<option value="">firstname aaaa</option>
<option value="">firstname lastname</option>
</select>
<input type="hidden" value="1" name="_staffs"/>

Id as String

In order to have the staff member ID in the value attribute of the option element, we can create a new getter in the Person class that returns the id as String, and then use that in the JSP:

public abstract class Person implements Serializable {
	//...
	public String getIdAsString() {
		return new Long(id).toString();
	}
}
<form:select path="staffs" itemValue="idAsString" multiple="true" items="${activeStaff}" itemLabel="fullName"/>

InitBinder

The solution to the binding problem is more difficult. We need a PropertyEditor for the attribute ’staffs’. Spring contains a number of PropertyEditors, so we can use the CustomCollectionEditor. It is expected that the property editor can map the string from options value back to the element, so we need to store that mapping somewhere, in a map for example.

public class ProjectController {
 
private Map<String, Staff> staffCache;
 
@RequestMapping(method = RequestMethod.GET, value = "/project/createTask.action")
public void createTaskView(@ModelAttribute Task task, Model model) {
	List<Staff> activeStaff = timetrackingService.getActiveStaff();
	staffCache = new HashMap<String, Staff>();
	for (Staff staff : activeStaff) {
		staffCache.put(staff.getIdAsString(), staff);
	}
	model.addAttribute("activeStaff", activeStaff);
}
 
@InitBinder
protected void initBinder(WebDataBinder binder) throws Exception {
	binder.registerCustomEditor(Set.class, "staffs", new CustomCollectionEditor(Set.class) {
		protected Object convertElement(Object element) {
			if (element instanceof Staff) {
				System.out.println("Converting from Staff to Staff: " + element);
				return element;
			}
			if (element instanceof String) {
				Staff staff = staffCache.get(element);
				System.out.println("Looking up staff for id " + element + ": " + staff);
				return staff;
			}
			System.out.println("Don't know what to do with: " + element);
			return null;
		}
	});
}

The code still contains some debug output to System.out, which has to be removed. But it shows that the method is called very frequently. Only for showing the select box with 5 employees, the method is caller 15 times. 10 times the id is passed in as a String, and 5 times the object is passed in. I have found no good documentation what exact behaviour is expected from that PropertyEditor, this is the best working solution I could come up with.

Looking up staff for id 1: Staff(firstname lastname)
Looking up staff for id 1: Staff(firstname lastname)
Converting from Staff to Staff: Staff(firstname lastname)
Looking up staff for id 2: Staff(aaaa aaaa)
Looking up staff for id 2: Staff(aaaa aaaa)
Converting from Staff to Staff: Staff(aaaa aaaa)
Looking up staff for id 3: Staff(firstname lastName)
Looking up staff for id 3: Staff(firstname lastName)
Converting from Staff to Staff: Staff(firstname lastName)
Looking up staff for id 4: Staff(firstname aaaa)
Looking up staff for id 4: Staff(firstname aaaa)
Converting from Staff to Staff: Staff(firstname aaaa)
Looking up staff for id 5: Staff(firstname lastname)
Looking up staff for id 5: Staff(firstname lastname)
Converting from Staff to Staff: Staff(firstname lastname)

After selecting an employee and submitting the form, expectedly there’s only one line in the log, converting the id back to the staff member.:

Looking up staff for id 3: Staff(firstname lastName)

Conclusion

With the massive amount of web frameworks around, I find it surprisingly complicated to achieve something as simple as a multiple select box in Spring MVC. But, I just leard Spring MVC yesterday, so I might not know all details yet. So if there’s a more elegant and simpler solution to achieve the same as described above, I very much welcome your feedback.

Andreas Ebbert-Karroum

 

About a very special experience: JDK6, JDK5 and Spring 2.0.0

In one of our current projects, we are migrating from JDK5 Update 7 to JDK6 Update 12. One of our applications uses JCaptcha to secure input forms. We gain the biggest possible ease by configuring the captcha through Spring.

After switching one of our development machines to JDK6, we suddenly faced an IllegalArgumentException during initialization of the captcha servlet. Switching JBoss back to JDK5 solved the problem. This was leading nowhere though, because the target systems are all going to be switched to Java 6.

This is an excerpt from the stack trace:

java.lang.IllegalArgumentException: Color parameter outside of expected range: Red Green Blue
	at java.awt.Color.testColorValueRange(Color.java:298)
	at java.awt.Color.(Color.java:382)
	at java.awt.Color.(Color.java:357)
	at java.awt.Color.(Color.java:448)

A more in-depth investigation into the problem using the Eclipse Debugger yielded the following result:

Obviously, the Color constructor for three float arguments was being used. An excerpt from the spring beans configuration:

<bean id="captchaBackgroundColor" class="java.awt.Color">
	<constructor-arg index="0"><value>255</value></constructor-arg>
	<constructor-arg index="1"><value>255</value></constructor-arg>
	<constructor-arg index="2"><value>255</value></constructor-arg>
</bean>

The float constructor of java.awt.Color has this as its first line of code:

this( (int) (r*255+0.5), (int) (g*255+0.5), (int) (b*255+0.5));

This passes the arguments to the int constructor, which in our case is called as Color(65025, 65025, 65025). The immediate result of this is the aforementioned IllegalArgumentException.

The exact reason for our problem arises from a combination of multiple facts. If you aren’t much interested in technical details, skip the following list:

  • In the project, Spring 2.0.0 is used. The constructor to be called is resolved via ConstructorResolver.autowireConstructor(…). On line 100 in that method, an array of potential constructors is created via reflection. Next, this array is sorted. The underlying Arrays.sort(…) gives a different result with JDK6 than with JDK5 (this seems to happen only on Windows machines)
  • In the sorted array, the constructor Color(float, float, float) resides at a lower index than Color(int, int, int). With JDK5, the opposite is true.
  • What follows is a loop that picks one constructor that is to be used for instantiation from the array. This loop determines the constructor to be used based on a comparison of “number of arguments” (trivial) and a so called “Type Difference Weight” (not so trivial).
  • Type Diffence Weight means that a difference in class hierarchy is computed for parameter types and the related arguments. We want to use int arguments in order to instantiate our Color object. The type weight difference calculation method “climbs” the class hierarchy of each parameter type as long as no higher superclass can be found. As long as the superclass found is a type to which the related argument can be assigned, the type difference weight value is increased and the search continues. (AutowireUtils.getTypeDifferenceWeight(…))
  • This obviously means that the type difference weight of float and int is 0, as both are primitives.
  • If the found tdw is smaller than the smallest tdw found so far, the constructor being examined in the current loop run is set as the constructor to be used.
  • Because the float constructor (using JDK6) is closer to the start of the array and because the tdw calculated in further loop runs cannot become smaller than the lowest tdw found so far (0 cannot be smaller than 0), the float constructor will be used in the end.
  • The float constructor passes its arguments to the int constructor, and it does so by multiplying them by 255 and increasing them by 0.5
  • The int constructor is called as Color(65025, 65025, 65025). This results in the IllegalArgumentException, because RGB values can only be between 0 and 255.

Back to the phenomenon: on the test system that has already been switched to Java 6, the captcha still runs without errors. Hence, the root of the problem is obviously that the constructor array has a different order after sorting on a Windows system than it has on a Linux system. The type difference weight mechanism should hopefully have become a little smarter too with newer Spring versions, given that autowiring still relies on that after all.

Nevertheless, we can solve the problem by adding explicit type settings to our Spring beans:

<bean id="captchaBackgroundColor" class="java.awt.Color">
	<constructor-arg index="0" type="int"><value>255</value></constructor-arg>
	<constructor-arg index="1" type="int"><value>255</value></constructor-arg>
	<constructor-arg index="2" type="int"><value>255</value></constructor-arg>
</bean>

This ensures that the desired constructor, which is java.awt.Color#Color(int r, int g, int b), is used.

The source code analysis I ran in as much depth as possible on Spring 2.0.0 and JDK6 Update 12 did not yield a precise finding as to why Arrays.sort(…) and the provided comparator from the Spring framework gives a different result on Windows systems than it does on Linux systems. Anyone able to shed light on this issue is invited to do so. :-)

Conclusion: the devil is in the details. Even an assumed “trivial” change like an update of the Java version can lead to errors which are hard to find. Intensive and precise testing is vital in such cases!

Thanks a lot to Mike Wiesner, Senior Consultant at SpringSource, who helped me “in realtime” with a question regarding Spring 2.0.0!

Robert Spielmann

 

OSGi applications vs. bunch of bundles

When I speak of a OSGi application, then i mean a group of bundles, which result in a application. Such a breakdown seems obvious when using OSGi. The single parts of the application communicate through the OSGi registry. One of the benefits is that you can replace a part of the application at the runtime and it want affect the other parts.

Unfortunately there is no way in OSGi to differ between bundles, which belong to different applications. This nuisance probably has a historical reason. OSGi originally was meant to run on small devices with decent amount of bundles. Today OSGi is used in projects like Eclipse IDE which hundreds of bundles inside the OSGi container. When I start my current installed Eclipse IDE (./eclipse -console) and type “ss” in the console it shows over 600 installed bundles. I have only few extra plug-ins installed. Other installations of Eclipse IDE surely get more the 1000 bundles. If I want to uninstall a plug-in over the console I would have my hands full by searching the bundles, which belongs to that plug-in. Instead I would use the update-manager of eclipse. In a different project, where I use OSGi (Equinox in my case) I do not have a update-manger, only the console.

Together with my application (composed of 6 bundles) there are a servlet container, the spring framework and few libraries installed in the OSGi container. When I develop on my application I am actually not interested in the other bundles. Some of them remain untouched since installed once. Nevertheless I have to go trough the list with all bundles, when I look for my application. It would be handy to list the bundles, which belongs to my application with a single command. Furthermore it would be handy to change the status of those bundles with a single command. As you can read in those blogs[1][2], I am not the only one missing such a feature. So I looked around whether there are already existent solutions.  I discovered the Platform Archive (PAR), which was introduced by SpringSource with the release of the SpringSource dm Server (former SpringSource Application Platform). A PAR is a regular JAR-file carrying multiple OSGi bundles. When you deploy the PAR all the packaged bundles will be installed automatically. Actually the PAR concepts fixes all my problems and offers equal management functionalities as known from normal WAR and EAR archives. As PARs are currently only supported by the SpringSource dm Server this is not a solution for all OSGi runtimes. In addition to that one of the issues with the PAR archive is, that it has to bew rebuild if one bundle is updated.

To gain some more flexibility I wanted to add the desired functionality to the Equinox myself. What I want is a way to compose groups of bundles without to violate the OSGi specification, so I still can install the bundles in a different OSGi container. Furthermore I want the bundles to remain separated. After a look in the source code of equinox I realized that I don’t even have to extend the OSGi framework itself. I only have to implement the CommandProvider interface in the org.eclipse.osgi.framework.console package and build a bundle which registers a instance of the resulting class in the OSGi registry. That’s what you do in order to add your own commands to the Equinox console.

The resulting class looks like this:

public class GroupCommandProvider implements CommandProvider {
   private BundleContext bctx;
 
   public GroupCommandProvider(BundleContext bctx) {
      this.bctx = bctx;
   }
 
   public String getHelp() {
      return "\tstopgroup &lt;group&gt; - stops all bundles in the specified group.";
   }
 
   public void _stopgroup(CommandInterpreter ci) throws BundleException {
      String groupToStop = ci.nextArgument();
      if (groupToStop == null)
         return;
 
      Bundle[] bundles = bctx.getBundles();
      for (Bundle bundle : bundles) {
         String currentGroup = (String) bundle.getHeaders().get("Bundle-Group");
         if (currentGroup == null || !currentGroup.equals(groupToStop))
            continue;
 
         if (bundle.getState() == Bundle.ACTIVE) {
            bundle.stop();
         }
      }
   }
}

The interesting method is _stopgroup(). By calling it you can stop all bundles with a specified value in the “Bundle-Group” field in the manifest file.

A manifest file could look like this:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: de.codecentric.mybundle
Bundle-Group: myGroup
Bundle-Version: 0.1.0
Import-Package: org.osgi.framework

All bundles with the same “Bundle-Group” value can be sopped by typing “stopgroup myGroup” in the equinox console.

In order to get the GroupCommandProvider working, you need a activator which registers a instance in the OSGi registry. It could look like this:

public class Activator implements BundleActivator {
   private CommandProvider commandProvider;
 
   public void start(BundleContext bctx) throws Exception {
      commandProvider = new GroupCommandProvider(bctx);
      bctx.registerService(CommandProvider.class.getName(), commandProvider, null);
   }
 
   public void stop(BundleContext arg0) throws Exception {
      commandProvider = null;
   }
}

In order to benefit from the GroupCommandProvider you probably will have to write methods to start, uninstall and update a group of bundles. In the method for starting a group of bundles you will have to differ between bundles which need to be started and those which don’t. I decided to extend the “Bundle-Group” field in the manifest file by a additional attribute. So it looks like this “Bundle-Group: myGroup;startable=true”. I think the _stopgroup() method clarifies the idea.

This solution doesn’t provide as much features as the PAR does, but it suites my needs. We will have to wait and see whether the OSGi will get some grouping capabilities in the future.

Eugen Melnichuk

 

SpringSource Partnership

In almost all of our projects we rely on a lightweight architecture in the Java Enterprise environment and are using in many projects the Springframework and its subprojects like Spring Batch or Spring Webflow. Already this spring we did talk on the JAX with SpringSource about a possible partnership and announced this now officially.

The combination of our Java EE expertise in the areas of performance, architecture and open source and the product portfolio of SpringSource was considered as the optimal solution for our customers. It is the support for production and development, the excellent Core Spring Training and Enterprise version of Spring, with monitoring functions (on the basis of  Hyperic), Eclipse based IDE and Oracle extended support that bring Spring up to a new level for business enterprise applications.

The SpringSource Application Platform will be interesting for clients, as it brings the lightweight architecture of Spring and Tomcat with the advantages of OSGi for application development and combines them to new opportunities for the operation and development.

This new platform Eberhard Wolff presented to us during one of our Friday meetings. We do work ourselves with OSGi and the possibilities in application development and deployment solution for services within a SOA and Eugen also writes his diploma thesis on this issue. The lecture was therefore particularly well percieved by our team and various challenges and solutions with OSGi and Spring Application Platform have been discussed.

Mirko Novakovic