You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.java file 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 to john.doe@example.com.
  • When saving the Employee entity, the emailId will automatically be converted to lowercase before being persisted to the database.

Content sourced from Stack Exchange, question author GAURAV PANT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 18:19:06