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

自定义Converter对RequestParam生效,对RequestBody字段无效问题

Why Your CountryEnumConverter Isn’t Working for @RequestBody

The key issue here is that Spring uses different deserialization mechanisms for request parameters vs. JSON request bodies:

  • For @RequestParam, Spring relies on Converter<String, T> implementations to convert incoming string parameters to your enum type. That’s why your converter works here.
  • For @RequestBody, Spring uses Jackson’s ObjectMapper (via MappingJackson2HttpMessageConverter) to parse JSON into objects. Your Converter isn’t part of this JSON deserialization pipeline, so it never gets called.

Here are the most straightforward solutions to fix this:


Solution 1: Add a @JsonCreator Method to Your Enum

The simplest approach is to tell Jackson to use your existing getBySign method to deserialize the enum from a string. Just add the @JsonCreator annotation to the method:

public enum CountryEnum {
    US("us"),
    CA("ca");

    private final String sign;

    CountryEnum(String sign) {
        this.sign = sign;
    }

    @JsonCreator // This tells Jackson to use this method for deserialization
    public static CountryEnum getBySign(String country) {
        CountryEnum countryEnum = Arrays.stream(values())
                .filter(c -> c.sign.equalsIgnoreCase(country))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException(country + " - Country is not supported!"));
        return countryEnum;
    }

    // Optional getter for the sign field
    public String getSign() {
        return sign;
    }
}

This way, when Jackson encounters a string in the JSON body mapped to a CountryEnum field, it will call getBySign to convert the string to the correct enum value.


Solution 2: Create a Custom Jackson Deserializer

If you prefer to keep deserialization logic separate from the enum, you can create a dedicated Jackson deserializer and register it:

Step 1: Implement the Deserializer

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;

public class CountryEnumDeserializer extends StdDeserializer<CountryEnum> {

    public CountryEnumDeserializer() {
        super(CountryEnum.class);
    }

    @Override
    public CountryEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String countrySign = p.getValueAsString();
        CountryEnum countryEnum = CountryEnum.getBySign(countrySign);
        if (countryEnum == null) {
            throw new IllegalArgumentException(countrySign + " - Country is not supported!");
        }
        return countryEnum;
    }
}

Step 2: Register the Deserializer

You can register it either per field in your MyBody class:

public class MyBody {
    @NotNull
    @JsonDeserialize(using = CountryEnumDeserializer.class) // Apply to this field
    private CountryEnum country;

    // Constructors, getters, setters
}

Or globally for all CountryEnum fields in your Spring configuration:

import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonConfig {
    @Bean
    public SimpleModule countryEnumDeserializerModule() {
        SimpleModule module = new SimpleModule();
        module.addDeserializer(CountryEnum.class, new CountryEnumDeserializer());
        return module;
    }
}

Solution 3: Reuse Your Existing Converter with Jackson

If you want to avoid duplicating logic and reuse your CountryEnumConverter, you can configure Jackson to use Spring’s ConversionService:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import java.io.IOException;

@Configuration
public class JacksonConfig {
    private final ConversionService conversionService;

    public JacksonConfig(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    @Bean
    public SimpleModule conversionServiceModule() {
        SimpleModule module = new SimpleModule();
        module.addDeserializer(Enum.class, new StdDeserializer<Enum>(Enum.class) {
            @Override
            public Enum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                String value = p.getValueAsString();
                Class<?> enumType = ctxt.getContextualType().getRawClass();
                return (Enum) conversionService.convert(value, enumType);
            }
        });
        return module;
    }
}

This will make Jackson use Spring’s converters for all enum types, so your existing CountryEnumConverter will be used for @RequestBody fields too.


内容的提问来源于stack exchange,提问作者stefan.stt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 18:22:48