private static <E extends Enum<E>> E getValueByName(Class<E> enumClass, String name, StatementContext ctx) { return JdbiOptionals.findFirstPresent( () -> Arrays.stream(enumClass.getEnumConstants()).filter(e -> e.name().equals(name)).findFirst(), () -> Arrays.stream(enumClass.getEnumConstants()).filter(e -> e.name().equalsIgnoreCase(name)).findFirst() ) .orElseThrow(() -> new UnableToProduceResultException( String.format("no %s value could be matched to the name %s", enumClass.getSimpleName(), name), ctx)); } }
@SafeVarargs public static <T> Optional<T> findFirstPresent(Supplier<Optional<T>>... suppliers) { return Stream.of(suppliers) .flatMap(supplier -> stream(supplier.get())) .findFirst(); }
return JdbiOptionals.findFirstPresent( () -> Optional.ofNullable(method.getAnnotation(SqlBatch.class)) .map(SqlBatch::value)
@Override public Optional<Argument> build(Type expectedType, Object value, ConfigRegistry config) { return FACTORIES.stream() .flatMap(factory -> JdbiOptionals.stream(factory.build(expectedType, value, config))) .findFirst(); }
/** * Register bean arguments and row mapping for an {@code Immutable*} value class, expecting the default generated class and builder names. * @param spec the specification interface or abstract class * @param <S> the specification class * @return a plugin that configures type mapping for the given class */ public <S> JdbiImmutables registerImmutable(Class<S> spec) { final Class<? extends S> impl = classByPrefix("Immutable", spec); return registerImmutable(spec, impl, JdbiOptionals.findFirstPresent( () -> nullaryMethodOf(spec, "builder"), () -> nullaryMethodOf(impl, "builder")) .orElseThrow(() -> new IllegalArgumentException("Neither " + spec + " nor " + impl + " have a 'builder' method"))); }
@Override public Optional<ColumnMapper<?>> build(Type type, ConfigRegistry config) { return FACTORIES.stream() .flatMap(factory -> JdbiOptionals.stream(factory.build(type, config))) .findFirst(); } }
@Override public Optional<Argument> build(Type type, Object value, ConfigRegistry config) { if (String.class.equals(type)) { return Optional.empty(); } String json = value == null ? null : config.get(JsonConfig.class).getJsonMapper().toJson(type, value, config); Arguments a = config.get(Arguments.class); // look for specialized json support first, revert to simple String binding if absent return Optional.of(JdbiOptionals.findFirstPresent( () -> a.findFor(QualifiedType.of(String.class).with(Json.class), json), () -> a.findFor(String.class, json)) .orElseThrow(() -> new UnableToCreateStatementException(JSON_NOT_STORABLE))); } }
/** * Obtain an {@link SqlArrayType} for the given array element type in the given context * * @param elementType the array element type. * @return an {@link SqlArrayType} for the given element type. */ public Optional<SqlArrayType<?>> findFor(Type elementType) { return factories.stream() .flatMap(factory -> JdbiOptionals.stream(factory.build(elementType, registry))) .findFirst(); }
@Override public Optional<ColumnMapper<?>> build(Type type, ConfigRegistry config) { if (String.class.equals(type)) { return Optional.empty(); } ColumnMappers cm = config.get(ColumnMappers.class); // look for specialized json support first, revert to simple String mapping if absent ColumnMapper<String> jsonStringMapper = JdbiOptionals.findFirstPresent( () -> cm.findFor(QualifiedType.of(String.class).with(Json.class)), () -> cm.findFor(String.class)) .orElseThrow(() -> new UnableToProduceResultException(JSON_NOT_RETRIEVABLE)); final JsonMapper mapper = config.get(JsonConfig.class).getJsonMapper(); return Optional.of((rs, i, ctx) -> { String json = jsonStringMapper.map(rs, i, ctx); return json == null ? null : mapper.fromJson(type, json, config); }); } }
public Optional<Handler> findFor(Class<?> sqlObjectType, Method method) { return factories.stream() .flatMap(factory -> JdbiOptionals.stream(factory.buildHandler(sqlObjectType, method))) .findFirst(); }
/** * Determines which strategy is to be used for a given {@link QualifiedType}, falling back to * reading strategy annotations on the source class and/or using the configured default. * * @param <E> the {@link Enum} type * @param type qualified type to derive a strategy from * @return the strategy by which this enum should be handled */ public <E extends Enum<E>> EnumStrategy findStrategy(QualifiedType<E> type) { Class<?> erasedType = getErasedType(type.getType()); return JdbiOptionals.findFirstPresent( () -> doFindStrategy(type), () -> doFindStrategy(QualifiedType.of(erasedType).with(getQualifiers(erasedType))) ).orElseGet(() -> registry.get(Enums.class).getDefaultStrategy()); }
/** * Look up an argument by name. * * @param name the key to lookup the value of * @param ctx the statement context * * @return the bound Argument */ public Optional<Argument> findForName(String name, StatementContext ctx) { if (named.containsKey(name)) { return Optional.of(named.get(name)); } return namedArgumentFinder.stream() .flatMap(arguments -> JdbiOptionals.stream(arguments.find(name, ctx))) .findFirst(); }
/** * Obtain a row mapper for the given type in the given context. * * @param type the target type to map to * @return a RowMapper for the given type, or empty if no row mapper is registered for the given type. */ public Optional<RowMapper<?>> findFor(Type type) { // ConcurrentHashMap can enter an infinite loop on nested computeIfAbsent calls. // Since row mappers can decorate other row mappers, we have to populate the cache the old fashioned way. // See https://bugs.openjdk.java.net/browse/JDK-8062841, https://bugs.openjdk.java.net/browse/JDK-8142175 RowMapper<?> cached = cache.get(type); if (cached != null) { return Optional.of(cached); } Optional<RowMapper<?>> mapper = findFirstPresent( () -> factories.stream() .flatMap(factory -> toStream(factory.build(type, registry))) .findFirst(), () -> registry.get(ColumnMappers.class).findFor(type) .map(SingleColumnMapper::new)); mapper.ifPresent(m -> cache.put(type, m)); return mapper; }
/** * Obtain an argument for given value in the given context. * * @param type the qualified type of the argument. * @param value the argument value. * @return an Argument for the given value. */ @Beta public Optional<Argument> findFor(QualifiedType<?> type, Object value) { return factories.stream() .flatMap(factory -> JdbiOptionals.stream(factory.build(type, value, registry))) .findFirst(); }
@Override public Optional<Argument> build(Type type, Object value, ConfigRegistry config) { if (String.class.equals(type)) { return Optional.empty(); } return Optional.of((pos, stmt, ctx) -> { String json = value == null ? null : ctx.getConfig(JsonConfig.class).getJsonMapper().toJson(type, value, ctx); // look for specialized json support first, revert to simple String binding if absent Argument stringBinder = JdbiOptionals.findFirstPresent( () -> ctx.findArgumentFor(QualifiedType.of(String.class).with(Json.class), json), () -> ctx.findArgumentFor(String.class, json)) .orElseThrow(() -> new UnableToCreateStatementException(JSON_NOT_STORABLE)); stringBinder.apply(pos, stmt, ctx); }); } }
/** * Obtain a row mapper for the given type in the given context. * * @param type the target type to map to * @return a RowMapper for the given type, or empty if no row mapper is registered for the given type. */ public Optional<RowMapper<?>> findFor(Type type) { // ConcurrentHashMap can enter an infinite loop on nested computeIfAbsent calls. // Since row mappers can decorate other row mappers, we have to populate the cache the old fashioned way. // See https://bugs.openjdk.java.net/browse/JDK-8062841, https://bugs.openjdk.java.net/browse/JDK-8142175 RowMapper<?> cached = cache.get(type); if (cached != null) { return Optional.of(cached); } Optional<RowMapper<?>> mapper = factories.stream() .flatMap(factory -> JdbiOptionals.stream(factory.build(type, registry))) .findFirst(); mapper.ifPresent(m -> cache.put(type, m)); return mapper; }
@Override public Optional<ColumnMapper<?>> build(Type type, ConfigRegistry config) { if (String.class.equals(type)) { return Optional.empty(); } return Optional.of((rs, i, ctx) -> { // look for specialized json support first, revert to simple String mapping if absent ColumnMapper<String> jsonStringMapper = JdbiOptionals.findFirstPresent( () -> ctx.findColumnMapperFor(QualifiedType.of(String.class).with(Json.class)), () -> ctx.findColumnMapperFor(String.class)) .orElseThrow(() -> new UnableToProduceResultException(JSON_NOT_RETRIEVABLE, ctx)); String json = jsonStringMapper.map(rs, i, ctx); return json == null ? null : ctx.getConfig(JsonConfig.class).getJsonMapper().fromJson(type, json, ctx); }); } }
/** * Obtain a column mapper for the given qualified type. * * @param type the qualified target type to map to * @return a ColumnMapper for the given type, or empty if no column mapper is registered for the given type. */ @Beta public <T> Optional<ColumnMapper<T>> findFor(QualifiedType<T> type) { // ConcurrentHashMap can enter an infinite loop on nested computeIfAbsent calls. // Since column mappers can decorate other column mappers, we have to populate the cache the old fashioned way. // See https://bugs.openjdk.java.net/browse/JDK-8062841, https://bugs.openjdk.java.net/browse/JDK-8142175 @SuppressWarnings("unchecked") ColumnMapper<T> cached = (ColumnMapper<T>) cache.get(type); if (cached != null) { return Optional.of(cached); } Optional<ColumnMapper<T>> mapper = factories.stream() .flatMap(factory -> JdbiOptionals.stream(factory.build(type, registry))) .findFirst() .map(m -> (ColumnMapper<T>) m); mapper.ifPresent(m -> cache.put(type, m)); return mapper; }