InjectValidator { public void validate() { while (true) { var instance = queue.poll(); if (instance == null) return; visitedObjects.add(instance); Field[] fields = instance.getClass().getDeclaredFields(); for (Field field : fields) { int modifiers = field.getModifiers(); if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) continue; Object value = fieldValue(field, instance); if (field.isAnnotationPresent(Inject.class)) { if (value == null) throw new Error(Strings.format("field with @Inject is not bound to any value, rootClass={}, field={}", rootClass.getCanonicalName(), Fields.path(field))); } else if (value != null && shouldInspect(value)) { queue.add(value); } } } } InjectValidator(Object instance); void validate();  }
@Test void validate() { var bean = new TestBeanWithNotInjectedField(); var validator = new InjectValidator(bean); assertThatThrownBy(validator::validate) .isInstanceOf(Error.class) .hasMessageContaining("field with @Inject is not bound to any value") .hasMessageContaining(".dependency2"); }
@Test void validateWithCircularReference() { var bean = new TestBeanWithCircularReference(); assertThat(bean.selfDependency).isSameAs(bean.selfDependency.dependency); assertThat(bean.dependency1).isSameAs(bean.dependency1.dependency.dependency); assertThat(bean.testEnum).isNotNull(); var validator = new InjectValidator(bean); validator.validate(); }