public class InstantArgumentFactory implements ArgumentFactory<Instant> {
    /**
     * <p>{@link Calendar} for representing a database time zone.<p>
     * If a field is not represented in a database as
     * {@code TIMESTAMP WITH TIME ZONE}, we need to set its time zone
     * explicitly. Otherwise it will not be correctly represented in
     * a time zone different from the time zone of the database.
     */
    private final Optional<Calendar> calendar;

    public InstantArgumentFactory() {
        this(Optional.empty());
    }

    public InstantArgumentFactory(final Optional<TimeZone> tz) {
        this.calendar = tz.map(GregorianCalendar::new);
    }

    @Override
    public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
        return value instanceof Instant;
    }

    @Override
    public Argument build(Class<?> expectedType, Instant value, StatementContext ctx) {
        return new InstantArgument(value, calendar);
    }
} public class InstantMapper extends TypedMapper<Instant> {
    /**
     * <p>{@link Calendar} for representing a database time zone.<p>
     * If a field is not represented in a database as
     * {@code TIMESTAMP WITH TIME ZONE}, we need to set its time zone
     * explicitly. Otherwise it will not be correctly represented in
     * a time zone different from the time zone of the database.
     */
    private final Optional<Calendar> calendar;

    public InstantMapper() {
        this(Optional.empty());
    }

    public InstantMapper(final Optional<TimeZone> tz) {
        this.calendar = tz.map(GregorianCalendar::new);
    }

    @Override
    protected Instant extractByName(ResultSet r, String name) throws SQLException {
        final Timestamp timestamp = calendar.isPresent() ? r.getTimestamp(name, cloneCalendar()) : r.getTimestamp(name);
        return timestamp == null ? null : timestamp.toInstant();
    }

    @Override
    protected Instant extractByIndex(ResultSet r, int index) throws SQLException {
        final Timestamp timestamp = calendar.isPresent() ? r.getTimestamp(index, cloneCalendar()) : r.getTimestamp(index);
        return timestamp == null ? null : timestamp.toInstant();
    }

    private Calendar cloneCalendar() {
        return (Calendar) calendar.get().clone();
    }
} public class LocalDateArgumentFactory implements ArgumentFactory<LocalDate> {

    @Override
    public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
        return value instanceof LocalDate;
    }

    @Override
    public Argument build(Class<?> expectedType, LocalDate value, StatementContext ctx) {
        return new LocalDateArgument(value);
    }
} public class LocalDateMapper extends TypedMapper<LocalDate> {

    @Override
    protected LocalDate extractByName(ResultSet r, String name) throws SQLException {
        Timestamp timestamp = r.getTimestamp(name);
        if (timestamp == null) {
            return null;
        }
        return timestamp.toLocalDateTime().toLocalDate();
    }

    @Override
    protected LocalDate extractByIndex(ResultSet r, int index) throws SQLException {
        Timestamp timestamp = r.getTimestamp(index);
        if (timestamp == null) {
            return null;
        }
        return timestamp.toLocalDateTime().toLocalDate();
    }
} public class LocalDateTimeArgumentFactory implements ArgumentFactory<LocalDateTime> {

    @Override
    public boolean accepts(final Class<?> expectedType,
                           final Object value,
                           final StatementContext ctx) {
        return value instanceof LocalDateTime;
    }

    @Override
    public Argument build(final Class<?> expectedType,
                          final LocalDateTime value,
                          final StatementContext ctx) {
        return new LocalDateTimeArgument(value);
    }
} public class LocalDateTimeMapper extends TypedMapper<LocalDateTime> {

    @Override
    protected LocalDateTime extractByName(final ResultSet r, final String name) throws SQLException {
        final Timestamp timestamp = r.getTimestamp(name);
        if (timestamp == null) {
            return null;
        }
        return timestamp.toLocalDateTime();
    }

    @Override
    protected LocalDateTime extractByIndex(final ResultSet r, final int index) throws SQLException {
        final Timestamp timestamp = r.getTimestamp(index);
        if (timestamp == null) {
            return null;
        }
        return timestamp.toLocalDateTime();
    }
} public class OptionalArgumentFactory implements ArgumentFactory<Optional<Object>> {
    private static class DefaultOptionalArgument implements Argument {
        private final Optional<?> value;
        private final int nullType;

        private DefaultOptionalArgument(Optional<?> value, int nullType) {
            this.value = value;
            this.nullType = nullType;
        }

        private DefaultOptionalArgument(Optional<?> value) {
            this(value, Types.OTHER);
        }

        @Override
        public void apply(int position,
                          PreparedStatement statement,
                          StatementContext ctx) throws SQLException {
            if (value.isPresent()) {
                statement.setObject(position, value.get());
            } else {
                statement.setNull(position, nullType);
            }
        }
    }

    private static class MsSqlOptionalArgument implements Argument {
        private final Optional<?> value;

        private MsSqlOptionalArgument(Optional<?> value) {
            this.value = value;
        }

        @Override
        public void apply(int position,
                          PreparedStatement statement,
                          StatementContext ctx) throws SQLException {
            statement.setObject(position, value.orElse(null));
        }
    }

    private final String jdbcDriver;

    public OptionalArgumentFactory(String jdbcDriver) {
        this.jdbcDriver = jdbcDriver;
    }

    @Override
    public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
        return value instanceof Optional;
    }

    @Override
    public Argument build(Class<?> expectedType, Optional<Object> value, StatementContext ctx) {
        if ("com.microsoft.sqlserver.jdbc.SQLServerDriver".equals(jdbcDriver)) {
            return new MsSqlOptionalArgument(value);
        } else if ("oracle.jdbc.OracleDriver".equals(jdbcDriver)) {
            return new DefaultOptionalArgument(value, Types.NULL);
        }
        return new DefaultOptionalArgument(value);
    }
} public class OptionalInstantArgumentFactory implements ArgumentFactory<Optional<Instant>> {

    private final Optional<Calendar> calendar;

    public OptionalInstantArgumentFactory() {
        calendar = Optional.empty();
    }

    public OptionalInstantArgumentFactory(Optional<TimeZone> timeZone) {
        calendar = timeZone.map((Function<TimeZone, Calendar>) GregorianCalendar::new);
    }

    @Override
    public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
        if (value instanceof Optional) {
            final Optional<?> optionalValue = (Optional<?>) value;
            // Fall through to OptionalArgumentFactory if absent.
            // Fall through to OptionalArgumentFactory if present, but not Instant.
            return optionalValue.isPresent() && optionalValue.get() instanceof Instant;
        }
        return false;
    }

    @Override
    public Argument build(Class<?> expectedType, Optional<Instant> value, StatementContext ctx) {
        // accepts guarantees that the value is present
        return new InstantArgument(value.get(), calendar);
    }
} public class OptionalLocalDateArgumentFactory implements ArgumentFactory<Optional<LocalDate>> {
    @Override
    public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
        if (value instanceof Optional) {
            final Optional<?> optionalValue = (Optional<?>) value;
            // Fall through to OptionalArgumentFactory if absent.
            // Fall through to OptionalArgumentFactory if present, but not DateTime.
            return optionalValue.isPresent() && optionalValue.get() instanceof LocalDate;
        }
        return false;
    }

    @Override
    public Argument build(Class<?> expectedType, Optional<LocalDate> value, StatementContext ctx) {
        // accepts guarantees that the value is present
        return new LocalDateArgument(value.get());
    }
} public class OptionalLocalDateTimeArgumentFactory implements ArgumentFactory<Optional<LocalDateTime>> {
    @Override
    public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
        if (value instanceof Optional) {
            final Optional<?> optionalValue = (Optional<?>) value;
            // Fall through to OptionalArgumentFactory if absent.
            // Fall through to OptionalArgumentFactory if present, but not LocalDateTime.
            return optionalValue.isPresent() && optionalValue.get() instanceof LocalDateTime;
        }
        return false;
    }

    @Override
    public Argument build(Class<?> expectedType, Optional<LocalDateTime> value, StatementContext ctx) {
        // accepts guarantees that the value is present
        return new LocalDateTimeArgument(value.get());
    }
}
import io.dropwizard.db.ManagedDataSource;
import io.dropwizard.db.PooledDataSourceFactory;
import io.dropwizard.java8.jdbi.args.InstantArgumentFactory;
import io.dropwizard.java8.jdbi.args.InstantMapper;
import io.dropwizard.java8.jdbi.args.LocalDateArgumentFactory;
import io.dropwizard.java8.jdbi.args.LocalDateMapper;
import io.dropwizard.java8.jdbi.args.LocalDateTimeArgumentFactory;
import io.dropwizard.java8.jdbi.args.LocalDateTimeMapper;
import io.dropwizard.java8.jdbi.args.OptionalArgumentFactory;
import io.dropwizard.java8.jdbi.args.OptionalInstantArgumentFactory;
import io.dropwizard.java8.jdbi.args.OptionalLocalDateArgumentFactory;
import io.dropwizard.java8.jdbi.args.OptionalLocalDateTimeArgumentFactory;
import io.dropwizard.setup.Environment;
import org.skife.jdbi.v2.DBI;
import java.util.Optional;
import java.util.TimeZone;
package io.dropwizard.java8.jdbi;



public class DBIFactory extends io.dropwizard.jdbi.DBIFactory {
    @Override
    public DBI build(Environment environment,
                     PooledDataSourceFactory configuration,
                     ManagedDataSource dataSource,
                     String name) {
        final DBI dbi = super.build(environment, configuration, dataSource, name);

        dbi.registerArgumentFactory(new OptionalArgumentFactory(configuration.getDriverClass()));
        dbi.registerContainerFactory(new OptionalContainerFactory());
        dbi.registerArgumentFactory(new LocalDateArgumentFactory());
        dbi.registerArgumentFactory(new OptionalLocalDateArgumentFactory());
        dbi.registerArgumentFactory(new LocalDateTimeArgumentFactory());
        dbi.registerArgumentFactory(new OptionalLocalDateTimeArgumentFactory());
        dbi.registerMapper(new LocalDateMapper());
        dbi.registerMapper(new LocalDateTimeMapper());

        final Optional<TimeZone> tz = Optional.ofNullable(databaseTimeZone().orNull());
        dbi.registerArgumentFactory(new InstantArgumentFactory(tz));
        dbi.registerArgumentFactory(new OptionalInstantArgumentFactory(tz));