InsertOperation.java
/*
* Copyright 2025-present the original author or authors.
*
* 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
*
* https://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 io.github.simplejdbcmapper.core;
import java.util.Arrays;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.util.Assert;
import io.github.simplejdbcmapper.exception.MapperException;
/**
* The insert operation.
*
* @author Antony Joseph
*/
class InsertOperation {
private final SimpleJdbcMapperSupport sjmSupport;
private final SimpleCache<Class<?>, SimpleJdbcInsert> insertSqlCache = new SimpleCache<>();
public InsertOperation(SimpleJdbcMapperSupport sjmSupport) {
this.sjmSupport = sjmSupport;
}
public void insert(Object object) {
Assert.notNull(object, "object must not be null");
TableMapping tableMapping = sjmSupport.getTableMapping(object.getClass());
EntityWrapper ew = new EntityWrapper(object);
validateId(ew, tableMapping);
populateAutoAssignProperties(ew, tableMapping);
MapSqlParameterSource mapSqlParameterSource = createMapSqlParameterSource(ew, tableMapping);
SimpleJdbcInsert simpleJdbcInsert = insertSqlCache.get(object.getClass());
if (simpleJdbcInsert == null) {
simpleJdbcInsert = createSimpleJdbcInsert(tableMapping);
// Spring's SimpleJdbcInsert is thread safe. cache it
insertSqlCache.put(object.getClass(), simpleJdbcInsert);
}
if (tableMapping.isIdAutoGenerated()) {
KeyHolder kh = simpleJdbcInsert.executeAndReturnKeyHolder(mapSqlParameterSource);
// set the generated id on the object
ew.setPropertyValue(tableMapping.getIdPropertyMapping(), kh.getKeyAs(Object.class),
sjmSupport.getConversionService());
} else {
simpleJdbcInsert.execute(mapSqlParameterSource);
}
}
SimpleCache<Class<?>, SimpleJdbcInsert> getInsertSqlCache() {
return insertSqlCache;
}
private MapSqlParameterSource createMapSqlParameterSource(EntityWrapper ew, TableMapping tableMapping) {
MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource();
for (PropertyMapping propMapping : tableMapping.getPropertyMappings()) {
Object val = ew.getPropertyValue(propMapping);
Integer columnSqlType = propMapping.getColumnSqlType();
String columnName = propMapping.getColumnName();
if (propMapping.isBinaryLargeObject()) {
InternalUtils.assignBlobMapSqlParameterSource(mapSqlParameterSource, val, columnName, columnSqlType);
} else if (propMapping.isCharacterLargeObject()) {
InternalUtils.assignClobMapSqlParameterSource(mapSqlParameterSource, val, columnName, columnSqlType);
} else if (propMapping.isEnum()) {
if (val == null) {
mapSqlParameterSource.addValue(columnName, null, columnSqlType);
} else {
mapSqlParameterSource.addValue(columnName, ((Enum<?>) val).name(), columnSqlType);
}
} else {
mapSqlParameterSource.addValue(columnName, val, columnSqlType);
}
}
return mapSqlParameterSource;
}
private void validateId(EntityWrapper ew, TableMapping tableMapping) {
Object idValue = ew.getPropertyValue(tableMapping.getIdPropertyMapping());
if (tableMapping.isIdAutoGenerated()) {
if (idValue != null) {
throw new MapperException("For insert() the property " + ew.getWrappedClass().getSimpleName() + "."
+ tableMapping.getIdPropertyName()
+ " has to be null since this insert is for an object whose id is auto generated");
}
} else {
if (idValue == null) {
throw new MapperException("For insert() the property " + ew.getWrappedClass().getSimpleName() + "."
+ tableMapping.getIdPropertyName() + " must not be null since it is not an auto generated id");
}
}
}
private void populateAutoAssignProperties(EntityWrapper ew, TableMapping tableMapping) {
if (tableMapping.hasAutoAssignProperties()) {
PropertyMapping createdOnPropMapping = tableMapping.getCreatedOnPropertyMapping();
if (createdOnPropMapping != null && sjmSupport.getRecordAuditedOnSupplier() != null) {
ew.setPropertyValue(createdOnPropMapping, sjmSupport.getRecordAuditedOnSupplier().get());
}
PropertyMapping updatedOnPropMapping = tableMapping.getUpdatedOnPropertyMapping();
if (updatedOnPropMapping != null && sjmSupport.getRecordAuditedOnSupplier() != null) {
ew.setPropertyValue(updatedOnPropMapping, sjmSupport.getRecordAuditedOnSupplier().get());
}
PropertyMapping createdByPropMapping = tableMapping.getCreatedByPropertyMapping();
if (createdByPropMapping != null && sjmSupport.getRecordAuditedBySupplier() != null) {
ew.setPropertyValue(createdByPropMapping, sjmSupport.getRecordAuditedBySupplier().get());
}
PropertyMapping updatedByPropMapping = tableMapping.getUpdatedByPropertyMapping();
if (updatedByPropMapping != null && sjmSupport.getRecordAuditedBySupplier() != null) {
ew.setPropertyValue(updatedByPropMapping, sjmSupport.getRecordAuditedBySupplier().get());
}
PropertyMapping versionPropMapping = tableMapping.getVersionPropertyMapping();
if (versionPropMapping != null) {
// version property value defaults to 1 on inserts
ew.setPropertyValue(versionPropMapping, 1);
}
}
}
private SimpleJdbcInsert createSimpleJdbcInsert(TableMapping tableMapping) {
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(sjmSupport.getJdbcTemplate())
.withCatalogName(tableMapping.getCatalogName()).withSchemaName(tableMapping.getSchemaName())
.withTableName(tableMapping.getTableName());
// make sure SimpleJdbcInsert does not access database table meta data.
simpleJdbcInsert.setAccessTableColumnMetaData(false);
String[] columns = null;
if (tableMapping.isIdAutoGenerated()) {
// remove id from list of columns
columns = Arrays.stream(tableMapping.getPropertyMappings()).filter(e -> !e.isIdAnnotation())
.map(e -> e.getColumnName()).toArray(String[]::new);
} else {
columns = Arrays.stream(tableMapping.getPropertyMappings()).map(e -> e.getColumnName())
.toArray(String[]::new);
}
simpleJdbcInsert.usingColumns(columns);
if (tableMapping.isIdAutoGenerated()) {
simpleJdbcInsert.usingGeneratedKeyColumns(tableMapping.getIdColumnName());
}
return simpleJdbcInsert;
}
}