简体   繁体   中英

Stackoverflow error when saving an Object's toString value - Java/Hibernate/Spring

I have the following sample entities:

Institution

@Data
@Entity
@NoArgsConstructor
@EntityListeners(InstitutionAuditListener.class)
public class Institution extends Auditable<String> {

    @OneToMany(mappedBy = "institution", cascade = CascadeType.ALL)
    @JsonManagedReference
    private List<RegisteredProgram> registeredPrograms;

    private String name;
}

RegisteredProgram

@Data
@NoArgsConstructor
@Entity
@EntityListeners(RegisteredProgramAuditListener.class)
public class RegisteredProgram extends Auditable<String> {

   private String name;

   @ManyToOne
   @JoinColumn(name = "institution_id", nullable = false)
   @JsonBackReference
   private Institution institution;

   @Embedded
   private RegistrationRequirement registrationRequirement;

   @OneToMany(mappedBy = "registeredProgram", cascade = CascadeType.ALL)
   @JsonManagedReference
   private List<Official> officialList;
}

Official

@Data
@Entity
@EntityListeners(OfficialAuditListener.class)
@NoArgsConstructor
public class Official extends Auditable<String> {

    private String name;
    private String position;

    @ManyToOne
    @JoinColumn(name = "REGISTERED_PROGRAM_ID", nullable = false)
    @JsonBackReference
    private RegisteredProgram registeredProgram;
}

Audit Log

@Entity
@Data
@NoArgsConstructor
public class AuditLog extends AuditBase {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    private Long entityId;

    @Type(type = "yes_no")
    private Boolean isDeleted = false;

    @Column(columnDefinition = "json")
    @Convert(converter = JpaConverterJson.class)
    private String jsonObject;
}

When I attempted to save an instance of Official 's object toString() value into AuditLog 's jsonObject field, I encountered the error below:

java.lang.StackOverflowError: null
    at java.base/java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:173) ~[na:na]
    at java.base/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:538) ~[na:na]
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:174) ~[na:na]
    at com.tesda8.region8.program.registration.model.entities.RegisteredProgram.toString(RegisteredProgram.java:26) ~[classes/:na]
    at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:168) ~[na:na]
    at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:473) ~[na:na]
    at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
    at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:168) ~[na:na]
    at com.tesda8.region8.program.registration.model.entities.Institution.toString(Institution.java:23) ~[classes/:na]
    at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:168) ~[na:na]
    at com.tesda8.region8.program.registration.model.entities.RegisteredProgram.toString(RegisteredProgram.java:26) ~[classes/:na]

I was wondering if there are any annotations in spring/hibernate that could prevent this issue to occur or is there any other way that i could save the object's (JSON) value to an object's column in spring? I was assuming that @JsonManagedReference and @JsonBackReference should've prevented this issue to happen.

UPDATE

  1. I already tried to used toString() method for objects through Lombok's @Data annotation
  2. I also tried to use String.valueOf(official)

The problem is the fact you are using Lombok's @Data annotation to generate the equals , hashCode and toString method. This will lead to several issues/oddities (more info in this blog post I wrote ).

Trying to use a Jackson @JsonBackReference will ofcourse not solve the generating of the toString method, this will only help with creating JSON using the Jackson library.

What happens is that your toString of Institution will call the toString of the RegisteredProgram . Which will call the toString of Institution again, which will call the toString of RegisteredProgram again which.... (well you probably get the drift).

Don't rely on the equals , hashCode and toString methods from the @Data functionality to Lombok as, as mentioned in the start, it will lead to issues. Instead write your own equals , hashCode and toString or at least declare what needs to be part of those methods (the end result might even be that it is easier to write those methods by hand).

On the other hand, isn't storing the toString value a bit weird in the first place?

Related Links

  1. https://deinum.biz/2019-02-13-Lombok-Data-Ojects-Arent-Entities/
  2. https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/

Cheers for M. Deinum's insights regarding my issue. https://stackoverflow.com/a/65388643/14806310

The root cause of my problem was indeed using toString() by Lombok's @Data to save the details of my entity to a field, which was problematic right off the bat. I did try to override the toString() method of RegisteredProgram , which then solved the StackOverflow error, but still my approach on saving the JSON object was weird.

So rather than saving the object to String json column through toString() , I created a new HashMap field entityAttributes for my entity to persist a JSON object.

UPDATED AuditLog Entity

@Entity
@Data
@NoArgsConstructor
public class AuditLog extends AuditBase {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    private Long entityId;

    @Type(type = "yes_no")
    private Boolean isDeleted = false;

    @Convert(converter = HashMapConverter.class)
    private Map<String, Object> entityAttributes;
}

More details on how to save the JSON object can be seen through this link: https://www.baeldung.com/hibernate-persist-json-object

Also, moving forward, it really is recommended to create your own equals , hashCode and toString method for your entities and don't rely on Lombok etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM