org.primeframework.persistence.jdbc.Insert.java Source code

Java tutorial

Introduction

Here is the source code for org.primeframework.persistence.jdbc.Insert.java

Source

/*
 * Copyright (c) 2001-2011, Inversoft Inc., All Rights Reserved
 *
 * 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 org.primeframework.persistence.jdbc;

import javax.persistence.Column;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.primeframework.persistence.jdbc.convert.TypeConverter;
import org.primeframework.persistence.util.StringTools;

import static java.util.Arrays.*;

/**
 * This class is a builder for inserting into a table and retrieving any generated keys.
 *
 * @author Brian Pontarelli
 */
public class Insert extends BaseOperation<Insert> {
    private final Connection c;
    private StringBuilder sql = new StringBuilder();

    public Insert(Connection c) {
        super(true);
        this.c = c;
    }

    public Insert(Connection c, String sql) {
        super(true);
        this.c = c;
        this.sql.append(sql);
    }

    public Insert in(String sql) {
        this.sql = new StringBuilder();
        this.sql.append(sql);
        return this;
    }

    /**
     * Allows the insertion of Objects directly via reflection and JPA annotations. This also makes numerous assumptions
     * if there are no JPA annotations.
     *
     * @param type The type of objects to insert.
     * @param <T>  The type.
     * @return The builder that is used to insert the objects with.
     */
    public <T> InsertObject<T> into(Class<T> type) {
        return new InsertObject<T>(type);
    }

    /**
     * Adds a bulk insert block. This appends the (?,?,?) format to the SQL. It also adds the given values ot the
     * parameters.
     *
     * @param params The value parameters.
     * @return This insert builder.
     */
    public Insert addBulk(Object... params) {
        if (sql.charAt(sql.length() - 1) == ')') {
            sql.append(",");
        }

        sql.append("(");
        for (int i = 0; i < params.length; i++) {
            if (i > 0) {
                sql.append(",");
            }
            sql.append("?");
            add(params[i]);
        }
        sql.append(")");
        return this;
    }

    /**
     * Performs the insert.
     *
     * @return The number of rows inserted.
     * @throws InsertException If the insert fails.
     */
    public int go() throws InsertException {
        PreparedStatement ps = null;
        try {
            ps = c.prepareStatement(sql.toString(), Statement.NO_GENERATED_KEYS);
            setParams(ps);

            return ps.executeUpdate();
        } catch (SQLException e) {
            throw new InsertException(e);
        } finally {
            close(ps);
        }
    }

    /**
     * Performs the insert.
     *
     * @param handler The generated keys handler.
     * @return The result.
     * @throws InsertException If the insert fails.
     */
    public <T> InsertResult<T> go(GeneratedKeyHandler<T> handler) throws InsertException {
        PreparedStatement ps = null;
        try {
            ps = c.prepareStatement(sql.toString(), Statement.RETURN_GENERATED_KEYS);
            setParams(ps);

            int results = ps.executeUpdate();
            if (results != 1) {
                throw new InsertException("Inserting a single row failed completely");
            }

            ResultSet keysRS = ps.getGeneratedKeys();
            List<T> keys = new ArrayList<T>();
            while (keysRS.next()) {
                keys.add(handler.handle(keysRS));
            }

            return new InsertResult<T>(results, keys);
        } catch (SQLException e) {
            throw new InsertException(e);
        } finally {
            close(ps);
        }
    }

    public static class InsertException extends JDBCException {
        public InsertException() {
        }

        public InsertException(String message) {
            super(message);
        }

        public InsertException(String message, Throwable cause) {
            super(message, cause);
        }

        public InsertException(Throwable cause) {
            super(cause);
        }
    }

    public abstract static class GeneratedKeyHandler<T> {
        public abstract T handle(ResultSet rs) throws SQLException;
    }

    public static class InsertResult<T> {
        public final int count;
        public final List<T> keys;

        public InsertResult(int count, List<T> keys) {
            this.count = count;
            this.keys = keys;
        }
    }

    /**
     * @param <T>
     */
    public class InsertObject<T> {
        private final Class<T> type;
        private final List<T> objects = new ArrayList<T>();

        public InsertObject(Class<T> type) {
            this.type = type;
        }

        public InsertObject objects(T... objects) {
            this.objects.addAll(asList(objects));
            return this;
        }

        public InsertObject objects(Collection<T> objects) {
            this.objects.addAll(objects);
            return this;
        }

        public int go() throws InsertException {
            List<String> columns = columnNames(type);
            Insert.this.sql.append("insert into ").append(tableName(type)).append(" (")
                    .append(StringUtils.join(columns, ",")).append(") values ");
            boolean first = true;
            for (T object : objects) {
                if (!first) {
                    Insert.this.sql.append(",");
                }
                first = false;

                Insert.this.sql.append("(");
                for (int i = 0; i < columns.size(); i++) {
                    Insert.this.sql.append("?");
                    if (i < columns.size() - 1) {
                        Insert.this.sql.append(",");
                    }
                }
                Insert.this.sql.append(")");

                Insert.this.add(values(type, columns.size(), object));
            }

            return Insert.this.go();
        }

        private String tableName(Class<T> type) {
            Table table = type.getAnnotation(Table.class);
            String tableName;
            if (table != null) {
                tableName = table.name();
            } else {
                tableName = StringTools.deCamelCase(type.getSimpleName(), true, "_");
            }

            return tableName;
        }

        private List<String> columnNames(Class<T> type) {
            List<String> columnNames = new ArrayList<String>();
            Field[] fields = type.getFields();
            for (Field field : fields) {
                Transient trans = field.getAnnotation(Transient.class);
                if (trans != null) {
                    continue;
                }

                Column column = field.getAnnotation(Column.class);
                String name = "";
                if (column != null) {
                    name = column.name();
                }

                if (name.equals("")) {
                    name = StringTools.deCamelCase(field.getName(), true, "_");
                }

                columnNames.add(name);
            }

            return columnNames;
        }

        @SuppressWarnings("unchecked")
        private Object[] values(Class<T> type, int size, T object) {
            Object[] values = new Object[size];
            Field[] fields = type.getFields();
            int index = 0;
            for (Field field : fields) {
                Transient trans = field.getAnnotation(Transient.class);
                if (trans != null) {
                    continue;
                }

                try {
                    values[index] = field.get(object);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }

                Class<?> fieldType = field.getType();
                TypeConverter converter = TypeConverter.Converters.get(fieldType);
                if (converter != null) {
                    values[index] = converter.convertToSQL(values[index]);
                }

                index++;
            }

            return values;
        }

        public <T> InsertResult go(GeneratedKeyHandler<T> handler) throws InsertException {
            return Insert.this.go(handler);
        }
    }
}