findById 导致 StackOverflowError 但 findAll 工作正常
findById causes StackOverflowError but findAll workds fine
我在调用 JpaRepository findById() 的 spring 引导端点时遇到了一个奇怪的问题。每当我向端点 /v1/goals/{id} 发送 GET 请求时,都会发生堆栈溢出错误,而对 /v1/goals 的 GET 请求工作正常。
编辑:将错误消息添加到底部
简化控制器class:
@RestController
public class GoalController {
private final GoalServiceImpl service;
@Autowired
GoalController(GoalServiceImpl service) { this.service = service; }
@GetMapping("/v1/goals")
ResponseEntity<List<Goal>> allGoals() { return new ResponseEntity<>(service.getGoals(), HttpStatus.OK); }
@GetMapping("/v1/goals/{id}")
ResponseEntity<String> singleGoal(@PathVariable Long id) {
return new ResponseEntity<>(service.getGoalById(id).toString(), HttpStatus.OK);
}
}
简化服务class:
@Service
public class GoalServiceImpl implements GoalService {
private final GoalRepository repository;
@Autowired
public GoalServiceImpl(GoalRepository repository) { this.repository = repository; }
public Goal getGoalById(Long id) {
return repository
.findById(id)
.orElseThrow(() -> new GoalNotFoundException(id));
}
public List<Goal> getGoals() { return repository.findAll(); }
}
简化实体class:
@NoArgsConstructor
@Data
@Entity
public class Goal {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long goalId;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id")
@JsonIgnore
private User user;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "goal")
@JsonIgnoreProperties(value = "goal")
private List<Milestone> milestones;
}
简化的里程碑实体:
@NoArgsConstructor
@Data
@Entity
public class Milestone {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long milestone_id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
@JsonIgnore
private User user;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "goal_id")
private Goal goal;
简化的用户实体:
@NoArgsConstructor
@Data
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long userId;
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
@JsonIgnoreProperties(value = "user")
private List<Goal> goals;
}
错误信息:
java.lang.WhosebugError: null
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at com.motivate.api.user.User$HibernateProxy$KaIclPZ9.toString(Unknown Source) ~[classes/:na]
at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
at com.motivate.api.goal.Goal.toString(Goal.java:16) ~[classes/:na]
at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
at java.base/java.lang.StringBuilder.append(StringBuilder.java:168) ~[na:na]
at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:473) ~[na:na]
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
at com.motivate.api.user.User.toString(User.java:11) ~[classes/:na]
at jdk.internal.reflect.GeneratedMethodAccessor58.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.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at com.motivate.api.user.User$HibernateProxy$KaIclPZ9.toString(Unknown Source) ~[classes/:na]
解决方案
Chris 和 PaulD 在评论中提供:
@GetMapping("/v1/goals/{id}")
ResponseEntity<Goal> singleGoal(@PathVariable Long id) {
return new ResponseEntity<>(service.getGoalById(id), HttpStatus.OK);
}
删除 toString() ,因为这会导致整个对象被 lombok 序列化,而 lombok 不考虑 jackson 注释。将 ResponseEntity 更改为 Goal 类型并传入整个实体。
我在调用 JpaRepository findById() 的 spring 引导端点时遇到了一个奇怪的问题。每当我向端点 /v1/goals/{id} 发送 GET 请求时,都会发生堆栈溢出错误,而对 /v1/goals 的 GET 请求工作正常。
编辑:将错误消息添加到底部
简化控制器class:
@RestController
public class GoalController {
private final GoalServiceImpl service;
@Autowired
GoalController(GoalServiceImpl service) { this.service = service; }
@GetMapping("/v1/goals")
ResponseEntity<List<Goal>> allGoals() { return new ResponseEntity<>(service.getGoals(), HttpStatus.OK); }
@GetMapping("/v1/goals/{id}")
ResponseEntity<String> singleGoal(@PathVariable Long id) {
return new ResponseEntity<>(service.getGoalById(id).toString(), HttpStatus.OK);
}
}
简化服务class:
@Service
public class GoalServiceImpl implements GoalService {
private final GoalRepository repository;
@Autowired
public GoalServiceImpl(GoalRepository repository) { this.repository = repository; }
public Goal getGoalById(Long id) {
return repository
.findById(id)
.orElseThrow(() -> new GoalNotFoundException(id));
}
public List<Goal> getGoals() { return repository.findAll(); }
}
简化实体class:
@NoArgsConstructor
@Data
@Entity
public class Goal {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long goalId;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id")
@JsonIgnore
private User user;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "goal")
@JsonIgnoreProperties(value = "goal")
private List<Milestone> milestones;
}
简化的里程碑实体:
@NoArgsConstructor
@Data
@Entity
public class Milestone {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long milestone_id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
@JsonIgnore
private User user;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "goal_id")
private Goal goal;
简化的用户实体:
@NoArgsConstructor
@Data
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long userId;
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
@JsonIgnoreProperties(value = "user")
private List<Goal> goals;
}
错误信息:
java.lang.WhosebugError: null
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at com.motivate.api.user.User$HibernateProxy$KaIclPZ9.toString(Unknown Source) ~[classes/:na]
at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
at com.motivate.api.goal.Goal.toString(Goal.java:16) ~[classes/:na]
at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
at java.base/java.lang.StringBuilder.append(StringBuilder.java:168) ~[na:na]
at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:473) ~[na:na]
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
at com.motivate.api.user.User.toString(User.java:11) ~[classes/:na]
at jdk.internal.reflect.GeneratedMethodAccessor58.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.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at com.motivate.api.user.User$HibernateProxy$KaIclPZ9.toString(Unknown Source) ~[classes/:na]
解决方案
Chris 和 PaulD 在评论中提供:
@GetMapping("/v1/goals/{id}")
ResponseEntity<Goal> singleGoal(@PathVariable Long id) {
return new ResponseEntity<>(service.getGoalById(id), HttpStatus.OK);
}
删除 toString() ,因为这会导致整个对象被 lombok 序列化,而 lombok 不考虑 jackson 注释。将 ResponseEntity 更改为 Goal 类型并传入整个实体。