Contents

Hi! In this article, I’d like to tell you about Enum Circular Dependency Problem in Java.

The problem, I stumbled upon in project, is not so common so I decided to write about it. In the following examples I used Java 11.

Usually we use Enums in Java when we want to create some values that don’t change (so should be immutable) and should be available across our whole application. These values are instances of normal class so they can also have some state. Sometimes it’s reasonable to create Enums that consist of other Enums like in the below example:

enum Driver {
    ADAM, JOE, MARTIN
}
enum Car {
    AUDI(Driver.JOE), BMW(Driver.MARTIN), MERCEDES(Driver.ADAM);
    private final Driver driver;
    Car(Driver driver) {
        this.driver = driver;
    }
    Driver getDriver() {
        return driver;
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println(Car.AUDI.getDriver());
    }
}

When we run this example we will see this:

JOE

Certainly the result is not a surprise. But let’s move on. If any chosen car can return information about his driver why wouldn’t we want to have car in the Driver Enum? To do that let’s replace the old Driver with new one:

enum Driver {
    ADAM(Car.MERCEDES), JOE(Car.AUDI), MARTIN(Car.BMW);
    private final Car car;
    Driver(Car car) {
        this.car = car;
    }
    Car getCar() {
        return car;
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println(Driver.JOE.getCar());
    }
}

Which results in this:

AUDI

Again nothing special happens. That’s what we would expect to be displayed.

Ok, so now let’s try to mix these two examples and create chain of calls:

public class Main {
    public static void main(String[] args) {
        System.out.println(Car.AUDI.getDriver().getCar());
    }
}

If we run above code the result is:

null

We encountered Enum Circular Dependency In Java. Driver has Car and Car has Driver. The problem is that to create Car we need a Driver and on the other site to create Driver we need a Car. This Circular Dependency causes in this case Car to have a Driver but Driver not to have a Car:

public class Main {
    public static void main(String[] args) {
        System.out.println(Car.AUDI.getDriver().getCar());
        System.out.println(Car.AUDI.getDriver());
        System.out.println(Car.BMW.getDriver());
        System.out.println(Car.MERCEDES.getDriver());
        System.out.println(Driver.JOE.getCar());
        System.out.println(Driver.ADAM.getCar());
        System.out.println(Driver.MARTIN.getCar());
    }
}

Result:

null
JOE
MARTIN
ADAM
null
null
null

As we can see Enum Circular Dependency In Java created in above code results in null values in Drivers’ car fields.

This Enum Circular Dependency works in the following way:

  1. Car.AUDI.getDriver().getCar() call triggers Car Enum class to be loaded.
  2. When Java ClassLoader tries to load Car Enum, it sees that Driver Enum is used and then tries to load Driver.
  3. While Driver initialization the Car is used too so it also should be initialized, however Car initialization is being proccesed and that’s why Driver’s constructor’s argument is null. Unfortunately it will never be changed.
  4. When Driver is loaded, Car’s constructor’s argument will be non null Driver value.

If we reverse the order of calls in the following way:

public class Main {
    public static void main(String[] args) {
        System.out.println(Driver.JOE.getCar().getDriver());
        System.out.println(Car.AUDI.getDriver());
        System.out.println(Car.BMW.getDriver());
        System.out.println(Car.MERCEDES.getDriver());
        System.out.println(Driver.JOE.getCar());
        System.out.println(Driver.ADAM.getCar());
        System.out.println(Driver.MARTIN.getCar());
    }
}

The result will be reversed (Driver will be loaded as the first one) according to the preceding explanation:

null
null
null
null
AUDI
MERCEDES
BMW

To solve Enum Circular Dependency problem we should use static initializer in all Enums to assign fields in the following way:

enum Driver {
    ADAM, JOE, MARTIN;
    private Car car;
    static {
        ADAM.car = Car.MERCEDES;
        JOE.car = Car.AUDI;
        MARTIN.car = Car.BMW;
    }
    Car getCar() {
        return car;
    }
}
enum Car {
    AUDI, BMW, MERCEDES;
    private Driver driver;
    static {
        AUDI.driver = Driver.JOE;
        BMW.driver = Driver.MARTIN;
        MERCEDES.driver = Driver.ADAM;
    }
    Driver getDriver() {
        return driver;
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println(Driver.JOE.getCar().getDriver());
        System.out.println(Car.AUDI.getDriver());
        System.out.println(Car.BMW.getDriver());
        System.out.println(Car.MERCEDES.getDriver());
        System.out.println(Driver.JOE.getCar());
        System.out.println(Driver.ADAM.getCar());
        System.out.println(Driver.MARTIN.getCar());
    }
}

What results in output we expect:

JOE
JOE
MARTIN
ADAM
AUDI
MERCEDES
BMW

The code in static initializers is run after the enum instances are created. Thanks to that we’re able to assign fields with already initialized other enum instances. Of course it’s related with not final fields what is the cost of having the Enum Circular Dependency problem solved.

In this post, we understood what is Enum Circular Dependency In Java, how to create it, how it works under the hood and how to solve it. I hope you like it.