3

I am trying to create a basic REST service using Spring Boot that returns POJOs created from a database using Hibernate and then are transformed into JSON and returned to the REST call.

I can get regular non-Hibernate POJOs to be returned as JSON, but for Hibernate objects I am getting this error:

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"])

Here is my code:

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);
    }
}

If someone could help me understand why this is not working, it would be very much appreciated. Thanks!

Adam P
  • 4,603
  • 6
  • 31
  • 40
  • Error message about empty bean, are you sure that person with given ID or found? – Igor Bljahhin Jan 29 '18 at 06:37
  • You can call the DaoImpl from the controller where you can retrieve the list from Hibernate and then when you get the list in controller you can either convert it into JSON using GSON or by using jackson binder. – Akki Jan 29 '18 at 06:54
  • Right answer here : [https://stackoverflow.com/questions/24482117/when-use-getone-and-findone-methods-spring-data-jpa](https://stackoverflow.com/questions/24482117/when-use-getone-and-findone-methods-spring-data-jpa) – TungHarry Aug 15 '18 at 11:00

6 Answers6

6

It turns out this was all caused by me using the wrong method. If I replace return personRepository.getOne(id) with return personRepository.findOne(id), this works perfectly. I don't understand why getOne() does not work, but this did solve the issue.

Adam P
  • 4,603
  • 6
  • 31
  • 40
0

The getters for the fields need to be public.

If that doesn't work. you might have to use a POJO such as PersonDto.java, which would only have a those three fields, and the getter's and setters for those three fields.

DavidX
  • 1,281
  • 11
  • 16
0

This may not be the reason but this is the recommended practice. Instead of

@Autowired
PersonRepository personRepository;

Do this

PersonRepository personRepository;

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

Also, in new Spring boot, I don't think you have to implement Serializable. If i'm correct, it's automatically configured for you when you annotate it with @Entity.

In addition, try to make the empty Person() constructor public.

Rei Brown
  • 185
  • 9
0

I also go this error and got it resolved and keep using the getOne(). As i was sending the entity as the direct response this was causing the Error. There are two ways to resolve this:

  1. Use public ResponseEntity<UserEntity> getOneUser(@PathVariable Integer userid){ return new ResponseEntity<>(userServiceImplementation.getOneUser(userid), HttpStatus.OK)}
  2. Or convert the Entity into DTO ModelMapper mapper = new ModelMapper(); mapper.map(entityObject,DTOCLass.class); and then return it.

Since this post is old, but updating it so people like me dont get stuck.

0

The same thing (getting a proxy instead of the real object) happens in findByName() if the entity is fetched previously in the same transaction. For getOne() it is documented by Spring but for findByName() it happens surprisingly. Workaround is to use 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()));
0

In Spring Data JPA by default T getOne(ID id) and Optional findById(ID id) method will load object lazily and here before loading data jackson api trying to convert it into json.

That means jackson is trying to convert a null object into json that's by we are getting error.

I am not sure about T getOne(ID id) because it got deprecated in spring data jpa 2.5.2, but If you will override the declaration of Optional findById(ID id) in your repository interface it will solve your problem.

Please see below code snippet :

@Repository public interface BookRepository extends JpaRepository<Book, Integer> {

public Optional<Book> findById(Integer id);

}