Skip to content
Advertisement

Does the following Java code really contain cyclic dependency?

At a recent discussion within our team I had written the following code which was later flagged as having the cyclic dependency although to my knowledge and experience it is not. I need some fresh eyes to take a look at it so that I can learn more.

disclaimer: The production code was converted into the corresponding dummy code to avoid copyright issues. Main method (ofcourse) did not exist in the prod code.

Beany.java

public class Beany {

    private String x;

    public static void main(String[] args) {
        // main exists for testing purposes here. Depicts the functionality of validation function.
        List<BeanyValidator> validatorList = List.of(isConfigDataNull(),
                                                     isValueOfXEmpty());
        Beany beany = new Beany();
        beany.setX("");
        System.out.println(collectErrorsFrom(beany, validatorList));
    }

    public void setX(String x) { // setters in our code does not exist. This is merely for demo purposes here.
        this.x = x;
    }

    public String getX() {
        return x;
    }
}

BeanyValidator.java:

public interface BeanyValidator extends Function<Beany, String> {

    static BeanyValidator isConfigDataNull() {
        return beany -> Objects.isNull(beany)
                               ? "Object is null!"
                               : "NO_ERROR";
    }

    static BeanyValidator isValueOfXEmpty() {
        return beany -> beany.getX().isEmpty()
                               ? "Value is empty!"
                               : "NO_ERROR";
    }

    static List<String> collectErrorsFrom(Beany beany, List<BeanyValidator> validators) {
        return validators.stream()
                         .map(validator -> validator.apply(beany))
                         .filter(err -> !"NO_ERROR".equals(err))
                         .collect(Collectors.toList());
    }
}

What was pointed out as circular dependency was the fact Beany was being used as Function<T,U> — making beany dependency of BeanyValidator — and using validators inside the main method (which in prod is some sort of validation function) makes the validator a dependency of Beany and thereby causing circular dependency. I do not agree with my respectful peer but I always come into a discussion thinking I could be wrong.

By the way, I applied combinator pattern using Java8 Functions. Could someone please some shed some light on this?

Thanks in advance!

Kind regards.

Advertisement

Answer

Yes, there is a cyclic dependency:

  • Class Beany has a List<BeanyValidator>
  • Interface BeanyValidator extends Function<Beany, String>

This can be verified by putting the classes in different packages and then look at the import statements required for the code to compile. You will find that one class imports the other and vice versa.

One suggestion to break the circular dependency is to refactor the main() method from the Beany class to a separate class, e.g.

public class Main {
    public static void main(String[] args) {
        List<BeanyValidator> validatorList = List.of(isConfigDataNull(),
                                                     isValueOfXEmpty());
        Beany beany = new Beany();
        beany.setX("");
        System.out.println(collectErrorsFrom(beany, validatorList));
    }
}
Advertisement