In Java, a PropertyEditor is an interface that converts a property’s value to and from its native type representation into a String. Spring PropertyEditors acts as a converter between the String-based property values and the complex types to store the values.
1. PropertyEditors in Spring
Spring heavily uses PropertyEditors to be able to represent properties in a different way than the object itself, for example, parsing human-readable inputs from HTTP request params or displaying human-readable values of pure Java objects in the view layer.
Spring has a number of built-in PropertyEditors in the org.springframework.beans.propertyeditors package e.g. for Boolean
, Currency
, and URL
. Some of these editors are registered by default, while some you need to register when required.
For example, CustomNumberEditor converts a String to a number. The CustomDateEditor converts a String to a java.util.Date or its subclasses, and CurrencyEditor translates the currency codes into Currency objects.
2. Creating Custom PropertyEditor
We can create a custom PropertyEditor in case the default property editors do not serve the purpose. Spring has full support for registering custom PropertyEditor implementations. The only downside is that the java.beans.PropertyEditor interface has a lot of methods, and most are irrelevant to the parsing tasks.
A better approach is to extend the java.beans.PropertyEditorSupport class leaving us to implement only two methods: setAsText() and getAsText().
Let’s say we are creating an application for book management. Now people can search the books by ISBN as well. Also, you will need to display ISBN details on the webpage.
import org.springframework.util.StringUtils;
import java.beans.PropertyEditorSupport;
public class IsbnPropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasText(text)) {
setValue(new Isbn(text.trim()));
} else {
setValue(null);
}
}
@Override
public String getAsText() {
Isbn isbn = (Isbn) getValue();
if (isbn != null) {
return isbn.getIdentifier();
} else {
return "";
}
}
}
Where Isbn class is as below:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Isbn {
private String identifier;
}
3. Registering the Custom PropertyEditor
The next step is to register a custom property editor in the spring IoC Container. To register, you will need to create a method with annotation – @InitBinder
. On application startup, this annotation is scanned and all the detected methods should have a signature of accepting WebDataBinder
as an argument.
Always remember that PropertyEditors are not thread safe. You should always create a new instance of custom editor for every web request and register it with WebDataBinder.
@Controller public class HomeController { //... @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(Isbn.class, new IsbnEditor()); } }
To register the custom PropertyEditor globally, we can define it in a @Configuration class.
@Configuration
public class Config {
@Bean
public IsbnPropertyEditor isbnPropertyEditor() {
return new IsbnPropertyEditor();
}
@Bean
CustomEditorConfigurer customEditorConfigurer(){
var configurer = new CustomEditorConfigurer();
configurer.setCustomEditors(Map.of(Isbn.class, IsbnPropertyEditor.class));
return configurer;
}
}
4. How do we use the Custom PropertyEditor?
Now when the custom property editor is created and registered, let’s use it. You can use it in the controller to accept input as follows:
@Controller
public class HomeController {
private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
@RequestMapping(value = "/books/{isbn}", method = RequestMethod.GET)
public String getBook(@PathVariable Isbn isbn, Map<String, Object> model)
{
LOGGER.info("You searched for book with ISBN :: " + isbn.getIsbn());
model.put("isbn", isbn);
return "index";
}
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Isbn.class, new IsbnEditor());
}
}
Just look at how we are not accepting ISBN value directly in @PathVariable Isbn isbn
variable. Our IsbnEditor
is pretty much simple, but you can have a full range of rules and validations there and it will work.
To display the supplied value, you do not need a special way. Just plain old spring way.
<!DOCTYPE html>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html lang="en">
<body>
<h2>ISBN You searched is :: ${ isbn.displayValue }</h2>
</body>
</html>
5. Demo
Now test the application by running the spring boot application.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
Now hit the browser with URL: http://localhost:8080/books/978-3-16-148410-0
Verify the logs in the server, and display in a browser that isbn received as request input is correct as passed as the path parameter.
2017-03-16 13:40:00 - You searched for book with ISBN :: 978-3-16-148410-0
Drop me your questions in the comments section.
Happy Learning !!
Comments