在ControllerAdvice方法参数验证(@Valid)响应中返回@JsonAlias值。

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

Return @JsonAlias value in ControllerAdvice Method Argument Validation (@Valid) response

问题

我已经使用最新版本的javax.validation实现了一个简单的验证。

所以我的类:

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Person {

    @NotNull(message = "必填字段")
    @JsonAlias(value = "current_name")
    private String name;

    @NotNull(message = "必填字段")
    private String age;
}

然后我创建了一个Advice来处理和自定义异常消息。就像这样:

@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex,
            HttpHeaders headers,
            HttpStatus status,
            WebRequest request) {

        List<FieldError> errors = ex.getBindingResult().getFieldErrors();

        List<Field> listOfErrors = errors.stream()
                .map(error -> Field.builder()
                        .field(error.getField())
                        .message(error.getDefaultMessage())
                        .build())
                .collect(Collectors.toList());

        ApiError apiError = new ApiError("validation_error", "一些无效的字段", listOfErrors);
        return handleExceptionInternal(ex, apiError, headers, HttpStatus.BAD_REQUEST, request);
    }
}

所以,当我获得**error.getField()**时,它是一个原始属性名称:"name"。但我需要获取别名:"current_name"。

我正在使用Jackson库。

这是可能的吗?

英文:

I has implemented a simple validation using javax.validation, latest version.

So my class:

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Person {

    @NotNull(message = &quot;Required field&quot;)
    @JsonAlias(value = &quot;current_name&quot;)
    private String name;

    @NotNull(message = &quot;Required field&quot;)
    private String age;
}

And then I created a Advice to handle and customize the exception message.
Like this:

@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity&lt;Object&gt; handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex,
            HttpHeaders headers,
            HttpStatus status,
            WebRequest request) {

        List&lt;FieldError&gt; errors = ex.getBindingResult().getFieldErrors();

        List&lt;Field&gt; listOfErrors = errors.stream()
                .map(error -&gt; Field.builder()
                        .field(error.getField())
                        .message(error.getDefaultMessage())
                        .build())
                .collect(Collectors.toList());

        ApiError apiError = new ApiError(&quot;validation_error&quot;, &quot;Some invalid fields&quot;, listOfErrors);
        return handleExceptionInternal(ex, apiError, headers, HttpStatus.BAD_REQUEST, request);
    }
}

So, when a get the error.getField(), It is a original attribute name: "name". But I need to get the alias: "current_name".

I'm using Jackson lib.

It's possible?

答案1

得分: 1

在你的handleMethodArgumentNotValid方法中,执行以下操作:

  1. 获取当前参数类型的所有字段
    Field[] clsFields = ex.getParameter().getParameter().getType().getDeclaredFields();
  1. 找到匹配的字段以及该字段上的 @JsonAlias 注解

  2. 读取注解的值 --> 这是你放在注解中的值

 @JsonAlias(value = "current_name")
 String name;
  1. 使用该值代替原始字段 error.getField()

完整的工作示例:

import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.*;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.*;

@SpringBootApplication
public class JsonInspect {
    public static void main(String[] args) { SpringApplication.run(JsonInspect.class, args); }
}
@RestController
class Controller {
    @PostMapping("/test")
    public void t(@RequestBody @Valid Person p) {
        System.out.println(p);
    }
}
@ControllerAdvice
class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

        Field[] clsFields = ex.getParameter().getParameter().getType().getDeclaredFields();

        List<FieldError> errors = ex.getBindingResult().getFieldErrors();

        List<ErrField> listOfErrors = errors.stream()
                .map(e -> new ErrField(getJsonAlias(clsFields, e), e.getDefaultMessage()))
                .collect(Collectors.toList());

        ApiError apiError = new ApiError("validation_error", "Some invalid fields", listOfErrors);
        return handleExceptionInternal(ex, apiError, headers, HttpStatus.BAD_REQUEST, request);
    }

    String getJsonAlias(Field[] clsFields, FieldError e) {

        JsonAlias[] alisas = getAnnotationsForField(clsFields, e.getField());
        if (alisas == null || alisas.length == 0) {
            return e.getField();
        }

        String[] values = alisas[0].value();
        if (values.length == 0) {
            return e.getField();
        }

        return values[0];
    }
    JsonAlias[] getAnnotationsForField(Field[] clsFields, String fieldName) {
        Optional<Field> first = Stream.of(clsFields).filter(f -> f.getName().equals(fieldName)).findFirst();
        return first.map(field -> field.getAnnotationsByType(JsonAlias.class)).orElse(null);
    }

}

@Data
@AllArgsConstructor
class ErrField {
    String fld;
    String message;
}
@Data
@AllArgsConstructor
class ApiError {
    String type;
    String message;
    List<ErrField> fields;
}
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Data
class Person {
    @JsonAlias("person_name")
    @NotNull
    String name;
    @NotNull
    String address;
}

所需的库:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
英文:

In your handleMethodArgumentNotValid method, do the following

  1. Find all the fields for current parameter type
    Field[] clsFields = ex.getParameter().getParameter().getType().getDeclaredFields();
  1. Find matching Field and @JsonAlias annotations on that field

  2. Read value of the annotation --> which is the value that you put in

 @JsonAlias(value = &quot;current_name&quot;)
String name;
  1. Use that value instead of the original field error.getField()

Complete working example:

import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.*;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.*;
@SpringBootApplication
public class JsonInspect {
public static void main(String[] args) { SpringApplication.run(JsonInspect.class, args); }
}
@RestController
class Controller {
@PostMapping(&quot;/test&quot;)
public void t(@RequestBody @Valid Person p) {
System.out.println(p);
}
}
@ControllerAdvice
class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity&lt;Object&gt; handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
Field[] clsFields = ex.getParameter().getParameter().getType().getDeclaredFields();
List&lt;FieldError&gt; errors = ex.getBindingResult().getFieldErrors();
List&lt;ErrField&gt; listOfErrors = errors.stream()
.map(e -&gt; new ErrField(getJsonAlias(clsFields, e), e.getDefaultMessage()))
.collect(Collectors.toList());
ApiError apiError = new ApiError(&quot;validation_error&quot;, &quot;Some invalid fields&quot;, listOfErrors);
return handleExceptionInternal(ex, apiError, headers, HttpStatus.BAD_REQUEST, request);
}
String getJsonAlias(Field[] clsFields, FieldError e) {
JsonAlias[] alisas = getAnnotationsForField(clsFields, e.getField());
if (alisas == null || alisas.length == 0) {
return e.getField();
}
String[] values = alisas[0].value();
if (values.length == 0) {
return e.getField();
}
return values[0];
}
JsonAlias[] getAnnotationsForField(Field[] clsFields, String fieldName) {
Optional&lt;Field&gt; first = Stream.of(clsFields).filter(f -&gt; f.getName().equals(fieldName)).findFirst();
return first.map(field -&gt; field.getAnnotationsByType(JsonAlias.class)).orElse(null);
}
}
@Data
@AllArgsConstructor
class ErrField {
String fld;
String message;
}
@Data
@AllArgsConstructor
class ApiError {
String type;
String message;
List&lt;ErrField&gt; fields;
}
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Data
class Person {
@JsonAlias(&quot;person_name&quot;)
@NotNull
String name;
@NotNull
String address;
}

Required libraries

    &lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-validation&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;

huangapple
  • 本文由 发表于 2020年10月4日 02:47:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/64187804.html
匿名

发表评论

匿名网友

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

确定