diff --git a/src/main/java/org/springframework/data/jdbc/repository/EntityRowMapper.java b/src/main/java/org/springframework/data/jdbc/repository/EntityRowMapper.java new file mode 100644 index 000000000..704506707 --- /dev/null +++ b/src/main/java/org/springframework/data/jdbc/repository/EntityRowMapper.java @@ -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 implements org.springframework.jdbc.core.RowMapper { + + private final PersistentEntity entity; + + EntityRowMapper(PersistentEntity 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); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java b/src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java index 45bb7ad97..8ae8d4b72 100644 --- a/src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java +++ b/src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java @@ -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 implements CrudRepository { - private final EntityInformation entityInformation; + private final JdbcPersistentEntity 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 entity, DataSource dataSource) { + + this.entity = entity; this.template = new NamedParameterJdbcTemplate(dataSource); + + findOneSql = createFindOneSelectSql(); + insertSql = createInsertSql(); } @Override public S save(S entity) { - Map 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 implements CrudRep @Override public T findOne(ID id) { - return null; + + return template.queryForObject( + findOneSql, + new MapSqlParameterSource("id", id), + new EntityRowMapper(entity) + ); } @Override @@ -99,4 +112,45 @@ public class SimpleJdbcRepository 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 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 Map getPropertyMap(final S entity) { + + Map 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; + } } diff --git a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java index a92d74d6c..d24598250 100644 --- a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java +++ b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java @@ -39,13 +39,12 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport { @Override public EntityInformation getEntityInformation(Class aClass) { - JdbcPersistentEntity persistentEntity = (JdbcPersistentEntity) context.getPersistentEntity(aClass); - return new JdbcPersistentEntityInformation(persistentEntity); + return new JdbcPersistentEntityInformation((JdbcPersistentEntity) 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 diff --git a/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java index b938925f6..b1fd9045c 100644 --- a/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java @@ -48,19 +48,18 @@ public class JdbcRepositoryIntegrationTests { private final NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(db); + private final DummyEntityRepository repository = createRepository(db); + + private DummyEntity entity = createDummyEntity(); + @After - public void afeter() { + public void after() { db.shutdown(); } @Test public void canSaveAnEntity() throws SQLException { - DummyEntityRepository repository = createRepository(); - - DummyEntity entity = new DummyEntity(); - entity.setId(23L); - entity.setName("Entity Name"); entity = repository.save(entity); @@ -74,9 +73,31 @@ public class JdbcRepositoryIntegrationTests { count); } - private DummyEntityRepository createRepository() throws SQLException { - JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(db); - return jdbcRepositoryFactory.getRepository(DummyEntityRepository.class); + @Test + public void canSaveAndLoadAnEntity() throws SQLException { + + entity = repository.save(entity); + + DummyEntity reloadedEntity = repository.findOne(entity.getId()); + + assertEquals( + entity.getId(), + reloadedEntity.getId()); + assertEquals( + entity.getName(), + reloadedEntity.getName()); + } + + private static DummyEntityRepository createRepository(EmbeddedDatabase db) { + return new JdbcRepositoryFactory(db).getRepository(DummyEntityRepository.class); + } + + + private static DummyEntity createDummyEntity() { + DummyEntity entity = new DummyEntity(); + entity.setId(23L); + entity.setName("Entity Name"); + return entity; } private interface DummyEntityRepository extends CrudRepository {