Search code examples
javarecursionstack-overflowrelationships

Stackoverflow exception (Recursion) for typical 1-to-n relationship


enter image description here

This is my Car class:

public class Car {
private int FGNr;
private String name;
private String type;
private Owner owner;

private static ArrayList<Integer> allCarIds = new ArrayList<>();

public Car(int FGNr, String name, String type, Owner o) throws Exception {
    setFGNr(FGNr);
    setName(name);
    setType(type);
    setOwner(o);
}



public int getFGNr() {
    return FGNr;
}


public void setFGNr(int FGNr) throws Exception{
    this.FGNr = FGNr;
    if(allCarIds.contains(this.FGNr))
        throw new Exception("FGNr already excists!! ");
     allCarIds.add(this.FGNr);}

public String getName() {
    return name;
}

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

public String getType() {
    return type;
}

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

public Owner getOwner() {
    return owner;
}

public void setOwner(Owner owner) throws Exception{ 
    owner.addCar(this);
    this.owner = owner;
}

@Override
public int hashCode() {
    int hash = 7;
    hash = 73 * hash + this.FGNr;
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final Car other = (Car) obj;
    if (this.FGNr != other.FGNr) {
        return false;
    }
    return true;
}



@Override
public String toString() {
    return "Car{" + "FGNr=" + FGNr + ", name=" + name + ", type=" + type + ", owner=" + owner + '}';
  }   
}

And this is my Owner class:

public class Owner {
private String SVNr;
private String name;
HashSet<Car> allCars = new HashSet<>();
private static ArrayList<String> allOwnerSVNs = new ArrayList<>();

public Owner(String SVNr, String name) throws Exception{
    setSVNr(SVNr);
    setName(name);
}

public void addCar(Car c) throws Exception{
    if(allCars.contains(c))
        throw new Exception("this user has already this car");
    if(c.getOwner()!=null)
        throw new Exception("this car belongs to other owner");

    c.setOwner(this);
    allCars.add(c);
}

public String getSVNr() {
    return SVNr;
}

public void setSVNr(String SVNr) throws Exception{
    this.SVNr = SVNr;
     if(allOwnerSVNs.contains(this.SVNr))
        throw new Exception("SVNg already excists!! ");
     allOwnerSVNs.add(this.SVNr);
}

public String getName() {
    return name;
}

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

public HashSet<Car> getAllCars() {
    return allCars;
}

@Override
public int hashCode() {
    int hash = 5;
    hash = 41 * hash + Objects.hashCode(this.SVNr);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final Owner other = (Owner) obj;
    if (!Objects.equals(this.SVNr, other.SVNr)) {
        return false;
    }
    return true;
}

@Override
public String toString() {
    return "Owner{" + "SVNr=" + SVNr + ", name=" + name + ", allCars=" + allCars + '}';
    }    
}

And this is my main:

 try {
        Owner o1 = new Owner("0001","Owner1");
        Owner o2 = new Owner("0002","Owner2");

        Car c1 = new Car(1,"Model S", "Tesla",o1);
        Car c2 = new Car(2,"Model 3", "Tesla",o2);
        Car c3 = new Car(3,"TT", "Audi",o2);


    } catch (Exception ex) {
        System.out.println("error:"+ex.getMessage());

    }

So when trying to create a new Car I get this error:

Exception in thread "main" java.lang.StackOverflowError
at java.util.HashMap.containsKey(HashMap.java:595)
at java.util.HashSet.contains(HashSet.java:203)
at pkgData.Owner.addCar(Owner.java:28)
at pkgData.Car.setOwner(Car.java:63)

...........

It is a recursion error, but I don't know how to fix it. If I create a new car obviously I have to add the Car to the owner arrayList of cars. and if I call the addCar function the function calls the getOwner function. It's an endless circle of calling.

How I can make sure that when creating a new car that the collection of the owner will also be changed. It would not make any sense that a car has an owner but the owner of the car does not the car in his collection.


Solution

  • These two functions fall an infinite loop as you see.

    In Car class

    public void setOwner(Owner owner) throws Exception{ 
        owner.addCar(this);
        this.owner = owner;
    }
    

    And in Owner Class

    public void addCar(Car c) throws Exception{
        if(allCars.contains(c))
            throw new Exception("this user has already this car");
        if(c.getOwner()!=this && c.getOwner()!=null)
            throw new Exception("this car belongs to other owner");
    
        c.setOwner(this);
        allCars.add(c);
    }
    

    The car sets its owner and sends itself to the Owner class' addCar() method, thats OK. However, why the Owner class' addCar() method sets the owner as itself again ?

    I think there is a logical mistake. If you remove c.setOwner(this) line, it works fine.