Spring Boot: Custom PropertyEditor Example

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
Spring Custom Property Editor Example
Spring Custom Property Editor Example

Drop me your questions in the comments section.

Happy Learning !!

Source Code on Github

Comments

Subscribe
Notify of
guest
2 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.