如何修复`@requestbody`中的JSON解析错误和枚举(Enum)值?

huangapple go评论66阅读模式
英文:

How to fix JSON parse error in @requestbody and Enum value?

问题

我有两种方法:

  1. "JSON Body" 请求
  2. "Form param" 请求

第二种方法没问题,但是第一种方法有问题。
在这个方法中,当我发送一个枚举字段时,我得到以下错误:

JSON parse error: Cannot construct instance of ......service.dto.EuropeanLanguageEnumTypeDTO,问题:Unexpected value 'EN';nested exception is com.fasterxml.jackson.databind.exc.ValueInstantiationException:Cannot construct instance of ......service.dto.EuropeanLanguageEnumTypeDTO,问题:Unexpected value 'EN'
 at [Source: (PushbackInputStream); line: 6, column: 17] (through reference chain: ......service.dto.OrderCreateDTO["language"])

已解决 [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of ......service.dto.EuropeanLanguageEnumTypeDTO,问题:Unexpected value 'EN';nested exception is com.fasterxml.jackson.databind.exc.ValueInstantiationException:Cannot construct instance of ......service.dto.EuropeanLanguageEnumTypeDTO,问题:Unexpected value 'EN'
 at [Source: (PushbackInputStream); line: 6, column: 17] (through reference chain: ......service.dto.OrderCreateDTO["language"])]

EuropeanLanguageEnumTypeDTO.java:

public enum EuropeanLanguageEnumTypeDTO {
  
  BG("bg"),
  
  HR("hr"),
  
  CS("cs"),
  
  EN("en");

  private String value;

  EuropeanLanguageEnumTypeDTO(String value) {
    this.value = value;
  }

  @JsonValue
  public String getValue() {
    return value;
  }

  @Override
  public String toString() {
    return String.valueOf(value);
  }

  @JsonCreator
  public static EuropeanLanguageEnumTypeDTO fromValue(String value) {
    for (EuropeanLanguageEnumTypeDTO b : EuropeanLanguageEnumTypeDTO.values()) {
      if (b.value.equals(value)) {
        return b;
      }
    }
    throw new IllegalArgumentException("Unexpected value '" + value + "'");
  }
}

此外,我还有另一个组件,用于转换枚举,但只适用于 'form' 请求:

@Component
public class EuropeanLanguageEnumConverter implements Converter<String, EuropeanLanguageEnumTypeDTO> {

    @Override
    public EuropeanLanguageEnumTypeDTO convert(String value) {
        return EuropeanLanguageEnumTypeDTO.fromValue(value);
    }

}

可以工作的 JSON 示例和不工作的示例:

成功

{
    "language": "en"
}

失败

{
    "language": "EN"
}

我需要能够处理大小写。我已经搜索了很多并尝试了一些不同的方法,比如 jackson.mapper.ACCEPT_CASE_INSENSITIVE_ENUMS: true,但没有成功,请帮我解决这个问题。

附注:由于某些原因,我无法编辑 ENUM 类内部,因为它将与 openAPI 一起生成。

英文:

I've two methods:

  1. "JSON Body" request
  2. "Form param" request
@RequestMapping(value = &quot;/orders.json&quot;, consumes = { &quot;application/json&quot; }, method = RequestMethod.POST)
@Override
public ResponseEntity&lt;Void&gt; createOrder(@Valid @RequestBody OrderCreateDTO orderCreateDTO) {
    return doCreateOrder(orderCreateDTO);
}

@RequestMapping(value = &quot;/orders.json&quot;, consumes = { &quot;application/x-www-form-urlencoded&quot; }, method = RequestMethod.POST)
public ResponseEntity&lt;Void&gt; createOrderForm(@Valid @ModelAttribute OrderCreateDTO orderCreateDTO) {
    return doCreateOrder(orderCreateDTO);
}

The second method is fine, but there is an issue with the first.
In the method, when I sending an enum field, I got the following errors:

JSON parse error: Cannot construct instance of `......service.dto.EuropeanLanguageEnumTypeDTO`, problem: Unexpected value &#39;EN&#39;; nested exception is com.fasterxml.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of `......service.dto.EuropeanLanguageEnumTypeDTO`, problem: Unexpected value &#39;EN&#39;\n at [Source: (PushbackInputStream); line: 6, column: 17] (through reference chain: ......service.dto.OrderCreateDTO[\&quot;language\&quot;])

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `.......service.dto.EuropeanLanguageEnumTypeDTO`, problem: Unexpected value &#39;EN&#39;; nested exception is com.fasterxml.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of `......service.dto.EuropeanLanguageEnumTypeDTO`, problem: Unexpected value &#39;EN&#39;
 at [Source: (PushbackInputStream); line: 6, column: 17] (through reference chain: ......service.dto.OrderCreateDTO[&quot;language&quot;])]

EuropeanLanguageEnumTypeDTO.java:

public enum EuropeanLanguageEnumTypeDTO {
  
  BG(&quot;bg&quot;),
  
  HR(&quot;hr&quot;),
  
  CS(&quot;cs&quot;),
  
  EN(&quot;en&quot;);

  private String value;

  EuropeanLanguageEnumTypeDTO(String value) {
    this.value = value;
  }

  @JsonValue
  public String getValue() {
    return value;
  }

  @Override
  public String toString() {
    return String.valueOf(value);
  }

  @JsonCreator
  public static EuropeanLanguageEnumTypeDTO fromValue(String value) {
    for (EuropeanLanguageEnumTypeDTO b : EuropeanLanguageEnumTypeDTO.values()) {
      if (b.value.equals(value)) {
        return b;
      }
    }
    throw new IllegalArgumentException(&quot;Unexpected value &#39;&quot; + value + &quot;&#39;&quot;);
  }
}

Also, I've another component, to convert enum, but it just works only with 'form' request:

@Component
public class EuropeanLanguageEnumConverter implements Converter&lt;String, EuropeanLanguageEnumTypeDTO&gt; {

    @Override
    public EuropeanLanguageEnumTypeDTO convert(String value) {
        return EuropeanLanguageEnumTypeDTO.fromValue(value);
    }

}

Example of working JSON and not working:

success:

{
    &quot;language&quot;: &quot;en&quot;
}

fail:

{
    &quot;language&quot;: &quot;EN&quot;
}

I need to work with upper and lower case.
I search a lot and tried some different ways, such as jackson.mapper.ACCEPT_CASE_INSENSITIVE_ENUMS: true, but didn't work, please help me with this issue.

P.s. for some reason I can't edit inside ENUM class, because it will generate with openAPI.

答案1

得分: 2

第二种解决方案:您使用的带有@JsonCreator的方法是可行的,但需要进行小的更改。在您的枚举中添加以下方法:

@JsonCreator
public static EuropeanLanguageEnumTypeDTO forValue(String value) {
    return Stream.of(EuropeanLanguageEnumTypeDTO.values())
        .filter(enumValue -> enumValue.name().equals(value.toUpperCase()))
        .findFirst()
        .orElseThrow(IllegalArgumentException::new);
}
英文:

Second solution: the method which you use with @JsonCreator is ok but it needs small changes. Put to your enum the method below:

@JsonCreator
public static EuropeanLanguageEnumTypeDTO forValue(String value) {
    return Stream.of(EuropeanLanguageEnumTypeDTO.values())
        .filter(enumValue -&gt; enumValue.name().equals(value.toUpperCase()))
        .findFirst()
        .orElseThrow(IllegalArgumentException::new);
}

答案2

得分: -1

答案很简单,直接将枚举值放入你的DTO中,而不是使用字符串。
你不需要额外的映射器。

英文:

The answer is simple , try put in your DTO directly enum value instead of string.
You don't need additional mappers.

huangapple
  • 本文由 发表于 2020年10月27日 21:38:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/64555721.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定