Search code examples
mysqljsonspringhibernateentity

CrudRepository: findAll() stucks in infinite loop


I have a OneToMany data model with two entities. One machine contains many characteristics.

Problem: When I try to get the complete data of the data base the program stucks in an infinite loop. See the JSON result - the data is repeated all the time...

[{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":[{"name":null,"description":"CHARACTER2","type":0,"value":0,"machine":{"name":"Neue Machine","description":"Description der neuen machine","characteristics":

and so on...

I really do not know why that happens. Inserting data programatically seems to work fine! The current data is produced by the following lines of code:

@RequestMapping(value = "/machine", method = RequestMethod.GET)
    Collection<Machine> readMachines(){

        Machine machine = new Machine("Neue Machine", "Description der neuen machine");
        //Set<Characteristic> newCharacter =  new HashSet<Characteristic>(); 
        for(int i = 0; i < 6; i++){
            machine.addCharacteristic(new Characteristic("CHARACTER" + Integer.toString(i),0,0));
        }

        machineRepository.save(machine);

        return (Collection<Machine>) machineRepository.findAll();
    }

Question: Where does the infinite loop coming from?

The database model

machine:

enter image description here

create statement:

CREATE TABLE `machine` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `description` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8

entity:

@Entity
@Table(name = "characteristic")
public class Characteristic {
    private int characteristic_id; 

    private String name; 

    private String description; 

    private int type; 

    private int value;

    private Machine machine; 

    @ManyToOne
    @JoinColumn(name="machine_id")
    public Machine getMachine(){
        return machine;
    }

    public void setMachine(Machine machine){
        this.machine = machine;
    }

    public Characteristic() {}

    public Characteristic(String description, int type, int value) {
        this.description = description;
        this.type = type;
        this.value = value;
    } 

    public Characteristic(int characteristic_id, String description, int type, int value) {
        this.characteristic_id = characteristic_id;
        this.description = description;
        this.type = type;
        this.value = value;
    } 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="characteristic_id")
    public int getCharacteristic_Id() {
        return characteristic_id;
    }

    public void setCharacteristic_Id(int characteristic_id) {
        this.characteristic_id = characteristic_id;
    }

    @Column(name="name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(name="description")
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Column(name="type")
    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    @Column(name="value")
    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

characteristic:

enter image description here

create statement:

CREATE TABLE `characteristic` (
  `characteristic_id` int(11) NOT NULL AUTO_INCREMENT,
  `machine_id` int(11) NOT NULL DEFAULT '0',
  `name` varchar(45) DEFAULT NULL,
  `description` varchar(45) DEFAULT NULL,
  `type` int(11) NOT NULL,
  `value` int(11) DEFAULT NULL,
  PRIMARY KEY (`characteristic_id`),
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=latin1

entity:

@Entity
@Table(name = "machine")
public class Machine {
    private int machine_id; 

    private String name;

    private String description; 

    private Set<Characteristic> characteristics;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "machine", cascade = CascadeType.ALL)
    public Set<Characteristic> getCharacteristics() {
        return characteristics; 
    }

    public void setCharacteristics(Set<Characteristic> characteristics){
        this.characteristics = characteristics;
    }

    public Machine(){}

    public Machine(String name, String description){
        this.name = name;
        this.description = description; 
    }

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="id")
    public int getId() {
        return machine_id;
    }

    public void setId(int machine_id) {
        this.machine_id = machine_id;
    }

    @Column(name="name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(name="description")
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void addCharacteristic(Characteristic characteristic){
        if(this.characteristics == null){
            this.characteristics = new HashSet<Characteristic>();
        }
        characteristic.setMachine(this);
        this.characteristics.add(characteristic);
    }
}

CrudRepository:

public interface MachineRepository extends CrudRepository<Machine, Integer>{}

Solution

  • In your code you return a collection of Machine. This class has One-To-Many dependency to Characteristic. The Characteristic class has Many-To-One dependency om Machine.

    When Machine object is serialized it's looking on dependency Characteristic the last is looking back on Machyne, and so on. These cycle dependencies impossible to serialize until you exclude properties that reference to the same object. You should exclude either One-To-Many or Many-To-One properties.