【问题标题】:Unable to return JSON from Hibernate POJO in Spring Boot REST无法从 Spring Boot REST 中的 Hibernate POJO 返回 JSON
【发布时间】: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);
    }
}

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

【问题讨论】:

标签: hibernate spring-boot


【解决方案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()。当我将实体作为直接响应发送时,这导致了错误。有两种方法可以解决这个问题:

        1. 使用public ResponseEntity<UserEntity> getOneUser(@PathVariable Integer userid){ return new ResponseEntity<>(userServiceImplementation.getOneUser(userid), HttpStatus.OK)}
        2. 或者将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);
            

            }

            【讨论】:

              猜你喜欢
              • 2022-01-20
              • 2017-06-27
              • 2020-03-24
              • 2020-07-29
              • 2017-03-23
              • 2019-09-26
              • 2019-01-19
              • 1970-01-01
              • 2019-06-06
              相关资源
              最近更新 更多