Use a Spring InitBinder to Resolve Type Mismatch and Bind Exceptions in POST from Spring Framework MVC Forms to Controller Actions

As a follow up to the previous article on binding entities and their children to form objects in Spring Framework it’s important to know how to submit the values of form objects in a standard form back to the controller. In the previous example we had a “Parent” entity, with a dropdown “select” on the form where you could choose one of the available “Children” objects. We also had a “Description” textbox that allowed the user to type in a suitable description.

The actual form, a very simple interface with both these elements and a submit button looks like:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

<c:url var="saveParentUrl" value="/parent/save" />
<form:form modelAttribute="parent" method="POST" action="${saveParentUrl}">
Description:  <form:input path="description"/>
Child:  <form:select path="child" id="child" items="${children}" itemValue="id" itemLabel="name"/>
<input type="submit" value="Save Parent" />
</form:form>

In this example, when the user clicks on the “Save Parent” button the form will be posted to the “parent” controller action “saveParent” at “/parent/save” where we can save the updated “Parent” object.

Now the problem is that the POST header only contains text strings, not a full description of the actual “Child” object we have chosen for “Parent”. When you try to save the “Parent” object in the controller action the result is an exception,  “org.springframework.validation.BeanPropertyBindingResult”. The error message itself tells you exactly what is happening:

default message [Failed to convert property value of type ‘java.lang.String[]’ to required type ‘models.Child’ for property ‘Child’; nested exception is java.lang.IllegalStateException: Cannot convert value of type ] to required type [models.Child] for property ‘Child’: no matching editors or conversion strategy found]

The message tells you that Spring can’t automatically convert from the POST string value of the “child” select option (actually “id” in our case) to an actual “Child” object. We need to convert this string to a “Child” object in order to save the updated “Parent” entity. This is easily achieved using an “InitBinder” method within the controller class and a “@Validated” annotation on the “save” action’s “Parent” “@ModelAttribute” argument.

The code for the controller action looks like the following. Note that in this example I am using a “parentService” to pull the protocol to be updated from a “Parent” stored in session. It is likely that you will have something different or even pass in the id as part of the POST:

// ParentController.java
@RequestMapping(value = "/save", method=RequestMethod.GET)
public ModelAndView saveParent (@Validated @ModelAttribute("parent") Parent formparent, HttpServletRequest request )
{
    ...
    // find parent to update in database using parent service
    Parent parent = parentService.findById(sessionparent.getId());

    // set parent description and Child based on user input and save
    parent.setDescription(formparent.getDescription());
    parent.setChild(formparent.getChild());
    parentService.saveParent(parent);
    ...
}

The “formparent” is the “Parent” object passed in POST and mapped by Spring using the “@ModelAttribute” annotation. The “InitBinder” required to map the “Child” id passed in as part of POST to an actual “Child” object is:

@InitBinder
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
    binder.registerCustomEditor(Child.class, "child", new PropertyEditorSupport() {
    @Override
    public void setAsText(String text) {
        Child ch = childService.findById(Long.parseLong(text));
        setValue(ch);
    }
    });
}

What this does is register a binder for the “child” object when it is passed from the form to Spring that converts the value to an actual object. By overriding the “SetAsText” function I use a “childService” service to retrieve the correct “Child” entity based on the text value passed in POST. Spring can now understand and convert the POST values to actual objects and the “Parent” entity can be safely modified by the “saveParent” controller action mapped to “/parent/save”. More information and some alternative methods are available at Develop and Conquer and Empire5.

Quickly add a Virtual Host to Apache Tomcat to Map URLs to Java Web Applications

Adding a virtual host to Apache Tomcat is really easy and just involves pointing the address at the right directory. This means you can map web addresses pointing at your server IP to Java web applications running on Apache Tomcat. This assumes you already have a hostname such as “websiteaddress.com” pointing to your server with an IP (for example) of 1.2.3.4.

Just modify you server.xml file (in our Ubuntu Server tomcat7 setup in “/usr/share/tomcat7/conf/server.xml”) to include the following at the end of the file in the “Engine” element after the “Host” element for localhost:


      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>

      <Host name="websiteaddress.com" appBase="/usr/share/tomcat7/webapps/myapplication">
        <Context path="" docBase="."/>
      </Host>

Note here that the web address is http://websiteaddress.com and is being resolved to the application at “/usr/share/tomcat7/webapps/myapplication”. More information about this “Host” element is available at the Apache Tomcat website.

Binding Entities and Their Children to Java JSP Form Elements in Spring Framework MVC

Binding objects to JSP form elements is actually quite easy in Spring Framework using the “modelAttribute” and “path” tags. Our scenario was the use of two Hibernate POJOs comprised of a parent entity “Parent” and a single “Child” entity which needed to be displayed on screen with appropriate form elements (“input” and “select”). The entities were annotated for use as part of a larger application but the basic structure was:

// Parent.java
public class Parent{
  private Int id
  private String description
  private Child child
  ...
}

// Child.java
public class Child{
  private Int id
  private String name
  ...
}

To display these objects on screen as part of a form in Spring Framework MVC we used the following “ParentController” controller with a “showparent” action. The action uses a “parentService.getParent(id)” method (not shown) to retrieve a single parent entity based on “id” and attach it to the form using a Map “model” and a returned “ModelAndView”. A “childService” is used to get the list of every possible child entity (also not shown) and this is also added to the “ModelAndView”:

// ParentController.java
@RequestMapping(value = "/showparent", method=RequestMethod.GET)
public ModelAndView protocolList(HttpServletRequest request)
{
	...
	Map<String, Object> model = new HashMap<String, Object>();
	model.put ( "children", childService.getAll());
	model.put ( "parent", parentService.getParent(id));
	return new ModelAndView ( "showparent", model );
}

The form itself is very simple and uses Spring binding to automatically create and populate input fields:

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<form:form modelAttribute="parent" >
Description:  <form:input path="description"/>
Child:  <form:select path="child" id="child" items="${children}" itemValue="id" itemLabel="name"/>
</form:form>

Spring Framework uses the “modelAttribute” and “path” tags to determine what is set on the form. In this case the forms “modelAttribute” is “parent” which means that the elements in the form are properties of the “parent” entity. The “description” is shown as the contents of a simple textbox input using “form:input”. The interesting part is the “form:select” which automatically populates the select with option objects based on the set of “child” objects in “children” and selects the correct “child” option for the “parent” based on the “itemValue”, “id” in this case.

Submitting changes to “parent” entities is covered in my more recent post.

Install the latest Java 7 JDK on Ubuntu Linux Server 10.04 without apt-get

I was trying to set up Apache Tomcat on an older server running Ubuntu 10.04 and noticed that Java wasn’t actually installed by default. Also, the licensing agreement with Oracle seems to have changed and it is no longer possible to just use apt-get to install it. You have to manually accept the licensing agreement so even “wget” wont work any more (you just get a “download-fail-XXXXXXX.html” file instead.

First up, you have to go to the Java JDK download page and manually accept the licensing agreement. This must be done from a PC with a UI and a browser so no “wget”. You need to get the correct version, which in my case was the x86 tar.gz version. When this is downloaded you should have a “jdk-7u9-linux-i586.tar.gz” file which then needs to be copied to your Ubuntu server (I copied to my user’s home directory).

Now you have the file on your Ubuntu server you can extract it using:

tar -xvf jdk-7u9-linux-i586.tar.gz

This should give you a directory “jdk1.7.0_09″ which we need to move to somewhere sensible such as “/usr/lib/jvm/jdk1.7.0_09″:

sudo mv jdk1.7.0_09 /usr/lib/jvm/jdk1.7.0_09

Now we need to set up a symbolic link so that we can run Java from everywhere:

 sudo ln -fs /usr/lib/jvm/jdk1.7.0_09/bin/java /usr/bin/java

Now check that Java is all installed correctly by checking the version using:

java -version

Which in this case should give:

java version “1.7.0_09″
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) Client VM (build 23.5-b02, mixed mode)

Now you can set up your JAVA_HOME variable at a system level so other applications can use Java by editing “/etc/environment”:

sudo nano /etc/environment

Now add the following line to point to your newly installed Java:

JAVA_HOME=/usr/lib/jvm/jdk1.7.0_09

Now if you open up a new session (not your currect session) and type “echo $JAVA_HOME” you should see the path “/usr/lib/jvm/jdk1.7.0_09″ which means the variable has been set correctly.

My Oracle and Solaris Experience Overview

This post is to be updated as I dig out more of my original notes and bookmarks. It was written for an overview document to be handed to the next person handling the Oracle project:

The Oracle ADF development guide gives a good overview of the entire Application Development Framework as provided by Oracle and is targeted at Oracle 10g. There is a short presentation on ADF available.
Migration to Oracle from Access is best done using the ODBC connection to Oracle and standard SQL commands. There are other alternatives but most migration tools didn’t work properly or were expensive. Some of the tools tried include Oracle SQL Developer, EMS Data import, Apatar, Oracle Migration Workbench (see this forum thread).

The installation process of Oracle on Solaris took some time to get to work but despite a few typos this guide is the best source of information on Oracle installation. More information is available here but this is a slightly different installation method. My blog at http://blog.jamesrossiter.co.uk has some of the steps I took to install Oracle as well as a few of the pitfalls in the documentation to watch out for.
There is some slightly outdated info on Oracle’s built in http server here and here which helped explain a few of the different components Oracle needs for http.

The Oracle web server of choice is OC4J, Oracle Containers for Java. The most useful tutorials for working with JDeveloper and OC4J were on deployment of applications as well as this, the most important tutorial in this list on JSF, EJB and Oracle’s preferred way of writing web apps with JDeveloper. OC4J is based on Apache and must be installed separately to Oracle. A cut down old version of OC4J is included with Oracle 10g but this is not to be used to develop apps. A lot of the documentation is confusing on this but after checking the forums it appears you need to install a standalone OC4J instance or install the Oracle Application Server. I installed the standalone OC4J as it seems much easier to use and the documentation I found is mainly focused on the standalone version.

I had a look at Oracle htmlDB, which has been updated and is now called Apex (Oracle Application Express). This is supposed to be a very quick way of prototyping database driven applications, see this unofficial overview. There is an unofficial wiki for Apex. I got Apex to work but the amount of flexibility provided was not enough and I was concerned that we would outgrow the abilities of Apex when writing custom apps.

The best way to write online apps looks to be the ADF way of doing things with Jdeveloper, Oracle 10g (or 11) and OC4J. For this you need to know Enterprise Java Beans, Java Server Faces and how to use Jdeveloper to deploy your applications to OC4J. I had problems deploying applications to my Solaris install of OC4J using Jdeveloper but have tested several small apps based on the tutorial (in bold above) using the built in OC4J server in Jdeveloper. My forum posts with the problems I faced following the deployment tutorial are here and here but I still didn’t manage to solve the problem. There is a third party forum devoted to developing for Oracle.

The key to Jdeveloper web application creation is Master-Detail relationships, made possible through foreign key relationships in the Oracle database and automatic object creation using Java Beans. Master-Detail relationships can be easily visualised using the templates available in Oracle ADF Server Faces (a more Oracle focused version of Java Server Faces) and there are plenty of tutorials available from Oracle like those in the official documentation.

Setting Up & Starting Apache and Tomcat on Solaris 10 x86

Apache, Java and Tomcat are all installed by default in my copy of Solaris 10 x86, I assume this is the same for all versions of Solaris. I was dreading compiling Apache and Tomcat from source and was even considering installing the package from Blastwave.org. Luckily I googled a bit more and soon realised everything was installed by default, which is actually a bit obvious when you think about it.

Thanks to a random bug report page on opensolaris.org requesting an addition in documentation I got straight to the answer. I had to add an extra step in to add the required environment variables (which are now sitting in my “profile” file to be loaded each time). I’ve compressed the information a bit here but these are the steps I took to start Apache and Tomcat:

First add the two environment variables JAVA_HOME and CATALINA_BASE (for Tomcat) to your “/etc/profile” file or current session using usual “export” command:

export JAVA_HOME=/usr/java

and

export CATALINA_BASE=/var/apache/tomcat

Now you need to make sure the config files for both Apache and Tomcat exist with the right filenames. Luckily there are example config files included with both so you can just rename/copy these config files:

cp /etc/apache2/httpd.conf-example /etc/apache2/httpd.conf

cp /var/apache/tomcat/conf/server.xml-example /var/apache/tomcat/conf/server.xml

Now you can start up Apache:

svcadm enable apache

Now make a symbolic link to point the Tomcat “conf” directory to the Apache Tomcat “conf” directory (just to make sure config files come from the right place):

cd /usr/apache/tomcat

ln -s /var/apache/tomcat/conf conf

Now last of all, start up the Tomcat server using the startup.sh script in the Tomcat “bin” directory:

/usr/apache/tomcat/bin/startup.sh

Now you have both Apache and Tomcat running (on ports 80 and 8080 respectively). The home directory for Apache, where the html documents etc are stored, is located at “/var/apache2/htdocs/”. The home directory for Tomcat is at “/var/apache/tomcat/webapps/ROOT”.

Interestingly the test page for Tomcat at “http://localhost:8080″ states the environment variable as “$CATALINA_HOME” and not “$CATALINA_BASE” as I used. My Tomcat seems to be perfectly happy and I can run the sample applications so I guess you don’t need to worry about this.

UPDATE:

If you have installed Oracle you can use Oracle’s own web application server (OC4J) at “http://localhost:1158″. There is a default page here with links to documentation etc. I’ll write more on using this once I figure out how to do dev work in Windows and push it to our Solaris installs.

Find Running CPU Intensive Processes in Solaris

After a quick googling I found this article at Sun on finding out what’s going on with your processes from a terminal. Just type:

prstat

into a terminal and get a great regularly refreshing task list. There are other commands to do similar things & prstat can do a lot more I’m sure but this is dead handy.

Turns out that Java (probably the Java desktop environment) chews a fair amount of cpu just sitting there not doing anything, its almost always at the top of the list for cpu percentage. It could be because I am using RDP to remote in via Remote Desktop but still, it’s not great.