com.github.ferstl.spring.jdbc.oracle.OracleNamedParameterJdbcTemplate.java Source code

Java tutorial

Introduction

Here is the source code for com.github.ferstl.spring.jdbc.oracle.OracleNamedParameterJdbcTemplate.java

Source

/*
 * Copyright (c) 2013 by Philippe Marschall <philippe.marschall@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.ferstl.spring.jdbc.oracle;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import oracle.jdbc.OraclePreparedStatement;

import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;

/**
 * A subclass of Spring's {@link NamedParameterJdbcTemplate} the uses
 * Oracle named parameter support to avoid building a new query.
 * <h3>Limitations</h3>
 * <ul>
 * <li>
 * currently only works with
 * {@link org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource}
 * and
 * {@link org.springframework.jdbc.core.namedparam.MapSqlParameterSource}
 * but thats a limitation in {@link SqlParameterSourceUtils}
 * </li>
 * <li>does not support collections</li>
 * <ul>
 */
public final class OracleNamedParameterJdbcTemplate extends NamedParameterJdbcTemplate {

    /**
     * Create a new OracleNamedParameterJdbcTemplate for the given classic
     * Spring {@link org.springframework.jdbc.core.JdbcTemplate}.
     * @param classicJdbcTemplate the classic Spring JdbcTemplate to wrap
     */
    public OracleNamedParameterJdbcTemplate(JdbcOperations classicJdbcTemplate) {
        super(classicJdbcTemplate);
    }

    @Override
    protected PreparedStatementCreator getPreparedStatementCreator(String sql, SqlParameterSource parameterSource) {
        return new NamedPreparedStatementCreator(sql, parameterSource);
    }

    static final class NamedPreparedStatementCreator implements PreparedStatementCreator {

        private final String sql;
        private final SqlParameterSource parameterSource;

        NamedPreparedStatementCreator(String sql, SqlParameterSource parameterSource) {
            this.sql = sql;
            this.parameterSource = parameterSource;
        }

        @Override
        public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
            PreparedStatement wrapped = connection.prepareStatement(sql);
            OraclePreparedStatement statement = wrapped.unwrap(OraclePreparedStatement.class);

            for (String parameterName : this.getParameterNames()) {
                int sqlType = this.parameterSource.getSqlType(parameterName);
                Object value = this.parameterSource.getValue(parameterName);
                if (sqlType != SqlParameterSource.TYPE_UNKNOWN) {
                    if (value != null) {
                        statement.setObjectAtName(parameterName, value, sqlType);
                    } else {
                        statement.setNullAtName(parameterName, sqlType);
                    }
                } else {
                    if (value != null) {
                        statement.setObjectAtName(parameterName, value);
                    } else {
                        // REVIEW: not actually sure but there doesn't seem to be a
                        // setNullAtName without a type
                        // we can't do
                        // statement.getParameterMetaData().getParameterType(i)
                        // because that doesn't take names and
                        // OracleParameterMetaData doesn't add any additional methods
                        // it might not even be doable in an unambiguous way because
                        // a name can be used several times in a query for comparisons
                        // (or inserts) of columns of varying types
                        statement.setNullAtName(parameterName, Types.NULL);
                    }
                }
            }
            return wrapped;
        }

        private Collection<String> getParameterNames() {
            Map<?, ?> insensitiveParameterNames = SqlParameterSourceUtils
                    .extractCaseInsensitiveParameterNames(parameterSource);
            Set<String> parameterNames = new HashSet<>(insensitiveParameterNames.size());
            for (Object each : insensitiveParameterNames.values()) {
                parameterNames.add((String) each);
            }
            return parameterNames;
        }

    }

}