Table of Contents
Overview
There are times you work with legacy databases that store boolean values as strings. Let’s consider this example: Town A conducted a survey to see if their citizens like apples or not. The developer back then created a table like this:
CREATE TABLE apple_survey ( id serial not null primary key, name varchar(50) not null, like_apple varchar(5) NOT NULL )
For the file like_apple, he planned to store LIKE and DONOT as values (who knows why he did that). The task now is to map the such string to boolean values so other developers can create API interacting with that legacy data.
It turned out, JPA has quite an elegant support for this case. Let’s find out how to convert string to boolean and vice versa.
Using @Converter
To convert between two data types in JPA, you need to create a converter. In this case, this is the implementation:
package com.learn.springdata.model.survey; import javax.persistence.AttributeConverter; import javax.persistence.Converter; @Converter(autoApply = false) public class LikeConverter implements AttributeConverter<Boolean, String> { @Override public String convertToDatabaseColumn(Boolean aBoolean) { return aBoolean ? "LIKE" : "DONOT"; } @Override public Boolean convertToEntityAttribute(String s) { return s != null && s.equalsIgnoreCase("LIKE"); } }
To define a JPA converter, you need to:
- Create a class and annotate it will @Converter
- Make that class implement the interface AttributeConverter.
You may notice autoApply is set to false. This prevents the converter from applying to all fields (since this situation involves only one field).
Next, in the entity class, specify that the boolean field needs this converter to work properly:
package com.learn.springdata.model.survey; import lombok.Getter; import lombok.Setter; import javax.persistence.Column; import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Getter @Setter @Table(name = "apple_survey") public class SurveyPerson { @Id @GeneratedValue private long id; private String name; @Convert(converter = LikeConverter.class) @Column(name = "like_apple") private boolean likeApple; }
You specify the converter by annotating the field you want to convert with @Convert and specify the converter class.
This is all you need to do. Next, let’s see how the conversion work.
Test the converter
Let’s create a controller to accept POST and GET requests to demonstrate setting and getting data to and from the database.
package com.learn.springdata.controller.survey; import com.learn.springdata.model.survey.SurveyPerson; import com.learn.springdata.repo.survey.SurveyPersonRepository; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/surveys") public class SurveyPersonController { private final SurveyPersonRepository repository; public SurveyPersonController(SurveyPersonRepository repository) { this.repository = repository; } @PostMapping public SurveyPerson save(@RequestBody SurveyPerson person) { return repository.save(person); } @GetMapping("/list") public List<SurveyPerson> getAll() { return repository.findAll(); } }
As you can see, I created two endpoints to create and list the records here. First, let’s create some records using Postman:
Now, let’s try the list endpoint:
The API works as expected. Let’s check the data in the database:
As you can see, in the database, data for the field like_apple is still stored as a string.
Conclusion
As you can see, by using the @Converter, @Convert, and the AttributeConverter interface, it was quite easy to convert String to Boolean and back with Spring Data JPA.
As usual, the code for this article is available on Github.
I build softwares that solve problems. I also love writing/documenting things I learn/want to learn.