// Path: dalesbred/src/main/java/org/dalesbred/internal/utils/Throwables.java
// public final class Throwables {
// 
//     private Throwables() { }
// 
//     public static @NotNull RuntimeException propagate(@NotNull Throwable e) {
//         if (e instanceof Error)
//             throw (Error) e;
//         else if (e instanceof RuntimeException)
//             return (RuntimeException) e;
//         else
//             return new WrappedCheckedException(e);
//     }
// 
//     public static @NotNull <T extends Exception> T propagate(@NotNull Throwable e, @NotNull Class<T> allowed) {
//         if (allowed.isInstance(e))
//             return allowed.cast(e);
//         else
//             throw propagate(e);
//     }
// }
// 
// Path: dalesbred/src/main/java/org/dalesbred/internal/utils/StringUtils.java
// public static boolean isEqualIgnoringCaseAndUnderscores(@NotNull String s1, @NotNull String s2) {
//     int index1 = 0;
//     int index2 = 0;
//     int length1 = s1.length();
//     int length2 = s2.length();
// 
//     while (index1 < length1 && index2 < length2) {
//         char nameChar = s1.charAt(index1++);
//         if (nameChar == '_') continue;
// 
//         char memberNameChar = s2.charAt(index2++);
//         if (memberNameChar == '_') {
//             index1--;
//             continue;
//         }
// 
//         if (toLowerCase(nameChar) != toLowerCase(memberNameChar))
//             return false;
//     }
// 
//     // Skip trailing underscores
//     while (index1 < length1 && s1.charAt(index1) == '_') index1++;
//     while (index2 < length2 && s2.charAt(index2) == '_') index2++;
// 
//     return index1 == length1 && index2 == length2;
// }


import java.lang.reflect.Type;
import java.util.Optional;
import java.util.regex.Pattern;
import static java.lang.reflect.Modifier.isPublic;
import static org.dalesbred.internal.utils.StringUtils.isEqualIgnoringCaseAndUnderscores;
import org.dalesbred.annotation.DalesbredIgnore;
import org.dalesbred.internal.utils.Throwables;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
                currentClass = field.getType();
            } else {
                Method getter = findGetter(currentClass, segments[i]).orElse(null);
                if (getter != null) {
                    readers[i] = getter::invoke;
                    currentClass = getter.getReturnType();
                } else {
                    return Optional.empty();
                }
            }
        }

        Optional<PropertyAccessor> accessor = findFinalAccessor(currentClass, segments[segments.length - 1]);
        return accessor.map(a -> new NestedPathAccessor(readers, path, a));
    }

    private static @NotNull Optional<PropertyAccessor> findFinalAccessor(@NotNull Class<?> currentClass, @NotNull String name) {
        Optional<PropertyAccessor> setter = findSetter(currentClass, name).map(SetterPropertyAccessor::new);

        if (setter.isPresent()) {
            return setter;
        } else {
            return findField(currentClass, name).map(FieldPropertyAccessor::new);
        }
    }

    private static @NotNull Optional<Field> findField(@NotNull Class<?> cl, @NotNull String name) {
        Field result = null;

        for (Field field : cl.getFields())
// Path: dalesbred/src/main/java/org/dalesbred/internal/utils/Throwables.java
// public final class Throwables {
// 
//     private Throwables() { }
// 
//     public static @NotNull RuntimeException propagate(@NotNull Throwable e) {
//         if (e instanceof Error)
//             throw (Error) e;
//         else if (e instanceof RuntimeException)
//             return (RuntimeException) e;
//         else
//             return new WrappedCheckedException(e);
//     }
// 
//     public static @NotNull <T extends Exception> T propagate(@NotNull Throwable e, @NotNull Class<T> allowed) {
//         if (allowed.isInstance(e))
//             return allowed.cast(e);
//         else
//             throw propagate(e);
//     }
// }
// 
// Path: dalesbred/src/main/java/org/dalesbred/internal/utils/StringUtils.java
// public static boolean isEqualIgnoringCaseAndUnderscores(@NotNull String s1, @NotNull String s2) {
//     int index1 = 0;
//     int index2 = 0;
//     int length1 = s1.length();
//     int length2 = s2.length();
// 
//     while (index1 < length1 && index2 < length2) {
//         char nameChar = s1.charAt(index1++);
//         if (nameChar == '_') continue;
// 
//         char memberNameChar = s2.charAt(index2++);
//         if (memberNameChar == '_') {
//             index1--;
//             continue;
//         }
// 
//         if (toLowerCase(nameChar) != toLowerCase(memberNameChar))
//             return false;
//     }
// 
//     // Skip trailing underscores
//     while (index1 < length1 && s1.charAt(index1) == '_') index1++;
//     while (index2 < length2 && s2.charAt(index2) == '_') index2++;
// 
//     return index1 == length1 && index2 == length2;
// }


// Path: dalesbred/src/main/java/org/dalesbred/internal/instantiation/PropertyAccessor.java
import java.lang.reflect.Type;
import java.util.Optional;
import java.util.regex.Pattern;
import static java.lang.reflect.Modifier.isPublic;
import static org.dalesbred.internal.utils.StringUtils.isEqualIgnoringCaseAndUnderscores;
import org.dalesbred.annotation.DalesbredIgnore;
import org.dalesbred.internal.utils.Throwables;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

                currentClass = field.getType();
            } else {
                Method getter = findGetter(currentClass, segments[i]).orElse(null);
                if (getter != null) {
                    readers[i] = getter::invoke;
                    currentClass = getter.getReturnType();
                } else {
                    return Optional.empty();
                }
            }
        }

        Optional<PropertyAccessor> accessor = findFinalAccessor(currentClass, segments[segments.length - 1]);
        return accessor.map(a -> new NestedPathAccessor(readers, path, a));
    }

    private static @NotNull Optional<PropertyAccessor> findFinalAccessor(@NotNull Class<?> currentClass, @NotNull String name) {
        Optional<PropertyAccessor> setter = findSetter(currentClass, name).map(SetterPropertyAccessor::new);

        if (setter.isPresent()) {
            return setter;
        } else {
            return findField(currentClass, name).map(FieldPropertyAccessor::new);
        }
    }

    private static @NotNull Optional<Field> findField(@NotNull Class<?> cl, @NotNull String name) {
        Field result = null;

        for (Field field : cl.getFields())
            if (isPublic(field.getModifiers()) && isEqualIgnoringCaseAndUnderscores(name, field.getName()) && !field.isAnnotationPresent(DalesbredIgnore.class)) {