1

I want to start a relationship but I get an error that I can't understand.

Person.java

@Entity
@Getter
@Setter
@RequiredArgsConstructor
public class Personal implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String personName;
    private String personLastName;

    // comment old block 
    // @OneToOne(cascade = CascadeType.ALL)
    // private Address Address;

    // add 
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "person")
    private Address address;
}

Address.java

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class Address implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "Street")
    private String street;
    @Column(name = "Alley")
    private String alley;
    @Column(name = "District")
    private String district;

    // comment old block 
    // @OneToOne(mappedBy = "Address")
    // private Person person; 

    // add 
    @JoinColumn(name = "id")
    @OneToOne(fetch = FetchType.EAGER)
    @MapsId
    private Person person;

    
    public Adres(String street, String alley, String district, Person person) {
        this.street = street;
        this.alley = alley;
        this.district = district;
        this.person = person; 
    }
}

My Repository

    public String createUser(){
        Person p1 = new Person();
        p1.setId(p1.getId());
        p1.setPersonName("testPerson");
        p1.setPersonLastName("testPerson");
        p1.setAddress(new Address("test","test","test",p1)); // ad person on address constructor 
        personRepository.save(p1);
        return "Save is successful";
    }

AddressService.java

@Service
@RequiredArgsConstructor
public class AdresServices {


    private final AddressRepository addressRepository;


    public Optional<Address> getAddress(Integer id){
        return addressRepository.findById(id);
    }
}

I want to see "person" using address 1. but I get error. When I do mappedBy the program gives an error.

I am successfully saving to the database.

BUT! When I try to bring a member through the address table, or rather when I activate the use of @OneToOne(mappedBy = "x"), my program starts to give an error.

ERROR :

java.lang.StackOverflowError: null
    at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1012) ~[na:na]
    at java.base/java.util.concurrent.ConcurrentHashMap.putIfAbsent(ConcurrentHashMap.java:1541) ~[na:na]
    at java.base/java.lang.ClassLoader.getClassLoadingLock(ClassLoader.java:667) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:591) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579) ~[na:na]
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774) ~[jackson-databind-2.13.4.2.jar:2.13.4.2]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.13.4.2.jar:2.13.4.2]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.13.4.2.jar:2.13.4.2]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774) ~[jackson-databind-2.13.4.2.jar:2.13.4.2]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.13.4.2.jar:2.13.4.2]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.13.4.2.jar:2.13.4.2]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774) ~[jackson-databind-2.13.4.2.jar:2.13.4.2]

However, I still have the same problem! :) nothing has changed. the record to the database is successful, but it continues to give the same error when I want to retrieve the data

smhylc
  • 41
  • 1
  • 9

1 Answers1

1

Assuming that the Person is the parent entity and the Address is the child entity in this relation, you should annotate your fields as following:

@Entity
public class Person implements Serializable {

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "person")
    private Address Address;

}
@Entity
public class Address implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @JoinColumn(name = "id")
    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    private Person person; 

}

The exception most likely occurred because you set the mappedBy on the wrong side of the relationship, namely the child.

Note that with the @MapsId annotation, you don't need to generate a new ID for your address entity as the ID of the parent class is used. This is the recommended approach described by Hibernate maintainer Vlad Mihalcea.

Edit
In your comment you stated that the exception occurs when you try to access the address via a controller. The problem here is that you have a infinite loop in the serialization of your entity (or DTO?) due to address -> person -> address -> person -> ... Check this SO question for a detailed answer on how to fix it.

times29
  • 2,782
  • 2
  • 21
  • 40
  • First of all, thank you! However, this way the database started to give an error in the saving part! :) ```java org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [com.example.jpatrainingdemo.model.Address.person] at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:87) ~[hibernate-core-5.6.14.Final.jar:5.6.14.Final] at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:114) ~[hibernate-core-5.6.14.Final.jar:5.6.14.Final] at ``` – smhylc Jan 03 '23 at 10:19
  • @smhylc you need to set the `person` field in your `Address` entity before saving it to the database. The message says `attempted to assign id from null one-to-one property` which indicated that the `Address` you're trying to save has a `null` `OneToOne` person – times29 Jan 03 '23 at 10:21
  • I added "Person" in the "Address" constructor. and the registration was successful. However, when I want to pull the address number 1 from the database, "localhost:8080/get-adress?id=1" I'm getting the same error again, nothing has changed. ```java java.lang.StackOverflowError: null at java.base/java.lang.ClassLoader.defineClass1(Native Method) ~[na:na] at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016) ~[na:na] at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174) ~[na:na] ``` – smhylc Jan 03 '23 at 10:48
  • yes I debugged it and exactly as you said, it goes into an infinite loop in the form of "address -> person -> address -> person -> person -> ..." in an infinite way. I examined the link you gave as an example, they use JsonIgnore there. However, if I add JsonIgnore to the person variable in the address entity class, I cannot find a user in the address. Because JsonIgnore ignores that place and I cannot establish a relationship. I can see the associated address from the Person table. But I cannot see the staff from the address table. If I add JsonIgnore. I am not using DTO right now. – smhylc Jan 03 '23 at 11:35
  • Then try the apporach with JsonManagedReference and JsonBackReference – times29 Jan 03 '23 at 11:37
  • The same problem persists. I am not sending a Json data. I am not using DTO. When I added JsonIgnore, JsonManagedReference or JsonBackReference, the problem did not improve in any way. Because adding them disables my request. When I call address 1, I want to bring all users who use address 1. – smhylc Jan 03 '23 at 13:42