Spring Boot中如何实现通用的@ToLowerCase自定义注解?
Yes, this is absolutely feasible! You can create a custom @ToLowerCase annotation that works seamlessly for both REST request POJOs and JPA entity POJOs. Let’s break down the implementation step by step:
Step 1: Define the @ToLowerCase Annotation
First, create the annotation itself. It’ll target fields and retain at runtime so we can inspect it via reflection:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ToLowerCase { }
Step 2: Add Jackson Support for REST Request POJOs
To automatically convert annotated fields to lowercase when deserializing REST request bodies, we’ll hook into Jackson’s deserialization pipeline:
2.1 Create a Custom String Deserializer
This deserializer converts incoming string values to lowercase:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import java.io.IOException; public class ToLowerCaseDeserializer extends JsonDeserializer<String> { @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String value = p.getText(); return value != null ? value.toLowerCase() : null; } }
2.2 Register the Deserializer via an Annotation Introspector
We’ll create an introspector that tells Jackson to use our deserializer for fields marked with @ToLowerCase:
import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; public class ToLowerCaseAnnotationIntrospector extends JacksonAnnotationIntrospector { @Override public JsonDeserializer<?> findDeserializer(Annotated a) { if (a.getAnnotation(ToLowerCase.class) != null) { return new ToLowerCaseDeserializer(); } return super.findDeserializer(a); } }
2.3 Configure Jackson in Spring Boot
Register the introspector with Spring’s ObjectMapper:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.setAnnotationIntrospector(new ToLowerCaseAnnotationIntrospector()); return mapper; } }
Step 3: Add JPA Support for Entity POJOs
To convert annotated fields to lowercase before persisting/updating JPA entities, we’ll use a lifecycle listener:
3.1 Create an Entity Listener
This listener will inspect entities before persistence/update and convert marked fields:
import jakarta.persistence.PrePersist; import jakarta.persistence.PreUpdate; import java.lang.reflect.Field; public class ToLowerCaseEntityListener { @PrePersist @PreUpdate public void convertToLowerCase(Object entity) throws IllegalAccessException { Class<?> clazz = entity.getClass(); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(ToLowerCase.class) && field.getType().equals(String.class)) { field.setAccessible(true); String value = (String) field.get(entity); if (value != null) { field.set(entity, value.toLowerCase()); } } } } }
3.2 Register the Listener
You have a few options to register the listener:
- Per Entity: Add
@EntityListeners(ToLowerCaseEntityListener.class)to individual JPA entities. - Package-Level: Create a
package-info.javafile in your entity package to apply the listener to all entities in that package:@EntityListeners(com.yourpackage.ToLowerCaseEntityListener.class) package com.yourpackage.entities; import jakarta.persistence.EntityListeners; - Global: Use Spring’s JPA configuration to register it globally (works for all entities regardless of package):
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import javax.sql.DataSource; import java.util.Properties; @Configuration public class JpaConfig { @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource); em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); Properties jpaProps = new Properties(); jpaProps.put("hibernate.ejb.interceptor", "com.yourpackage.ToLowerCaseEntityListener"); em.setJpaProperties(jpaProps); return em; } }
Step 4: Test the Implementation
Use your annotation in POJOs as intended:
import lombok.Data; // REST Request POJO @Data public class EmployeeRequest { private String name; @ToLowerCase private String emailId; private String gender; private String phoneNumber; }
import jakarta.persistence.Entity; import jakarta.persistence.Id; import lombok.Data; // JPA Entity @Entity @Data public class Employee { @Id private Long id; private String name; @ToLowerCase private String emailId; private String gender; private String phoneNumber; }
- When a REST request comes in with
emailId: "John.Doe@Example.COM", it’ll be deserialized tojohn.doe@example.com. - When saving the
Employeeentity, theemailIdwill automatically be converted to lowercase before being persisted to the database.
Content sourced from Stack Exchange, question author GAURAV PANT

