无法从 Spring Boot REST 中的 Hibernate POJO 返回 JSON

Posted

技术标签:

【中文标题】无法从 Spring Boot REST 中的 Hibernate POJO 返回 JSON【英文标题】:Unable to return JSON from Hibernate POJO in Spring Boot REST 【发布时间】:2018-07-07 16:53:41 【问题描述】:

我正在尝试使用 Spring Boot 创建一个基本的 REST 服务,该服务返回使用 Hibernate 从数据库创建的 POJO,然后将其转换为 JSON 并返回给 REST 调用。

我可以将常规的非 Hibernate POJO 作为 JSON 返回,但对于 Hibernate 对象,我收到此错误:

Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: 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); nested exception is com.fasterxml.jackson.databind.JsonMappingException: 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.example.springboottest.model.Person_$$_jvst48e_0["handler"])

这是我的代码:

Person.java

@Entity
@Table(name = "people")
public class Person implements Serializable 

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

private String nameLast;
private String nameFirst;

@Temporal(TemporalType.DATE)
private Date dob;

protected Person()

public Person(String nameLast, String nameFirst, Date dob) 
    this.nameLast = nameLast;
    this.nameFirst = nameFirst;
    this.dob = dob;


// Getters and Setters...

PersonRepository.java

@Repository
public interface PersonRepository extends JpaRepository<Person, Long>


PersonController.java

@RestController
public class PersonController 

    @Autowired
    PersonRepository personRepository;

    @GetMapping("/person/id:\\d+")
    public Person getPersonByID(@PathVariable long id)
        return personRepository.getOne(id);
    

如果有人可以帮助我理解为什么这不起作用,将不胜感激。谢谢!

【问题讨论】:

空bean的错误信息,你确定给定ID的那个人还是找到了? 您可以从控制器调用 DaoImpl,您可以在其中从 Hibernate 检索列表,然后当您在控制器中获取列表时,您可以使用 GSON 或使用 jackson binder 将其转换为 JSON。跨度> 正确答案:https://***.com/questions/24482117/when-use-getone-and-findone-methods-spring-data-jpa 【参考方案1】:

原来这都是我用错方法造成的。如果我将return personRepository.getOne(id) 替换为return personRepository.findOne(id),则效果很好。我不明白为什么getOne() 不起作用,但这确实解决了问题。

【讨论】:

【参考方案2】:

字段的 getter 必须是 public

如果这不起作用。您可能必须使用诸如 PersonDto.java 之类的 POJO,它只有这三个字段,以及这三个字段的 getter 和 setter。

【讨论】:

【参考方案3】:

这可能不是原因,但这是推荐的做法。而不是

@Autowired
PersonRepository personRepository;

这样做

PersonRepository personRepository;

@Autowired
public PersonController(PersonRepository personRepository)
this.personRepository = personRepository;

另外,在新的 Spring 启动中,我认为您不必实现 Serializable。如果我是正确的,它会在您使用 @Entity 注释时自动为您配置。

另外,尝试使空的Person()构造函数public

【讨论】:

【参考方案4】:

我也遇到了这个错误并得到了解决,并继续使用 getOne()。当我将实体作为直接响应发送时,这导致了错误。有两种方法可以解决这个问题:

    使用public ResponseEntity<UserEntity> getOneUser(@PathVariable Integer userid) return new ResponseEntity<>(userServiceImplementation.getOneUser(userid), HttpStatus.OK) 或者将Entity转换成DTOModelMapper mapper = new ModelMapper(); mapper.map(entityObject,DTOCLass.class);然后返回。

因为这篇文章很旧,所以更新它,这样像我这样的人就不会卡住了。

【讨论】:

【参考方案5】:

如果之前在同一事务中获取了实体,则在 findByName() 中会发生同样的事情(获取代理而不是真实对象)。对于 getOne() 它由 Spring 记录,但对于 findByName() 它却出人意料地发生。解决方法是使用 Hibernate.unproxy()。

      var optionalPotus= potusRepository.findByName("Biden");
      if(optionalPotus.isEmpty())
          return optionalPotus;
      
      Potus potus= optionalPotus.get();
      if(!(potus instanceof HibernateProxy))
          return optionalPotus;
      
      // This branch should never occur, but it happens sometimes.
      return Optional.of((Potus)Hibernate.unproxy(optionalPotus.get()));

【讨论】:

【参考方案6】:

在 Spring Data JPA 中默认 T getOne(ID id)可选的 findById(ID id) 方法将 延迟加载对象 在这里在加载数据之前 jackson api 尝试将其转换为 json。

这意味着杰克逊正在尝试将一个空对象转换为 json,这是我们遇到的错误。

我不确定 T getOne(ID id) 因为它在 spring data jpa 2.5.2 中已被弃用,但如果您将覆盖 Optional findById(ID id) 的声明 在您的存储库界面中,它将解决您的问题。

请看下面的代码sn-p:

@Repository 公共接口 BookRepository 扩展 JpaRepository

public Optional<Book> findById(Integer id);

【讨论】:

以上是关于无法从 Spring Boot REST 中的 Hibernate POJO 返回 JSON的主要内容,如果未能解决你的问题,请参考以下文章

无法从同一网络中的另一台计算机访问在我的计算机中运行的 SPRING BOOT 应用程序的 REST API

Spring boot:无法从另一个 Origin 访问安全资源 - CORS - Spring Security - Spring data rest

Rest Controller无法识别Spring Boot App中的GET请求

无法使用 Spring Boot 自动配置访问 REST 控制器

无法在 Spring Boot Data Rest 中启用 CORS

Spring Boot JPA多对多关系-Rest Web Service无法获取Get All中的所有子属性