DATAJDBC-95 - Saving and loading a trivial entity.

Creation of the necessary sql statements is now dynamic and driven in a trivial way by the entity.

Known issues with the solution that need to get fixed later:

- SQL generating code is in the repository and should go somewhere else.
- Mapping logic is very trivial and should go in a separate place.

Original pull request: #5.
This commit is contained in:
Jens Schauder
2017-02-21 13:57:25 +01:00
committed by Oliver Gierke
parent 7696f5a1de
commit 38a91d97a0
4 changed files with 162 additions and 23 deletions

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2017 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
*
* 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.springframework.data.jdbc.repository;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PropertyHandler;
/**
* @author Jens Schauder
*/
class EntityRowMapper<T> implements org.springframework.jdbc.core.RowMapper<T> {
private final PersistentEntity<T, ?> entity;
EntityRowMapper(PersistentEntity<T, ?> entity) {
this.entity = entity;
}
@Override
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
try {
T t = createInstance();
entity.doWithProperties((PropertyHandler) property -> {
setProperty(rs, t, property);
});
return t;
} catch (Exception e) {
throw new RuntimeException(String.format("Could not instantiate %s", entity.getType()));
}
}
private T createInstance() throws InstantiationException, IllegalAccessException, InvocationTargetException {
return (T) entity.getPersistenceConstructor().getConstructor().newInstance();
}
private void setProperty(ResultSet rs, T t, PersistentProperty property) {
try {
property.getSetter().invoke(t, rs.getObject(property.getName()));
} catch (Exception e) {
throw new RuntimeException(String.format("Couldn't set property %s.", property.getName()), e);
}
}
}

View File

@@ -16,11 +16,17 @@
package org.springframework.data.jdbc.repository;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@@ -29,23 +35,25 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
*/
public class SimpleJdbcRepository<T, ID extends Serializable> implements CrudRepository<T, ID> {
private final EntityInformation entityInformation;
private final JdbcPersistentEntity<T> entity;
private final NamedParameterJdbcOperations template;
public SimpleJdbcRepository(EntityInformation entityInformation, DataSource dataSource) {
this.entityInformation = entityInformation;
private final String findOneSql;
private final String insertSql;
public SimpleJdbcRepository(JdbcPersistentEntity<T> entity, DataSource dataSource) {
this.entity = entity;
this.template = new NamedParameterJdbcTemplate(dataSource);
findOneSql = createFindOneSelectSql();
insertSql = createInsertSql();
}
@Override
public <S extends T> S save(S entity) {
Map<String, Object> parameters = new HashMap<>();
parameters.put("id", entityInformation.getId(entity));
parameters.put("name", "blah blah");
template.update(
"insert into dummyentity (id, name) values (:id, :name)",
parameters);
template.update(insertSql, getPropertyMap(entity));
return entity;
}
@@ -57,7 +65,12 @@ public class SimpleJdbcRepository<T, ID extends Serializable> implements CrudRep
@Override
public T findOne(ID id) {
return null;
return template.queryForObject(
findOneSql,
new MapSqlParameterSource("id", id),
new EntityRowMapper<T>(entity)
);
}
@Override
@@ -99,4 +112,45 @@ public class SimpleJdbcRepository<T, ID extends Serializable> implements CrudRep
public void deleteAll() {
}
private String createFindOneSelectSql() {
String tableName = entity.getType().getSimpleName();
String idColumn = entity.getIdProperty().getName();
return String.format("select * from %s where %s = :id", tableName, idColumn);
}
private String createInsertSql() {
List<String> propertyNames = new ArrayList<>();
entity.doWithProperties((PropertyHandler) persistentProperty -> propertyNames.add(persistentProperty.getName()));
String insertTemplate = "insert into %s (%s) values (%s)";
String tableName = entity.getType().getSimpleName();
String tableColumns = propertyNames.stream().collect(Collectors.joining(", "));
String parameterNames = propertyNames.stream().collect(Collectors.joining(", :", ":", ""));
return String.format(insertTemplate, tableName, tableColumns, parameterNames);
}
private <S extends T> Map<String, Object> getPropertyMap(final S entity) {
Map<String, Object> parameters = new HashMap<>();
this.entity.doWithProperties(new PropertyHandler() {
@Override
public void doWithPersistentProperty(PersistentProperty persistentProperty) {
try {
parameters.put(persistentProperty.getName(), persistentProperty.getGetter().invoke(entity));
} catch (Exception e) {
throw new RuntimeException(String.format("Couldn't get value of property %s", persistentProperty.getName()));
}
}
});
return parameters;
}
}

View File

@@ -39,13 +39,12 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
@Override
public <T, ID extends Serializable> EntityInformation<T, ID> getEntityInformation(Class<T> aClass) {
JdbcPersistentEntity<T> persistentEntity = (JdbcPersistentEntity<T>) context.getPersistentEntity(aClass);
return new JdbcPersistentEntityInformation<T, ID>(persistentEntity);
return new JdbcPersistentEntityInformation<T, ID>((JdbcPersistentEntity<T>) context.getPersistentEntity(aClass));
}
@Override
protected Object getTargetRepository(RepositoryInformation repositoryInformation) {
return new SimpleJdbcRepository(getEntityInformation(repositoryInformation.getDomainType()), dataSource);
return new SimpleJdbcRepository(context.getPersistentEntity(repositoryInformation.getDomainType()), dataSource);
}
@Override