package org.jdbi.v3.core.argument;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import org.jdbi.v3.core.statement.StatementContext;
import org.jdbi.v3.core.statement.UnableToCreateStatementException;
abstract class ObjectPropertyNamedArgumentFinder implements NamedArgumentFinder {
final String prefix;
final Object object;
private final Map<String, Optional<NamedArgumentFinder>> childArgumentFinders = new ConcurrentHashMap<>();
ObjectPropertyNamedArgumentFinder(String prefix, Object object) {
this.prefix = (prefix == null || prefix.isEmpty()) ? "" : prefix + ".";
this.object = object;
}
@Override
public final Optional<Argument> find(String name, StatementContext ctx) {
if (name.startsWith(prefix)) {
final String actualName = name.substring(prefix.length());
int separator = actualName.indexOf('.');
if (separator != -1) {
String parentName = actualName.substring(0, separator);
String childName = actualName.substring(separator + 1);
return childArgumentFinders
.computeIfAbsent(parentName, pn ->
getValue(pn, ctx).map(v -> getNestedArgumentFinder(v.value)))
.flatMap(arg -> arg.find(childName, ctx));
}
return getValue(actualName, ctx)
.map(tv -> ctx.findArgumentFor(tv.type, tv.value)
.orElseThrow(() -> new UnableToCreateStatementException(
String.format("No argument factory registered for type [%s] for element [%s] on [%s]",
tv.type,
name,
object),
ctx)));
}
return Optional.empty();
}
abstract Optional<TypedValue> getValue(String name, StatementContext ctx);
abstract NamedArgumentFinder getNestedArgumentFinder(Object obj);
static class TypedValue {
public final Type type;
public final Object value;
TypedValue(Type type, Object value) {
this.type = type;
this.value = value;
}
}
}