/** * 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; }