Type Converters

What are Type Converters

Spring 3.x introduced a new type converter framework, and in the UI Framework we use this instead of their older PropertyEditor approach. (Spring's documentation is here but you shouldn't need to care about this, since they're wrapped by the UI Framework.)

The idea is that instead of writing an editor that converts a String to _and- from a custom type, we write one way converters. (A nice upside of this is being able to write a generic OpenmrsObjectToStringConverter, rather than having to write this functionality individually for each OpenmrsObject.)

The UI Framework uses Spring's conversion service in various ways, but the most common one is converting annotated method arguments in Page and Fragment controllers.

When do I need to write one?

Any time you introduce domain classes in a module, you'll probably want to write converters in your module from String to each domain class.

Occasionally you'll come across an OpenMRS type that doesn't have a converter implemented yet. In this case you should implement the converter in your module, and submit it for inclusion in the UI Framework module.

The error message you'd see in a stack trace for a missing converter would be something like this:

class org.springframework.core.convert.ConverterNotFoundException
: No converter found capable of converting from [java.lang.String] to [org.openmrs.Program]

How do I write one?

To add a new converter, you need to implement the converter, and instantiate it as a Spring bean. Both steps are trivial.

The converter class itself is typically no more than a few lines:

StringToProgramConverter.java
package org.openmrs.ui.framework.converter; // for a module: package org.openmrs.module.moduleid.converter

import org.apache.commons.lang.StringUtils;
import org.openmrs.Program;
import org.openmrs.api.context.Context;
import org.springframework.core.convert.converter.Converter;

/**
 * Converts from a {@link String} to a {@link Program}
 */
public class StringToProgramConverter implements Converter<String, Program> {

	/**
	 * Treats the string as the integer primary key of the Program
	 */
	@Override
	public Program convert(String id) {
		if (StringUtils.isBlank(id))
			return null;
		return Context.getProgramWorkflowService().getProgram(Integer.valueOf(id));
	}

}

The UI Framework's implementation of Spring's ConversionService will autowire any spring-managed converter. You may instantiate your converter via webModuleApplicationContext.xml

registering a converter via webModuleApplicationContext.xml
<bean class="org.openmrs.ui.framework.converter.StringToProgramConverter"/>

Alternate you may use annotation-driven configuration, like

registering a converter by annotation
...
@Component
public class StringToProgramConverter implements Converter<String, Program> {
...