Spring MVC Type Conversion:Propertyeditor or Converter

Spring MVC type conversion : PropertyEditor or Converter?

With all these drawbacks, why using Converters ? Am I missing
something ? Are there other tricks that I am not aware of ?

No, I think you have very comprehensively described both PropertyEditor and Converter, how each one is declared and registered.

In my mind, PropertyEditors are limited in scope - they help convert String to a type, and this string typically comes from UI, and so registering a PropertyEditor using @InitBinder and using WebDataBinder makes sense.

Converter on the other hand is more generic, it is intended for ANY conversion in the system - not just for UI related conversions(String to target type). For eg, Spring Integration uses a converter extensively for converting a message payload to a desired type.

I think for UI related flows PropertyEditors are still appropriate especially for the case where you need to do something custom for a specific command property. For other cases, I would take the recommendation from Spring reference and write a converter instead(for eg, to convert from a Long id to an entity say, as a sample).

What is the difference between PropertyEditor, Formatter and Converter in Spring?

To help to understand these concepts I would differentiate first the Spring specific functionality from that exposed from Java.

PropertyEditors and the related stuff are defined by the JavaBeans Specification.

The specification defines an API, mechanisms and conventions for dealing with objects, objects properties, and everything related to their changes, as events.

PropertyEditors are typically used in GUIs to handle the interaction between an UI and the underlying objects model, typically handling the conversion between properties values from/to its String representation.

Spring itself actually uses different PropertyEditor implementations and Java Beans conventions in many different situations. For example, from the docs:

A couple of examples where property editing is used in Spring:

  • Setting properties on beans is done by using PropertyEditor
    implementations. When you use String as the value of a property of some
    bean that you declare in an XML file, Spring (if the setter of the
    corresponding property has a Class parameter) uses ClassEditor to try
    to resolve the parameter to a Class object.

  • Parsing HTTP request parameters in Spring’s MVC framework is done by
    using all kinds of PropertyEditor implementations that you can manually
    bind in all subclasses of the CommandController.

In summary, PropertyEditors allow you for a broader number of use cases.

Now, in the Spring world you need to do a differentiation as well between Spring MVC and Spring Core.

Please, note that both the Convert and the Formatter stuff are defined as core technologies, of relevance to any use case and not limited to the web framework.

The Spring documentation, when describing Spring Field Formatting, provides a great explanation about the purpose of every API/SPI and how they are related to PropertyEditors as well:

As discussed in the previous section, core.convert is a general-purpose
type conversion system. It provides a unified ConversionService API as
well as a strongly typed Converter SPI for implementing conversion logic
from one type to another. A Spring container uses this system to bind bean
property values. In addition, both the Spring Expression Language (SpEL)
and DataBinder use this system to bind field values. For example, when
SpEL needs to coerce a Short to a Long to complete an
expression.setValue(Object bean, Object value) attempt, the core.convert
system performs the coercion.

Now consider the type conversion requirements of a typical client
environment, such as a web or desktop application. In such environments,
you typically convert from String to support the client postback process,
as well as back to String to support the view rendering process. In
addition, you often need to localize String values. The more general
core.convert Converter SPI does not address such formatting requirements
directly. To directly address them, Spring 3 introduced a convenient
Formatter SPI that provides a simple and robust alternative to
PropertyEditor implementations for client environments.

In general, you can use the Converter SPI when you need to implement
general-purpose type conversion logic — for example, for converting between
a java.util.Date and a Long. You can use the Formatter SPI when you
work in a client environment (such as a web application) and need to parse
and print localized field values. The ConversionService provides a
unified type conversion API for both SPIs.

In the specific use case of Spring MVC the framework itself is able to handle simple types when handling the HTTP requests.

Type conversion is automatically applied based on the configured set of converters, although that behavior can be tweaked using DataBinders and the aforementioned Formatting system. Please, see the relevant docs.

In a typical use case in which you deal with reading and writing the body of HTTP requests and responses, when using the @RequestBody, for example, Spring will use a bunch of different pre-configured HttpMessageConverter implementations: the actual ones registered will depend on your configuration and the libraries imported in your project - say Jackson, for example. I was unable to find that point in the documentation but here is the link to the actual source code.

Please, consider review this related SO question, it could be of help.

How does Spring PropertyEditor know which Class propert to convert

When you register a PropertyEditor in application context, you are providing the converter from String to some type, in your case the JodaTime type. The bean holding the type, (Contact) don't matter. The application context will use your ContactPropertyEditor editor any time that need to set a property of type JodaTime as String on any bean.

So ContactPropertyEdit it's a bad name. It should be JodaTimePropertyEditor.

If you want a real ContactPropertyEditor, it should convert Strings to Contacts. For example:

<bean id="someBeanHoldingAContact" class="someBeanClass">
<property name="contact" value="Hendrix, Jimi, 1942-11-27, http://www.jimihendrix.com" />
</bean>

and the ContactPropertyEditor should use the string value to create the contact.

The magic is in org.springframework.beans.BeanWrapperImp class. See the javadoc

Spring MVC - PropertyEditor not called during ModelAttribute type conversion

Spring's ConversionService and Converters are replacement for standard Java Beans PropertyEditors.

You need to implement Converter instead of PropertyEditor if this feature is based purely on conversion service.


To register your custom converters in WebDataBinder you might use ConfigurableWebBindingInitializer or @InitBinder method.

Single Converter for multiple types in Spring (MVC)

The solution is using a ConverterFactory such as

public final class EntityIdConverterFactory implements ConverterFactory<String, EntityId> {

@Override
public <T extends EntityId> Converter<String, T> getConverter(final Class<T> targetType) {
return new StringToEntityIdConverter<>(targetType);
}

private static final class StringToEntityIdConverter<T extends EntityId> implements Converter<String, T> {
private final Class<? extends T> targetType;

StringToEntityIdConverter(final Class<? extends T> targetType) {
this.targetType = targetType;
}

@Nullable
@Override
public T convert(final String source) {
if (StringUtils.isEmpty(source)) {
return null;
}

try {
final T t = targetType.newInstance();
t.setId(Long.parseLong(source));
return t;
} catch (final Exception e) {
ReflectionUtils.handleReflectionException(e);
}
throw new AssertionError("Never reach here!");
}
}
}

What's the difference between Converter and HandlerMethodArgumentResolver?

A converter simply converts between two different types. An HttpMessageConverter converts a request message having a defined media type to an instance of a defined class. Converters are usually called by argument resolvers.

An argument resolver provides a value for an argument. E.g. there is a resolver that creates the value based an a request parameter (@RequestParam) or one that converts the request body (@RequestBody). Both use converters.

But the value doesn't have to be related to the request. You could create a resolver that returns the current time, something like

public void foo(@CurrentTime Date) {

How request parameter binding and type conversion works in spring-mvc?

  1. When you annotate a method with @RequestMapping, a RequestMappingHandlerAdapter will register built-in argument resolvers.

  2. The arguments of the handler method will be scanned, and based on the type or annotation an appropriate argument resolver will kick-in. For example, for the @RequestParam annotation, an RequestParamMethodArgumentResolver will be called

  3. An argument resolver guides further the conversion and binding if applicable. The conversion is handled by an appropriate implementation of the Converter or PropertyEditor. The binding is handled by an appropriate instance of DataBinder. For the case of RequestParamMethodArgumentResolver and e.g. @RequestParam("age"), a NumberEditor guides the conversion, and a WebDataBinder guides the binding.

Different cases that you have in your example, are all a subject of the above flow, but different argument resolvers kick in e.g. ModelAttributeMethodProcessor, different converters of editors kick in (you can register custom ones for custom types, or for the User a default constructor will be called etc.)

About the singleton dilemma, it refers to a single instance of the component, and it concerns only the instance variables of the component. Methods, and arguments within are OK to be new instance it plays no role from the singleton perspective

How to config a appropriate converter to spring MVC controller method?

Basically one of the options is Accept Header, but spring has a built-in mechanism to deal with requirement like this called Content negotiation, you can config your own config or use the standard spring config, checkout this article for further information: https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc



Related Topics



Leave a reply



Submit