package moe.tristan.easyfxml;

import static org.assertj.core.api.Assertions.assertThat;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Set;

import org.junit.Test;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import moe.tristan.easyfxml.api.FxmlController;

/**
 * Asserts the presence of a private constructor on all classes without non-static fields. Partly because I'm getting
 * lowered coverage for this as well...
 */
public class UtilityClassesStyleTest {

    private static final Logger LOG = LoggerFactory.getLogger(UtilityClassesStyleTest.class);

    private static final Reflections reflections = new Reflections(
        "moe.tristan.easyfxml",
        new SubTypesScanner(false)
    );

    @Test
    public void assertExistsPrivateCtor() {
        final StringBuilder errorBuilder = new StringBuilder();
        try {
            reflections.getSubTypesOf(Object.class).stream()
                       .filter(UtilityClassesStyleTest::isNotTestClass)
                       .filter(UtilityClassesStyleTest::isNotSpringBean)
                       .filter(clazz -> !clazz.isInterface())
                       .filter(clazz ->
                                   Arrays.stream(clazz.getDeclaredFields())
                                         .allMatch(field -> Modifier.isStatic(field.getModifiers())))
                       .forEach(clazz -> {
                           errorBuilder.append("Expecting class ").append(clazz.getName()).append("to :").append('\n');
                           errorBuilder.append("\t-> be final ").append('\n');
                           assertThat(clazz).isFinal();
                           errorBuilder.append("\t-> have exactly one constructor ").append('\n');
                           Constructor<?>[] constructors = clazz.getDeclaredConstructors();
                           assertThat(constructors).hasSize(1);
                           errorBuilder.append("\t-> and that this constructor is private ").append('\n');
                           assertThat(Modifier.isPrivate(constructors[0].getModifiers())).isTrue();
                       });
        } catch (Throwable t) {
            LOG.error(errorBuilder.toString());
            throw t;
        }
    }

    private static boolean isNotTestClass(final Class<?> clazz) {
        if (clazz.getName().endsWith("Test")) {
            return false;
        }
        return !clazz.getName().split("\\$")[0].endsWith("Test");
    }

    private static boolean isNotSpringBean(final Class<?> clazz) {
        final Set<Class<?>> filteredBeanTypes = Set.of(FxApplication.class, FxUiManager.class, FxmlController.class);
        for (Class<?> filteredBeanType : filteredBeanTypes) {
            if (filteredBeanType.isAssignableFrom(clazz)) {
                return false;
            }
        }

        final Annotation[] annotations = clazz.getDeclaredAnnotations();
        return Arrays.stream(annotations)
                     .map(Annotation::toString)
                     .noneMatch(name -> name.contains("org.springframework"));
    }

}

@@ -238,19 +238,23 @@
 va.util.
-Set
+Objects
 ;%0A%0Aimpor
@@ -417,55 +417,127 @@
 ry;%0A
-%0A
 import 
-moe.tristan.easyfxml.api.FxmlController
+org.springframework.context.annotation.ComponentScan;%0Aimport org.springframework.core.annotation.AnnotationUtils
 ;%0A%0A/
@@ -2810,110 +2810,250 @@
 nal 
-Set%3CClass%3C?%3E%3E filteredBeanTypes = Set.of(FxApplication.class, FxUiManager.class, FxmlController.class)
+ComponentScan componentScanConfig = AnnotationUtils.findAnnotation(EasyFxmlAutoConfiguration.class, ComponentScan.class);%0A        final ComponentScan.Filter componentScanFilter = Objects.requireNonNull(componentScanConfig).includeFilters()%5B0%5D
 ;%0A  
@@ -3095,25 +3095,37 @@
 e : 
-filteredBeanTypes
+componentScanFilter.classes()
 ) %7B%0A

Use EasyFXML autoconfiguration ComponentScan annotation to filter out Spring classes on utility classes check