package org.jboss.seam; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.jboss.seam.core.BijectionInterceptor; /** * An exception that is thrown when {@link BijectionInterceptor} detects that a * component's dependencies cannot be injected due to a cyclic dependency. As * the exception is passed up the stack, the call sequence is recorded so that a * useful exception message can be constructed. * * @author Matt Drees * */ public class CyclicDependencyException extends IllegalStateException { /** * stores the invocations in reverse call order */ private final List<String> invocations = new ArrayList<String>(); private String tailComponentName; private boolean cycleComplete; /** * Records this invocation's component name and method to be displayed in * {@link #getMessage()}, unless this invocation is not part of the detected * cycle. This method will be successively called as the exception is * propagated up the stack. * * @param componentName * @param method */ public void addInvocation(String componentName, Method method) { if (cycleComplete) { return; } if (invocations.isEmpty()) { tailComponentName = componentName; } else { if (tailComponentName.equals(componentName)) { cycleComplete = true; } } invocations.add(createInvocationLabel(componentName, method)); } /** * returns e.g. "foo.doSomething()" */ private String createInvocationLabel(String componentName, Method method) { String invocationLabel = componentName + "." + method.getName() + "("; int i = 1; for (Class<?> parameterType : method.getParameterTypes()) { invocationLabel += parameterType.getSimpleName(); if (i < method.getParameterTypes().length) { invocationLabel += ", "; } i++; } invocationLabel += ")"; return invocationLabel; } @Override public String getMessage() { if (!cycleComplete) { return "Cyclic dependency found"; } else { String message = "Injection into " + tailComponentName + " resulted in a dependency cycle, requiring the invocation of " + invocations.get(0) + ". The complete cycle: "; for (int i = invocations.size() - 1; i >= 0; i--) { message += invocations.get(i); if (i != 0) message += " -> "; } return message; } } }