Search code examples
jsonspring-bootjpaspring-testobjectmapper

ObjectMapper.writeValueAsString JsonMappingException: failed to lazily initialize


There are two problems that I do not understand. First, the error message on the console. It does not give me the whole error message. Therefore I do not understand the issue at all :S The IDE is STS.

enter image description here

Second, why do I get this error, "JsonMapping failed to lazily initialize a..."

@Test
public void testUpdateCar() throws Exception {
    Car car = carRepository.findById(new Long(1)).get();
    car.setBrand("Mazda");
    car.setModel("326");

    String putJSON = objectMapper.writeValueAsString(car);
    mockMVC.perform(MockMvcRequestBuilders.put(String.format("/api/cars/%d", car.getId())).contentType(MediaType.APPLICATION_JSON_UTF8).content(putJSON))
    .andDo(MockMvcResultHandlers.print())
    .andExpect(MockMvcResultMatchers.status().isCreated())
    .andExpect(MockMvcResultMatchers.content().contentType("application/hal+json;charset=UTF-8"));
}

Car:

@Entity
public class Car {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @OneToOne
    private User owner;
    private String brand;
    private String model;
    private String color;
    private String plate;
    private String additionals;

Update 1: The error itself:

com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: me.eraytuncer.carpool.entity.User.carList, could not initialize proxy - no Session (through reference chain: me.eraytuncer.carpool.entity.Car["owner"]->me.eraytuncer.carpool.entity.User["carList"])

Update 2:

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String firstName;
    private String lastName;
    private String phone;
    private String email;

    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = "owner")
    private List<Car> carList;

Update 3:

@PutMapping("/cars/{id}")
ResponseEntity<?> replaceCar(@RequestBody Car newCar, @PathVariable Long id) {
    if (repository.existsById(id)) {
        newCar.setId(id);
        Resource<Car> carResource = assembler.toResource(repository.save(newCar));
        try {
            return ResponseEntity
                    .created(new URI(carResource.getId().expand().getHref()))
                    .body(carResource);
        } catch (URISyntaxException e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }                   
    } else {
        throw new CarNotFoundException(id);
    }
}

Update 4:

Adding @JsonIgnore solved the issue somehow. Maybe it was a misleading issue caused by infinite recursion?


Solution

  • Looks like field

    private List<Car> carList;
    

    is resolved lazily (default fetch type in @OneToMany), which means it is populated from DB only when getter for this field is called. In your case it is called by Jackson serializer outside scope of the Hibernate session and property cannot be populated. Changing fetch type to EAGER in @OneToMany on carList property should help.

    Also consider using DTO pattern, because returning entities from API is considered as bad practice.