// Path: src/main/java/com/michaelfotiadis/validator/annotated/SupportedAnnotationContainer.java
// public final class SupportedAnnotationContainer {
// 
//     private static final String PACKAGE_NAME = "com.michaelfotiadis.validator.annotated.annotations";
//     private static final List<Class> SUPPORTED_CLASSES = new ArrayList<>();
// 
//     private SupportedAnnotationContainer() {
//         // NOOP
//     }
// 
//     /*package*/
//     static boolean isSupported(final Class<?> type) {
//         return getSupportedClasses().contains(type);
//     }
// 
//     public static List<Class> getSupportedClasses() {
//         if (SUPPORTED_CLASSES.isEmpty()) {
//             final Class[] supportedArray;
//             try {
//                 supportedArray = ReflectionUtils.getClasses(PACKAGE_NAME);
//                 SUPPORTED_CLASSES.addAll(Arrays.asList(supportedArray));
//             } catch (ClassNotFoundException | IOException e) {
//                 e.printStackTrace();
//             }
//         }
//         return SUPPORTED_CLASSES;
//     }
// 
// 
// }
// 
// Path: src/main/java/com/michaelfotiadis/validator/annotated/processor/SearchPolicy.java
// public enum SearchPolicy {
//     SHALLOW,
//     DEEP
// }


import com.michaelfotiadis.validator.annotated.SupportedAnnotationContainer;
import com.michaelfotiadis.validator.annotated.processor.SearchPolicy;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
    public static List<Field> getAnnotatedFields(final Object root,
                                                 final SearchPolicy searchPolicy) throws ReflectiveOperationException {
        return getAnnotatedFields(root, searchPolicy, new HashSet<>());
    }

    private static List<Field> getAnnotatedFields(final Object root,
                                                  final SearchPolicy searchPolicy,
                                                  final Set<Object> inspected) throws ReflectiveOperationException {



        final List<Field> annotatedValues = new ArrayList<>();
        if (inspected.contains(root)) { // Prevents stack overflow.
            System.out.println("*** Breaking for already inspected");
            return Collections.emptyList();
        }
        if (isWrapperType(root.getClass())) { // Prevents stack overflow.

            System.out.println("*** Breaking for wrapper class");
            return Collections.emptyList();
        }

        for (final Field field : gatherFields(root.getClass())) {

            field.setAccessible(true);
            final Object currentValue = field.get(root);
            field.setAccessible(false);
            if (field.getAnnotations().length != 0) {
                // Found required value, search finished:
                for (final Annotation annotation : field.getAnnotations()) {
// Path: src/main/java/com/michaelfotiadis/validator/annotated/SupportedAnnotationContainer.java
// public final class SupportedAnnotationContainer {
// 
//     private static final String PACKAGE_NAME = "com.michaelfotiadis.validator.annotated.annotations";
//     private static final List<Class> SUPPORTED_CLASSES = new ArrayList<>();
// 
//     private SupportedAnnotationContainer() {
//         // NOOP
//     }
// 
//     /*package*/
//     static boolean isSupported(final Class<?> type) {
//         return getSupportedClasses().contains(type);
//     }
// 
//     public static List<Class> getSupportedClasses() {
//         if (SUPPORTED_CLASSES.isEmpty()) {
//             final Class[] supportedArray;
//             try {
//                 supportedArray = ReflectionUtils.getClasses(PACKAGE_NAME);
//                 SUPPORTED_CLASSES.addAll(Arrays.asList(supportedArray));
//             } catch (ClassNotFoundException | IOException e) {
//                 e.printStackTrace();
//             }
//         }
//         return SUPPORTED_CLASSES;
//     }
// 
// 
// }
// 
// Path: src/main/java/com/michaelfotiadis/validator/annotated/processor/SearchPolicy.java
// public enum SearchPolicy {
//     SHALLOW,
//     DEEP
// }


// Path: src/main/java/com/michaelfotiadis/validator/annotated/parser/FieldParser.java
import com.michaelfotiadis.validator.annotated.SupportedAnnotationContainer;
import com.michaelfotiadis.validator.annotated.processor.SearchPolicy;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

    public static List<Field> getAnnotatedFields(final Object root,
                                                 final SearchPolicy searchPolicy) throws ReflectiveOperationException {
        return getAnnotatedFields(root, searchPolicy, new HashSet<>());
    }

    private static List<Field> getAnnotatedFields(final Object root,
                                                  final SearchPolicy searchPolicy,
                                                  final Set<Object> inspected) throws ReflectiveOperationException {



        final List<Field> annotatedValues = new ArrayList<>();
        if (inspected.contains(root)) { // Prevents stack overflow.
            System.out.println("*** Breaking for already inspected");
            return Collections.emptyList();
        }
        if (isWrapperType(root.getClass())) { // Prevents stack overflow.

            System.out.println("*** Breaking for wrapper class");
            return Collections.emptyList();
        }

        for (final Field field : gatherFields(root.getClass())) {

            field.setAccessible(true);
            final Object currentValue = field.get(root);
            field.setAccessible(false);
            if (field.getAnnotations().length != 0) {
                // Found required value, search finished:
                for (final Annotation annotation : field.getAnnotations()) {
                    if (SupportedAnnotationContainer.getSupportedClasses().contains(annotation.annotationType())) {