NullPointerException and OneToMany Eager Fetch - spring-boot

In a Service I want to set the betrag for a BudgetGeschaeftfeld.
After setting the Betrag, a method of budgetPlan which is Fetch.Eager should be called to update its own Betrag. However I get a NullPointerException
java.lang.NullPointerException: Cannot invoke "com.bm.ent.budgetplan.BudgetPlan.berechnePrognose()" because "this.budgetPlan" is null
why is this happening? and what can I do to solve it?
my Class code:
#Entity(name= "Budgetgeschaftsfeld")
#Getter
#Setter
#NoArgsConstructor
public class BudgetGeschaeftsfeld extends Budget{
#JsonIgnore
#OneToMany(
mappedBy="budgetGeschaftfeld",
cascade=CascadeType.ALL,
orphanRemoval=true,
targetEntity = BudgetMarke.class
)
private List<BudgetMarke> childBudgets= new ArrayList<>();
#JsonIgnore
#ManyToMany
#ToString.Exclude
private List<User> users= new ArrayList<>();
#JsonIgnore
#ManyToOne( fetch=FetchType.EAGER,
cascade=CascadeType.PERSIST)
#JoinColumn(name="pid")
#ToString.Exclude
private BudgetPlan budgetPlan;
public BudgetGeschaeftsfeld(String name, BudgetTyp typ, Double betrag, String kommentar) {
super(name, typ, betrag, kommentar);
}
public void setBetrag(Double betrag) {
if (this.getBudgetTyp()==BudgetTyp.DYNAMISCH) {
super.setBetrag(this.betragChildBudgets());
}else {
super.setBetrag(betrag);
}
budgetPlan.berechnePrognose();
}

I think it's because you named a class but did not set an instance in memory of that class, because having this in your code is the same as = null:
private BudgetPlan budgetPlan;
So when your code executes with budgetPlan.berechnePrognose(); it cannot allocate anything in the memory.
Try:
#JsonIgnore
#ManyToOne( fetch=FetchType.EAGER,
cascade=CascadeType.PERSIST)
#JoinColumn(name="pid")
#ToString.Exclude
private BudgetPlan budgetPlan = new BudgetPlant();
Disclaimer: I have no experience with all the annotations in there, so maybe I'm missing the logic of this entire code but just make sure BudgetPlan budgetPlan != null.

The answer was
#JsonIgnore
#ManyToOne( fetch=FetchType.Lazy,
cascade=CascadeType.PERSIST)
#JoinColumn(name="pid")
#ToString.Exclude
private BudgetPlan budgetPlan;
and then getting the budgetplan before calling the method
public void setBetrag(Double betrag) {
if (this.getBudgetTyp()==BudgetTyp.DYNAMISCH) {
super.setBetrag(this.betragChildBudgets());
}else {
super.setBetrag(betrag);
}
detBudgetPlan().berechnePrognose();
}

Related

JPA lazy initialization error with #OneToMany #EmbeddedId

In Sprinboot/JPA I defined an entity with one-to-may association as follows:
#Entity
#Table(name = "useraccount", catalog = "useraccount")
public class UserAccount implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//other stuff...
#OneToMany(mappedBy ="tokenId.user", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval =true, fetch=FetchType.LAZY)
private Set<SecureToken> tokens = new HashSet<>();
public Set<SecureToken> getTokens()
{
return this.tokens;
}
//other getter and setter
}
The SecureToken entity:
#Entity
#Table(name = "secureToken", catalog = "useraccount")
public class SecureToken implements Serializable
{
#EmbeddedId
public SecureTokenId tokenId= new SecureTokenId();
#Column(unique = true)
private String token;
private Timestamp isConsumed;
#CreationTimestamp
#Column(updatable = false)
private Timestamp timestamp;
#Column(updatable = false)
#Basic(optional = false)
private Timestamp expireAt;
#MapsId("user_id")
#JoinColumn(name = "user_id", referencedColumnName ="id")
#ManyToOne
private UserAccount user;
public SecureToken(UserAccount user, String token, String tokenType, Timestamp timestamp, Timestamp expire)
{
super();
this.token=token;
this.tokenId.setTokenType(tokenType);
this.tokenId.setUser(user);
this.timestamp=timestamp;
this.expireAt=expire;
this.isExpired=false;
}
}
The SecureTokenId:
#Embeddable
public class SecureTokenId implements Serializable
{
#Column(name="tokenType")
private String tokenType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private UserAccount user;
public SecureTokenId()
{
super();
}
public SecureTokenId(String tokenType)
{
//this.user_id=user_id;
this.tokenType=tokenType;
}
#Override
public boolean equals(Object o)
{
if (o == null || getClass() != o.getClass())
return false;
SecureTokenId that = (SecureTokenId) o;
return Objects.equals(this.tokenType, that.tokenType) &&
Objects.equals(this.user.getId(), that.user.getId());
}
#Override
public int hashCode() {
return Objects.hash(tokenType, this.user.getId());
}
public void setTokenType(String tokenType)
{
this.tokenType=tokenType;
}
public String getTokenType()
{
return this.tokenType;
}
public void setUser(UserAccount user)
{
this.user=user;
}
public UserAccount getUser()
{
return this.user;
}
public Long getTokenId()
{
return this.user.getId();
}
}
But calling the method getToken() of entity UserAccount gets the famous "LazyInitializationException". I generally use Hibernate.initialize, but with this configuration I cannot get rid of the problem.
This how I create a token within a #Service annoted SecureTokenService class.
#Override
#Transactional
public SecureToken generateToken(UserAccount user, String tokenType)
{
byte[] random = new byte[64];
new SecureRandom().nextBytes(random);
Timestamp timestamp = java.sql.Timestamp.valueOf(LocalDateTime.now());
LocalDateTime expire= LocalDateTime.now().plusHours(12);
SecureToken token = new SecureToken(new SecureTokenId(user, tokenType),Base64.encodeBase64URLSafeString(random),
timestamp, Timestamp.valueOf(expire));
return token;
}
Then in the UserService class (#Service annotated) I try to create a token:
SecureToken token = secureTokenService.generateToken(user, type);
secureTokenService.save(token);
user.addSecureToken(token); //Error
this.save(user)
When I try to associate the token with the user the error is thrown. Without that statement, the application seems working but even with "spring.jpa.open-in-view = false" in application.properties calling user.getTokens() rises the lazy initialization error.
In parent child relationship, you didn't declare any parent reference from child side.
In the parent side (UserAccount), you declared as follows
#OneToMany(mappedBy ="user"....
Which means your child side (SecureToken) there is no such property named user.
To get rid of this situation,
First you need to declare user inside of SecureToken / SecureTokenId. From your definition, you declared user_id inside SecureTokenId, instead declare user inside SecureTokenId.
...
public class SecureTokenId ... {
...
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private UserAccount user;
...
}
Then in the UserAccount declare the #OneToMany as follows
#OneToMany(mappedBy ="tokenId.user"...
private Set<SecureToken> tokens;

Spring Controller Returns Object Incompletely

There are three classes (Course, Lesson, User).
#EqualsAndHashCode(callSuper = true)
#Entity
#Table(name = "usr")
#Data
public class User extends RepresentationModel<User> implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstname;
private String lastname;
private String username;
private String password;
#ElementCollection(targetClass = ERole.class, fetch = FetchType.EAGER)
#CollectionTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"))
#Enumerated(EnumType.STRING)
private Set<ERole> roles;
}
#Data
#Entity
#NoArgsConstructor
public class Lesson extends RepresentationModel<Lesson> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String startTime;
private String endTime;
private String dayOfWeek;
#ManyToOne
private User teacher;
}
#EqualsAndHashCode(callSuper = true)
#Data
#Entity
public class Course extends RepresentationModel<Course> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Date startDate;
private Date endDate;
private String name;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<User> teachers;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<User> students;
private String description;
#ManyToMany(cascade = CascadeType.ALL)
private Set<Lesson> lessons;
}
And also RestController (CoursesController). When accessing the server at /courses, I get the correct server response with all fields
.
#RestController
#RequestMapping("/courses")
public class CoursesController {
private final CourseService courseService;
private final UserService userService;
private final LessonService lessonService;
#Autowired
public CoursesController(CourseService courseService, UserService userService, LessonService lessonService) {
this.courseService = courseService;
this.userService = userService;
this.lessonService = lessonService;
}
#GetMapping
#Operation(
summary = "getAllCourses",
description = "Returns all available courses"
)
public ResponseEntity<Page<Course>> getAllCourses(#PageableDefault(sort = "id", size = 5) Pageable pageable) {
try {
Page<Course> coursePage = courseService.findAll(pageable);
for (Course course : coursePage.getContent())
course.add(linkTo(methodOn(CoursesController.class).getCourse(course.getId().toString())).withSelfRel());
return ResponseEntity.ok(courseService.findAll(pageable));
}
catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
#GetMapping("/{course-id}")
#Operation(
summary = "getCourse",
description = "Returns course by ID"
)
public ResponseEntity<Course> getCourse(#PathVariable ("course-id") String courseId) {
try {
Course course = courseService.getCourseById(courseId);
course.add(linkTo(methodOn(CoursesController.class).getCourse(courseId)).withSelfRel());
return ResponseEntity.ok(course);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
}
Why, when requesting a course by ID (GET /courses/{id}), does Spring return an incomplete object (despite the fact that I manually added several teachers, students and lessons)?
I need to get all the fields of my object.
My CourseRepository below.
#Repository
#Transactional
public interface CourseRepository extends JpaRepository<Course, Long> {
}
My CourseService below.
#Service
public class CourseService {
private final CourseRepository courseRepository;
private final LessonRepository lessonRepository;
private final UserRepository userRepository;
#Autowired
public CourseService(CourseRepository courseRepository, LessonRepository lessonRepository, UserRepository userRepository) {
this.courseRepository = courseRepository;
this.lessonRepository = lessonRepository;
this.userRepository = userRepository;
}
public Page<Course> findAll(Pageable pageable) {
return courseRepository.findAll(pageable);
}
public Course createCourse(CourseDto courseDto) {
Course course = new Course(courseDto.getStartDate(), courseDto.getEndDate(), courseDto.getName(), courseDto.getDescription());
return courseRepository.saveAndFlush(course);
}
public Optional<Course> getCourseById(String id) {
return courseRepository.findById(Long.parseLong(id));
}
public Course updateCourse(CourseDto courseDto, String id) {
Course course = courseRepository.findById(Long.parseLong(id)).get();
course.setStartDate(courseDto.getStartDate());
course.setEndDate(courseDto.getEndDate());
course.setName(courseDto.getName());
course.setDescription(courseDto.getDescription());
return courseRepository.saveAndFlush(course);
}
public Page<Lesson> getLessonsByCourse(String courseId, Pageable pageable) {
Course course = courseRepository.findById(Long.parseLong(courseId)).get();
return new PageImpl<>(new ArrayList<>(course.getLessons()), pageable, course.getLessons().size());
}
public Course addLesson(String courseId, LessonDto lessonDto) {
Course course = courseRepository.findById(Long.parseLong(courseId)).get();
Lesson lesson = new Lesson();
lesson.setStartTime(lessonDto.getStartTime());
lesson.setEndTime(lessonDto.getFinishTime());
lesson.setDayOfWeek(lessonDto.getDayOfWeek());
lesson.setTeacher(userRepository.getUserById(lessonDto.getTeacherId()));
lessonRepository.saveAndFlush(lesson);
System.out.println(lesson);
course.getLessons().add(lesson);
return courseRepository.saveAndFlush(course);
}
public void deleteCourse(String id) {
courseRepository.deleteById(Long.parseLong(id));
}
}
Which I would (or might) expect as well. I would links to be generated for those additional relationshps (at least normally with Spring Data RESt handling this is what would happen). I wonder what happens if you ditch the RepresentationModel from your JPA model and just expose Course then. As stated you don't really want your JPA and HATEOAS stuff to be intertwined. You want to have a specialized projection/dto to expose. WHy does it work for your findAll. well you aren't adding links to it (although you think it does but your findAll executes twice!).
Removed RepresentationModel from User class.
Thx to #M.Deinum

Infinite recursion with #JsonManagedReference and #JsonBackReference

I have an entity class that is self referencing itself. For example, a document can be linked to a parent document.
#Entity
#Table(name = "documents")
public class DocumentEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonIgnore
#JsonManagedReference
#ManyToOne(fetch = FetchType.LAZY)
private DocumentEntity parentDocument;
#JsonBackReference
#OneToMany(mappedBy = "parentDocument", fetch = FetchType.LAZY)
private Set<DocumentEntity> documents;
#Column(nullable = false, unique = true)
private String documentId;
#Column(nullable = false)
private String fileName;
}
In my entry point / controller layer :
#GetMapping(
path = "/{fileId}",
produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }
)
public DocumentResponse getParentDocument(#PathVariable("fileId") String fileId) {
modelMapper = createModelMapper();
DocumentDto documentDto = documentService.getParentDocument(fileId);
DocumentResponse documentResponse = modelMapper.map(documentDto, DocumentResponse.class);
documentResponse.getDocuments().forEach(document -> System.out.println(document.getDocumentId()));
return documentResponse;
}
In my Service layer :
#Override
public DocumentDto getParentDocument(String documentId) {
DocumentDto documentDtoResponse = new DocumentDto();
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
DocumentEntity storedDocumentEntity =
documentRepository.findByDocumentIdAndParentDocumentNull(documentId);
if(storedDocumentEntity.getDocumentId().isEmpty() || storedDocumentEntity.getDocumentId().isBlank()) {
throw new AppFileNotFoundException("Oops file not found");
}
documentDtoResponse = modelMapper.map(storedDocumentEntity, DocumentDto.class);
return documentDtoResponse;
}
In the repository:
Now I'm making a sql request in a repository interface that extends JpaRepository.
The application allow to have a parent document with child documents and child documents cannot have child documents.
#Repository
public interface DocumentRepository extends JpaRepository<DocumentEntity, Long> {
DocumentEntity findByDocumentIdAndParentDocumentNull(String documentId);
}
I also tried to implement the method using JPQL :
#Query("SELECT d FROM DocumentEntity d WHERE d.documentId = :documentId AND d.parentDocument IS NULL")
DocumentEntity findByDocumentIdAndParentDocumentNull(String documentId);
This query allow to get parent documents and child documents.
My code implementation separates response and database by using a DTO layer.
Issue:
My issue is that I obtain an infinite recursion. I think i'm using #JsonManagedReference and #JsonBackReference correctly. Even adding the same annotations to DTO pojo do not solve issue. If i add those annotation to response POJO, then I do not obtain child documents.
Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException
Inially I have a DTO class that also self refers to itself.
public class DocumentDto implements Serializable {
private String filePath;
private String mimeType;
private String documentType;
private DocumentDto parentDocument;
Set<DocumentDto> documents;
}
I created a second class without properties that are causing problems;
public class DocumentChildDto implements Serializable {
private String filePath;
private String mimeType;
private String documentType;
}
In the DocumentDto I simply replaced the DocumentDto with DocumentChildDto.
public class DocumentDto implements Serializable {
private String filePath;
private String mimeType;
private String documentType;
private DocumentChildDto parentDocument;
Set<DocumentChildDto> documents;
}
It's more a hack than a technical solution but it works fine. Here childDocumentDto object won't load the parentDocument.

JPA throws lazy loading exception even it is eager fetch

User entity
#Entity
#Table(name = "T_USER")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String email;
//A user can be employee in many organizations so he look at the same time as many emplyee
#JsonManagedReference(value = "user-association")
#OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private Set<Association> associations;
....
Association entity
#Entity
#Table(name = "T_ASSOCIATION")
public class Association implements Serializable {
#EmbeddedId
private AssociationId associationId;
private String permission;
#ManyToOne(fetch = FetchType.LAZY)
#JsonBackReference(value = "user-association")
#JoinColumn(name = "user_id", referencedColumnName = "id", insertable = false, updatable = false)
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#JsonBackReference(value = "organization-association")
#JoinColumn(name = "organization_id", referencedColumnName = "id", insertable = false, updatable = false)
private Organization organization;
POST endpoint
#PostMapping(path = "/{id}/users", consumes = MediaType.APPLICATION_JSON_VALUE)
public List<User> associateUserToOrganization(#RequestBody AssociationDTO userToOrgDTO, #PathVariable String id) {
Association association = new Association(new AssociationId(userToOrgDTO.getUserId(), userToOrgDTO.getOrganizationId()));
association.setPermission("GUEST_SET");
User userToAffect = userRepository.findById(userToOrgDTO.getUserId()).get();
Organization orgToAffect = organizationRepository.findById(userToOrgDTO.getOrganizationId()).get();
userToAffect.addAssociation(association);
orgToAffect.addAssociation(association);
organizationRepository.save(orgToAffect);
return userRepository.findAll().stream().filter(user -> !user.getAssociations().isEmpty()).collect(Collectors.toList());
}
When I add a user to the organization using POSTMAN with correct input, the famous error of serialization of lazy loading appears even I am not using fetch type Lazy
this is the error
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->jpa.workspace.manytomanyadditional.domain.User$HibernateProxy$pL9wPAuw["hibernateLazyInitializer"])
So i made the solution as it is mentioned in this exception and i put in application.properties,
spring.jackson.serialization.fail-on-empty-beans=false
and #JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) to remove it from the json
The issue is fixed sure, but why I am supposed to consider the User->associations relationship as Lazy fetching and not eager as I chose it...Is it related to #JsonManagedReference maybe?
am using spring 2.4.1 and hibernate (core 5.4.25 & annotations 5.1.2 Final)
Remove #JsonManagedReferenced, #JsonBackReference and add these following in your config class
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(jackson2HttpMessageConverter());
}
#Bean
public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(jacksonBuilder().build());
return converter;
}
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
Hibernate5Module hibernateModule = new Hibernate5Module();
hibernateModule.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, false);
builder.modules(hibernateModule);
builder.featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
builder.featuresToDisable(MapperFeature.DEFAULT_VIEW_INCLUSION);
return builder;
}

Infinite loop with spring-boot in a one to many relation

In a rest application, I use spring boot with jpa.
I have a class Lodger
who have
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger")
private List<Reference> referenceList;
In my class Reference, i have
#ManyToOne
#JoinColumn(name = "lodgerId")
private Lodger lodger;
when i call this method
#RequestMapping(value = "/lodgers/{lodgerId}", method = RequestMethod.GET)
public Lodger getLogderById(#PathVariable("lodgerId") long lodgerId) {
return lodgerService.getLodger(lodgerId);
}
I get this error
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError) (through reference chain: server.bean.Lodger["referenceList"]->org.hibernate.collection.internal.PersistentBag[0]->server.bean.Reference["lodger"]->server.bean.Lodger["referenceList"]->org.hibernate.collection.internal.PersistentBag[0]->server.bean.Reference["lodger"]->server.bean.Lodger["referenceList"]...
Solution:
Use
#JsonManagedReference annotation for the first objects instantiated
#JsonBackReference annotation for the second objects instantiated
First:
#JsonManagedReference
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger")
private List<Reference> referenceList;
Second:
#JsonBackReference
#ManyToOne
#JoinColumn(name = "lodgerId")
private Lodger lodger;
It happens when you have a cycle in return object and spring tries to serialize it to other type.
Try to create DTO or Value Object (simple POJO) without cycles from returned model and then return it.
If you primary keys in both tables are same name for example : id.
Add this
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class User {
...
}
And to Reference class.
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Reference {
...
}
The only thing that you need is, in your class in which you have the annotation #ManyToOne, implement the next annotation with the attributes that you want to skip in the value section
#JsonIgnoreProperties(value = {"yourAttribute", "handler", "hibernateLazyInitializer"}, allowSetters = true)
I put an example for your code ->
#ManyToOne(fetch = FetchType.LAZY)
#JsonIgnoreProperties(value = {"referenceList", "handler","hibernateLazyInitializer"}, allowSetters = true)
#JoinColumn(name = "lodgerId")
private Lodger lodger;
All the attributes that you put in the value section on the #JsonIgnoreProperties are ignored, with this you can resolve the infinite loop and use it for other developments with the same format in the future.
Do not return entity with circular dependencies via REST webservice - create new DTO class, map entities fetched from database and return it in webservice.
More info here: http://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application
Of course if you want you may use another mapping library, my personal favourite is Orika (http://orika-mapper.github.io/orika-docs/intro.html)
Lets assume your code looks like below :-
Lodger.class
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger")
private List<Reference> referenceList;
public List<Reference> getReferenceList() {
return referenceList;
}
public void setReferenceList(List<Reference> referenceList) {
this.referenceList = referenceList;
}
#Override
public String toString() {
return "Lodger[referenceList=" + referenceList + "]";
}
Reference.class
#ManyToOne
#JoinColumn(name = "lodgerId")
private Lodger lodger;
public Lodger getLodger() {
return lodger;
}
public void setLodger(Lodger lodger) {
this.lodger = lodger;
}
#Override
public String toString() {
return "Reference[lodger=" + lodger + "]";
}
When you notice at the toString() method written in both the POJO's, you will see that we are calling toString() of both the classes from either side which results in infinite no. of calls to toString() method from both sides which never terminates. To avoid this situation remove any the reference from toString() of Refernce.class[You may remove from Lodger class also.] So toString() of Reference class will not have lodger property in it.
So finally your Reference class will look like :-
Reference.class
#ManyToOne
#JoinColumn(name = "lodgerId")
private Lodger lodger;
public Lodger getLodger() {
return lodger;
}
public void setLodger(Lodger lodger) {
this.lodger = lodger;
}
#Override
public String toString() {
return "Reference[Properties other than lodger=" + properties other than lodger + "]";
}
#JsonIgnoreProperties({"hibernateLazyInitializer","referenceList"}) at class Level
For reference see this article on medium.com.

Resources