Spring Boot CRUD REST API + Spring Data JPA + H2 DB:在测试中获取 NPE 但在 Postman 中不获取
Spring Boot CRUD REST API + Spring Data JPA + H2 DB: Getting NPE on tests but not on Postman
我正在做一些练习以熟悉 spring 框架并使用 REST API。我确实通过了练习,但没有通过我最初的实施。我想知道为什么我在测试中得到 NPE 而在 Postman 中却没有。
尝试解决此测验时测试抛出了 NPE:
{
"title": "Math4",
"text": "Which of the following is equal to 4?",
"options": ["2*3", "5*8", "8*0", "1*5"],
"answer": null
}
当我使用 Postman post 此测验到 dB 并解决时,一切正常。
但是当我 运行 它通过测试时,我收到以下信息:
堆栈跟踪:
java.lang.NullPointerException: null
at engine.presentation.controllers.QuizController.solveQuiz(QuizController.java:44) ~[main/:na]
at jdk.internal.reflect.GeneratedMethodAccessor90.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at jdk.internal.reflect.GeneratedMethodAccessor64.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:170) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:225) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.29.jar:9.0.29]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:108) ~[spring-boot-actuator-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1591) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]
build.gradle
plugins {
id 'org.springframework.boot' version '2.2.2.RELEASE'
id 'java'
id "io.freefair.lombok" version "6.1.0-m3"
}
apply plugin: 'io.spring.dependency-management'
sourceCompatibility = 11
repositories {
mavenCentral()
}
sourceSets.main.resources.srcDirs = ["src/resources"]
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
}
application.settings
server.port=8889
management.endpoints.web.exposure.include=*
management.endpoint.shutdown.enabled=true
# H2 data source setup
spring.datasource.url=jdbc:h2:file:../quizdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Automatically update tables when persistence objects have changed
spring.jpa.hibernate.ddl-auto=update
# Setup for the H2 console, used for viewing data in the database
spring.h2.console.enabled=true
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false
# Show SQL statements generated by Spring ORM
spring.jpa.show-sql=true
Quiz.java:
@Entity
@Table(name = "quizzes")
@NoArgsConstructor
@Getter
@Setter
@ToString
@JsonPropertyOrder({
"id",
"title",
"text",
"options"
})
public class Quiz {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private int id;
@NotBlank(message = "Title is required")
private String title;
@NotBlank(message = "Text is required")
private String text;
@NotEmpty(message = "There must be at least 2 options")
@Size(min = 2, message = "There must be at least 2 options")
private LinkedHashSet<String> options;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private HashSet<Integer> answer;
public void setAnswer(HashSet<Integer> answer) {
this.answer = Optional.ofNullable(answer).orElseGet(HashSet::new);
}
}
QuizController.java
@RestController
@RequestMapping("/api")
public class QuizController {
private final QuizService quizService;
@Autowired
public QuizController(QuizService quizService) {
this.quizService = quizService;
}
@GetMapping("/quizzes")
public Iterable<Quiz> getQuizzes() {
return quizService.findAll();
}
@GetMapping("/quizzes/{id}")
public Quiz getQuiz(@PathVariable @Min(0) int id) {
return quizService.findById(id);
}
@PostMapping("/quizzes")
public Quiz saveQuiz(@RequestBody @Valid Quiz quiz) {
return quizService.save(quiz);
}
@PostMapping("/quizzes/{id}/solve")
public Response solveQuiz(@RequestBody @Valid AnswerDto answer,
@PathVariable @Min(0) int id) {
return Response.builder()
.success(quizService.findById(id).getAnswer().equals(answer.getAnswer()))
.build();
}
}
QuizService.java:
@Service
public class QuizService {
private final QuizRepository repository;
@Autowired
public QuizService(QuizRepository repository) {
this.repository = repository;
}
public Iterable<Quiz> findAll() {
return repository.findAll();
}
public Quiz findById(int id) {
Optional<Quiz> quiz = repository.findById(id);
if (quiz.isEmpty()) {
throw new QuizNotFoundException(id);
}
return quiz.get();
}
public Quiz save(Quiz quiz) {
return repository.save(quiz);
}
}
我不明白的是,如果 setAnswer 方法从未将字段设置为空,那么如何使用空答案字段创建测验。据我了解,如有错误请指正。当使用@RequestBody 将JSON 反序列化为对象时,它使用默认(无参数)构造函数和定义的setter 方法来实例化对象。另外,为什么我无法在 Postman 上复制问题?
这仅用于教育目的。即使我解决了问题,我还是想了解我从哪里开始做错了。非常感谢任何帮助。
编辑:为澄清起见,如果在创建 Quiz 对象时将空值作为答案传递,则会创建一个空的 HashSet。这应该反序列化为一个空数组,如上面的 postman 图像所示。当我 post 回答测验时,我收到了成功响应,因为答案是 [];
问题是
quizService.findById(id).getAnswer().equals(answer.getAnswer())
在第一个 getAnswer()
returns null
时失败,无法在其上调用 equals
。
您可以改用 null-safe Objects::equals
:
Objects.equals(quizService.findById(id).getAnswer(), answer.getAnswer())
问题是测试发送的测验 json 没有明确的 answer
字段。在那种情况下,您的 setter 不会被 Jackson 调用。要强制执行当前在 setter 中的逻辑,具有 @JsonCreator
的构造函数应该有所帮助。
我正在做一些练习以熟悉 spring 框架并使用 REST API。我确实通过了练习,但没有通过我最初的实施。我想知道为什么我在测试中得到 NPE 而在 Postman 中却没有。
尝试解决此测验时测试抛出了 NPE:
{
"title": "Math4",
"text": "Which of the following is equal to 4?",
"options": ["2*3", "5*8", "8*0", "1*5"],
"answer": null
}
当我使用 Postman post 此测验到 dB 并解决时,一切正常。
但是当我 运行 它通过测试时,我收到以下信息:
堆栈跟踪:
java.lang.NullPointerException: null
at engine.presentation.controllers.QuizController.solveQuiz(QuizController.java:44) ~[main/:na]
at jdk.internal.reflect.GeneratedMethodAccessor90.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at jdk.internal.reflect.GeneratedMethodAccessor64.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:170) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:225) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.29.jar:9.0.29]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:108) ~[spring-boot-actuator-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at jdk.internal.reflect.GeneratedMethodAccessor47.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:282) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.run(SecurityUtil.java:279) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:550) ~[na:na]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:191) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.access[=14=]0(ApplicationFilterChain.java:47) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:149) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.ApplicationFilterChain.run(ApplicationFilterChain.java:145) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1591) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.29.jar:9.0.29]
at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]
build.gradle
plugins {
id 'org.springframework.boot' version '2.2.2.RELEASE'
id 'java'
id "io.freefair.lombok" version "6.1.0-m3"
}
apply plugin: 'io.spring.dependency-management'
sourceCompatibility = 11
repositories {
mavenCentral()
}
sourceSets.main.resources.srcDirs = ["src/resources"]
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
}
application.settings
server.port=8889
management.endpoints.web.exposure.include=*
management.endpoint.shutdown.enabled=true
# H2 data source setup
spring.datasource.url=jdbc:h2:file:../quizdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Automatically update tables when persistence objects have changed
spring.jpa.hibernate.ddl-auto=update
# Setup for the H2 console, used for viewing data in the database
spring.h2.console.enabled=true
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false
# Show SQL statements generated by Spring ORM
spring.jpa.show-sql=true
Quiz.java:
@Entity
@Table(name = "quizzes")
@NoArgsConstructor
@Getter
@Setter
@ToString
@JsonPropertyOrder({
"id",
"title",
"text",
"options"
})
public class Quiz {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private int id;
@NotBlank(message = "Title is required")
private String title;
@NotBlank(message = "Text is required")
private String text;
@NotEmpty(message = "There must be at least 2 options")
@Size(min = 2, message = "There must be at least 2 options")
private LinkedHashSet<String> options;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private HashSet<Integer> answer;
public void setAnswer(HashSet<Integer> answer) {
this.answer = Optional.ofNullable(answer).orElseGet(HashSet::new);
}
}
QuizController.java
@RestController
@RequestMapping("/api")
public class QuizController {
private final QuizService quizService;
@Autowired
public QuizController(QuizService quizService) {
this.quizService = quizService;
}
@GetMapping("/quizzes")
public Iterable<Quiz> getQuizzes() {
return quizService.findAll();
}
@GetMapping("/quizzes/{id}")
public Quiz getQuiz(@PathVariable @Min(0) int id) {
return quizService.findById(id);
}
@PostMapping("/quizzes")
public Quiz saveQuiz(@RequestBody @Valid Quiz quiz) {
return quizService.save(quiz);
}
@PostMapping("/quizzes/{id}/solve")
public Response solveQuiz(@RequestBody @Valid AnswerDto answer,
@PathVariable @Min(0) int id) {
return Response.builder()
.success(quizService.findById(id).getAnswer().equals(answer.getAnswer()))
.build();
}
}
QuizService.java:
@Service
public class QuizService {
private final QuizRepository repository;
@Autowired
public QuizService(QuizRepository repository) {
this.repository = repository;
}
public Iterable<Quiz> findAll() {
return repository.findAll();
}
public Quiz findById(int id) {
Optional<Quiz> quiz = repository.findById(id);
if (quiz.isEmpty()) {
throw new QuizNotFoundException(id);
}
return quiz.get();
}
public Quiz save(Quiz quiz) {
return repository.save(quiz);
}
}
我不明白的是,如果 setAnswer 方法从未将字段设置为空,那么如何使用空答案字段创建测验。据我了解,如有错误请指正。当使用@RequestBody 将JSON 反序列化为对象时,它使用默认(无参数)构造函数和定义的setter 方法来实例化对象。另外,为什么我无法在 Postman 上复制问题?
这仅用于教育目的。即使我解决了问题,我还是想了解我从哪里开始做错了。非常感谢任何帮助。
编辑:为澄清起见,如果在创建 Quiz 对象时将空值作为答案传递,则会创建一个空的 HashSet。这应该反序列化为一个空数组,如上面的 postman 图像所示。当我 post 回答测验时,我收到了成功响应,因为答案是 [];
quizService.findById(id).getAnswer().equals(answer.getAnswer())
在第一个 getAnswer()
returns null
时失败,无法在其上调用 equals
。
您可以改用 null-safe Objects::equals
:
Objects.equals(quizService.findById(id).getAnswer(), answer.getAnswer())
问题是测试发送的测验 json 没有明确的 answer
字段。在那种情况下,您的 setter 不会被 Jackson 调用。要强制执行当前在 setter 中的逻辑,具有 @JsonCreator
的构造函数应该有所帮助。