英文:
How to turn off deserialization for enum
问题
我想要为具体的枚举类型关闭反序列化。这可能吗?
练习模型类:
package main.exercise;
import lombok.*;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Entity
@Builder
public class Exercise {
@Id
@GeneratedValue
private int id;
@NonNull
private String name;
@NonNull
private ExerciseType exerciseType;
private double caloriesBurned;
private String exerciseDescription;
}
在控制器中有以下方法:
@PostMapping("/addExercise")
public List<String> addExercise(@RequestBody Exercise exercise) {
return exerciseCrudActivitiesService.addExercise(exercise);
}
该方法接受一个 Exercise 对象作为请求体,如果 Exercise 类型错误,我会在进行 POST http 请求时收到错误:
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type 'main.exercise.ExerciseType' from String "CARdDIO": not one of the values accepted for Enum class: [CARDIO, WEIGHTLIFTING]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type 'main.exercise.ExerciseType' from String "CARdDIO": not one of the values accepted for Enum class: [CARDIO, WEIGHTLIFTING]
at [Source: (PushbackInputStream); line: 4, column: 25] (through reference chain: main.exercise.Exercise["exerciseType"])]
问题出在服务中的验证器,它验证枚举类型是正确还是错误,并将字符串返回到所有验证器的错误列表。不幸的是,由于错误,无法达到这段代码。
public List<String> addExercise(Exercise exercise) {
ExerciseValidator validator = new ExerciseValidator();
List<String> messages = validator.validate(exercise);
if (messages.isEmpty()) {
exerciseRepository.save(exercise);
}
return messages;
}
验证器:
package main.exercise.validator.attributesvalidators;
import main.exercise.Exercise;
import main.exercise.ExerciseType;
import main.exercise.validator.ExerciseAttributesValidator;
import java.util.InputMismatchException;
public class ExerciseTypeValidator implements ExerciseAttributesValidator {
@Override
public String validate(Exercise exercise) {
if (exercise.getExerciseType() == null) {
return "You didn't put exercise type!";
}
try {
ExerciseType.forName(exercise.getExerciseType().name());
} catch (InputMismatchException e) {
return "Wrong exercise type!";
}
return null;
}
}
英文:
I would like to turn off deserialization for concrete enum. Is it possible?
Exercise model class:
package main.exercise;
import lombok.*;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Entity
@Builder
public class Exercise {
@Id
@GeneratedValue
private int id;
@NonNull
private String name;
@NonNull
private ExerciseType exerciseType;
private double caloriesBurned;
private String exerciseDescription;
}
I got method in controller:
@PostMapping("/addExercise")
public List<String> addExercise(@RequestBody Exercise exercise) {
return exerciseCrudActivitiesService.addExercise(exercise);
}
which takes Exercise body and if type of Exercise is wrong I got error while POST http request:
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `main.exercise.ExerciseType` from String "CARdDIO": not one of the values accepted for Enum class: [CARDIO, WEIGHTLIFTING]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `main.exercise.ExerciseType` from String "CARdDIO": not one of the values accepted for Enum class: [CARDIO, WEIGHTLIFTING]
at [Source: (PushbackInputStream); line: 4, column: 25] (through reference chain: main.exercise.Exercise["exerciseType"])]
The point is in service I got validator, which validates whether type of enum is right or wrong and return string to list of errors from all validators. Unfortunately this code cannot be reached because of error.
public List<String> addExercise(Exercise exercise) {
ExerciseValidator validator = new ExerciseValidator();
List<String> messages = validator.validate(exercise);
if (messages.isEmpty()) {
exerciseRepository.save(exercise);
}
return messages;
}
Validator
package main.exercise.validator.attributesvalidators;
import main.exercise.Exercise;
import main.exercise.ExerciseType;
import main.exercise.validator.ExerciseAttributesValidator;
import java.util.InputMismatchException;
public class ExerciseTypeValidator implements ExerciseAttributesValidator {
@Override
public String validate(Exercise exercise) {
if (exercise.getExerciseType() == null) {
return "You didn't put exercise type!";
}
try {
ExerciseType.forName(exercise.getExerciseType().name());
} catch (InputMismatchException e) {
return "Wrong exercise type!";
}
return null;
}
}
答案1
得分: 1
要关闭序列化和反序列化,您可以在exerciseType
字段上添加@JsonIgnore
。然而,我认为这样做并不能帮助您。
如果忽略序列化,该字段将始终为null
,这不是预期的行为。
您的验证器太迟了。注意:validate
方法以Exercise
对象作为参数。问题出现在创建此对象的过程中。当执行到ExerciseType.forName(exercise.getExerciseType().name());
这一行时,它永远不会抛出异常,因为getExerciseType()
已经是有效的枚举。
除了这个自定义验证器外,您还可以利用Spring的@ControllerAdvice
为该错误类型注册自己的异常处理程序。
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(InvalidFormatException.class)
public ResponseEntity<?> badFormatException(InvalidFormatException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
}
}
更多详情请参阅:https://www.springboottutorial.com/spring-boot-exception-handling-for-rest-services。
英文:
To turn off (de-)serialization, you can add the @JsonIgnore
to the exerciseType
field. However, I don't think this will help you anyways.
If serialization is ignored, the field would always be null
which is not the intended behavior.
Your validator is too late. Note: the validate method takes an Exercise
object as a parameter. The problem occurs during the creation of this object already.
When you get to the point that the line ExerciseType.forName(exercise.getExerciseType().name());
get's executed, it will NEVER throw an exception, because getExerciseType()
is already a valid enum.
Instead of this custom validator, you could make use of a Spring @ControllerAdvice
to register your own Exception handler for that error type.
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import com.fasterxml.jackson.databind.exc.InvalidFormatException
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(InvalidFormatException.class)
public ResponseEntity<?> badFormatException(InvalidFormatException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
}
}
See e.g. https://www.springboottutorial.com/spring-boot-exception-handling-for-rest-services for more details.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论