序列化一个对象时找不到序列化程序
No serializer found when serializing one Object
我正在尝试 return 一个对象作为 JSON。
使用 /user/id
端点,我想根据他的 ID 显示一个用户。
调用此 controllerMethod 时出现以下异常:
InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.sample.scrumboard.models.User_$$_jvsta02_1["handler"])
我的 contollerClass 看起来像这样:
@RestController
@RequestMapping(path="/user")
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserRestController {
private UserRepository repository;
@Autowired
public UserRestController(UserRepository repository){
this.repository = repository;
}
@GetMapping(value = "/list")
public List<User> getUsers(){
return repository.findAll();
}
@GetMapping(value = "/{id}")
public @ResponseBody User getUserById(@PathVariable Long id, User user){
user = repository.getOne(id);
return user;
}
}
我检查了所有字段是否有 public getter 并尝试了 @JSONIgnoreProperties 的各种选项,但我找不到它。
将所有用户显示为 JSON 列表确实适用于 JSON 列表和 /user/list
。所以问题只在尝试显示一个对象时出现,而不是对象列表。
它确实从存储库中找到了用户,但无法序列化该对象并将其放入屏幕。
用户 class 本身看起来像这样:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "userId", nullable = false, updatable = false)
private Long id;
@NotNull
@Size(min=2, max=20)
private String firstName;
@NotNull
@Size(min=2, max=30)
private String lastName;
@NotNull
@Size(min=2, max=20)
private String userName;
@NotNull
@Size(min=2, max=30)
private String passWord;
@NotNull
@Email
private String email;
//the mappedBy element must be used to specify the relationship field or property of the entity that is the owner of the relationship
@OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JsonIgnore
private List<UserStory> userStoryList;
public User() {
}
public User(String firstName, String lastName, String userName, String passWord, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.userName = userName;
this.passWord = passWord;
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", userName='" + userName + '\'' +
", passWord='" + passWord + '\'' +
", email='" + email + '\'' +
'}';
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<UserStory> getUserStoryList() {
return userStoryList;
}
public void setUserStoryList(List<UserStory> userStoryList) {
this.userStoryList = userStoryList;
}
}
如何显示我的用户 return 来自 /user/id
?
解决方案?
按照下面的建议,我使用 Dto 和 ModelMapper 使其工作。
我加了
@Bean
public ModelMapper modelMapper(){
return new ModelMapper();
}
控制器方法
@GetMapping(value = "/{id}")
public UserDTO getUserById(@PathVariable Long id, User user, ModelMapper modelMapper){
user = repository.getOne(id);
return modelMapper.map(user, UserDTO.class);
}
和 UserDto
public class UserDTO {
private Long id;
private String firstName;
private String lastName;
private String userName;
private String passWord;
private String email;
private List<UserStory> userStoryList;
//getters and setters
现在我可以在屏幕上显示用户了。
我仍然想知道是否没有使用 Jackson 且没有 modelmapper 和 dto 的解决方案?
也许使用您的实体(用户)通过 REST 公开有关用户的数据不是一个好主意?你能为你的用户创建 UserDTO 来实现 Serializable 并通过 REST 发送这个 DTO 吗?在这种情况下,应该有必要将从数据库中检索到的用户对象转换为 UserDTO。
注解@JsonIgnoreProperties
不应该在UserRestController
上,需要序列化的是User
,去掉注解即可。 Jackson 将帮助完成所有工作,如果您想忽略 class User
上的某些字段,请将 @JsonIgnoreProperties
移至用户 class,并添加 @JsonProperty
归档需要显示在页面上。
您的 orm 的可序列化性 classes 实现了 java.io.Serializable 接口
您正在使用@RestController,不需要@ResponseBody
此外,无需创建 DTO class 来转换响应 json 的 ORM class。
OBS:对于双向关系,您将使用@JsonManagedReference、@JsonBackReference
不要在控制器class中使用@JsonIgnoreProperties(ignoreUnknown = true)
。
在实体中使用以下注释 class。那解决了那个问题。
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
尝试将以下行添加到您的 application.properties 文件中:
spring.jackson.serialization.fail-on-empty-beans=false
spring repository.getOne() 和 repository.findById() 之间存在差异。使用 getOne() 您可以获得参考(代理),例如如果该对象已在同一事务中读取。使用 findById() 你总能得到预期的用户。
我正在尝试 return 一个对象作为 JSON。
使用 /user/id
端点,我想根据他的 ID 显示一个用户。
调用此 controllerMethod 时出现以下异常:
InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.sample.scrumboard.models.User_$$_jvsta02_1["handler"])
我的 contollerClass 看起来像这样:
@RestController
@RequestMapping(path="/user")
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserRestController {
private UserRepository repository;
@Autowired
public UserRestController(UserRepository repository){
this.repository = repository;
}
@GetMapping(value = "/list")
public List<User> getUsers(){
return repository.findAll();
}
@GetMapping(value = "/{id}")
public @ResponseBody User getUserById(@PathVariable Long id, User user){
user = repository.getOne(id);
return user;
}
}
我检查了所有字段是否有 public getter 并尝试了 @JSONIgnoreProperties 的各种选项,但我找不到它。
将所有用户显示为 JSON 列表确实适用于 JSON 列表和 /user/list
。所以问题只在尝试显示一个对象时出现,而不是对象列表。
它确实从存储库中找到了用户,但无法序列化该对象并将其放入屏幕。
用户 class 本身看起来像这样:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "userId", nullable = false, updatable = false)
private Long id;
@NotNull
@Size(min=2, max=20)
private String firstName;
@NotNull
@Size(min=2, max=30)
private String lastName;
@NotNull
@Size(min=2, max=20)
private String userName;
@NotNull
@Size(min=2, max=30)
private String passWord;
@NotNull
@Email
private String email;
//the mappedBy element must be used to specify the relationship field or property of the entity that is the owner of the relationship
@OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JsonIgnore
private List<UserStory> userStoryList;
public User() {
}
public User(String firstName, String lastName, String userName, String passWord, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.userName = userName;
this.passWord = passWord;
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", userName='" + userName + '\'' +
", passWord='" + passWord + '\'' +
", email='" + email + '\'' +
'}';
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<UserStory> getUserStoryList() {
return userStoryList;
}
public void setUserStoryList(List<UserStory> userStoryList) {
this.userStoryList = userStoryList;
}
}
如何显示我的用户 return 来自 /user/id
?
解决方案?
按照下面的建议,我使用 Dto 和 ModelMapper 使其工作。
我加了
@Bean
public ModelMapper modelMapper(){
return new ModelMapper();
}
控制器方法
@GetMapping(value = "/{id}")
public UserDTO getUserById(@PathVariable Long id, User user, ModelMapper modelMapper){
user = repository.getOne(id);
return modelMapper.map(user, UserDTO.class);
}
和 UserDto
public class UserDTO {
private Long id;
private String firstName;
private String lastName;
private String userName;
private String passWord;
private String email;
private List<UserStory> userStoryList;
//getters and setters
现在我可以在屏幕上显示用户了。 我仍然想知道是否没有使用 Jackson 且没有 modelmapper 和 dto 的解决方案?
也许使用您的实体(用户)通过 REST 公开有关用户的数据不是一个好主意?你能为你的用户创建 UserDTO 来实现 Serializable 并通过 REST 发送这个 DTO 吗?在这种情况下,应该有必要将从数据库中检索到的用户对象转换为 UserDTO。
注解@JsonIgnoreProperties
不应该在UserRestController
上,需要序列化的是User
,去掉注解即可。 Jackson 将帮助完成所有工作,如果您想忽略 class User
上的某些字段,请将 @JsonIgnoreProperties
移至用户 class,并添加 @JsonProperty
归档需要显示在页面上。
您的 orm 的可序列化性 classes 实现了 java.io.Serializable 接口
您正在使用@RestController,不需要@ResponseBody
此外,无需创建 DTO class 来转换响应 json 的 ORM class。
OBS:对于双向关系,您将使用@JsonManagedReference、@JsonBackReference
不要在控制器class中使用@JsonIgnoreProperties(ignoreUnknown = true)
。
在实体中使用以下注释 class。那解决了那个问题。
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
尝试将以下行添加到您的 application.properties 文件中:
spring.jackson.serialization.fail-on-empty-beans=false
spring repository.getOne() 和 repository.findById() 之间存在差异。使用 getOne() 您可以获得参考(代理),例如如果该对象已在同一事务中读取。使用 findById() 你总能得到预期的用户。