Skip to content

Commit d7fadf9

Browse files
committed
DATAJDBC-97 - Basic implementation of all CRUD methods.
1 parent 6cbd779 commit d7fadf9

File tree

7 files changed

+371
-74
lines changed

7 files changed

+371
-74
lines changed

pom.xml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@
6767
<artifactId>spring-beans</artifactId>
6868
</dependency>
6969

70+
<dependency>
71+
<groupId>org.springframework</groupId>
72+
<artifactId>spring-jdbc</artifactId>
73+
</dependency>
74+
7075
<dependency>
7176
<groupId>org.springframework</groupId>
7277
<artifactId>spring-core</artifactId>
@@ -84,9 +89,12 @@
8489
<version>2.2.8</version>
8590
<scope>test</scope>
8691
</dependency>
92+
8793
<dependency>
88-
<groupId>org.springframework</groupId>
89-
<artifactId>spring-jdbc</artifactId>
94+
<groupId>org.assertj</groupId>
95+
<artifactId>assertj-core</artifactId>
96+
<version>3.6.2</version>
97+
<scope>test</scope>
9098
</dependency>
9199

92100

src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntity.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,35 @@
1919
import org.springframework.data.util.TypeInformation;
2020

2121
/**
22+
* meta data a repository might need for implementing persistence operations for instances of type {@code T}
2223
* @author Jens Schauder
2324
*/
2425
public class JdbcPersistentEntity<T> extends BasicPersistentEntity<T, JdbcPersistentProperty> {
2526

27+
private String tableName;
28+
private String idColumn;
29+
2630
public JdbcPersistentEntity(TypeInformation<T> information) {
2731
super(information);
2832
}
33+
34+
public String getTableName() {
35+
36+
if (tableName == null)
37+
tableName = getType().getSimpleName();
38+
39+
return tableName;
40+
}
41+
42+
public String getIdColumn() {
43+
44+
if (idColumn == null)
45+
idColumn = getIdProperty().getName();
46+
47+
return idColumn;
48+
}
49+
50+
public Object getIdValue(T instance) {
51+
return getPropertyAccessor(instance).getProperty(getIdProperty());
52+
}
2953
}

src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentProperty.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import org.springframework.data.mapping.model.SimpleTypeHolder;
2424

2525
/**
26+
* meta data about a property to be used by repository implementations.
27+
*
2628
* @author Jens Schauder
2729
*/
2830
public class JdbcPersistentProperty extends AnnotationBasedPersistentProperty<JdbcPersistentProperty> {
@@ -43,4 +45,8 @@ public JdbcPersistentProperty(Field field, PropertyDescriptor propertyDescriptor
4345
protected Association<JdbcPersistentProperty> createAssociation() {
4446
return null;
4547
}
48+
49+
public String getColumnName() {
50+
return getName();
51+
}
4652
}

src/main/java/org/springframework/data/jdbc/repository/EntityRowMapper.java

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,49 +15,62 @@
1515
*/
1616
package org.springframework.data.jdbc.repository;
1717

18-
import java.lang.reflect.InvocationTargetException;
1918
import java.sql.ResultSet;
2019
import java.sql.SQLException;
21-
import org.springframework.data.mapping.PersistentEntity;
20+
import org.springframework.data.convert.ClassGeneratingEntityInstantiator;
21+
import org.springframework.data.convert.EntityInstantiator;
22+
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
23+
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
2224
import org.springframework.data.mapping.PersistentProperty;
25+
import org.springframework.data.mapping.PreferredConstructor;
2326
import org.springframework.data.mapping.PropertyHandler;
27+
import org.springframework.data.mapping.model.MappingException;
28+
import org.springframework.data.mapping.model.ParameterValueProvider;
2429

2530
/**
31+
* maps a ResultSet to an entity of type {@code T}
32+
*
2633
* @author Jens Schauder
2734
*/
2835
class EntityRowMapper<T> implements org.springframework.jdbc.core.RowMapper<T> {
2936

30-
private final PersistentEntity<T, ?> entity;
37+
private final JdbcPersistentEntity<T> entity;
38+
39+
private final EntityInstantiator instantiator = new ClassGeneratingEntityInstantiator();
3140

32-
EntityRowMapper(PersistentEntity<T, ?> entity) {
41+
EntityRowMapper(JdbcPersistentEntity<T> entity) {
3342
this.entity = entity;
3443
}
3544

3645
@Override
3746
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
3847

39-
try {
40-
41-
T t = createInstance();
48+
T t = createInstance(rs);
4249

43-
entity.doWithProperties((PropertyHandler) property -> {
44-
setProperty(rs, t, property);
45-
});
50+
entity.doWithProperties((PropertyHandler) property -> {
51+
setProperty(rs, t, property);
52+
});
4653

47-
return t;
48-
} catch (Exception e) {
49-
throw new RuntimeException(String.format("Could not instantiate %s", entity.getType()));
50-
}
54+
return t;
5155
}
5256

53-
private T createInstance() throws InstantiationException, IllegalAccessException, InvocationTargetException {
54-
return (T) entity.getPersistenceConstructor().getConstructor().newInstance();
57+
private T createInstance(ResultSet rs) {
58+
return instantiator.createInstance(entity, new ParameterValueProvider<JdbcPersistentProperty>() {
59+
@Override
60+
public <T> T getParameterValue(PreferredConstructor.Parameter<T, JdbcPersistentProperty> parameter) {
61+
try {
62+
return (T) rs.getObject(parameter.getName());
63+
} catch (SQLException e) {
64+
throw new MappingException(String.format("Couldn't read column %s from ResultSet.", parameter.getName()));
65+
}
66+
}
67+
});
5568
}
5669

5770
private void setProperty(ResultSet rs, T t, PersistentProperty property) {
5871

5972
try {
60-
property.getSetter().invoke(t, rs.getObject(property.getName()));
73+
entity.getPropertyAccessor(t).setProperty(property, rs.getObject(property.getName()));
6174
} catch (Exception e) {
6275
throw new RuntimeException(String.format("Couldn't set property %s.", property.getName()), e);
6376
}

src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java

Lines changed: 47 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@
1616
package org.springframework.data.jdbc.repository;
1717

1818
import java.io.Serializable;
19-
import java.util.ArrayList;
2019
import java.util.HashMap;
21-
import java.util.List;
2220
import java.util.Map;
2321
import java.util.stream.Collectors;
22+
import java.util.stream.StreamSupport;
2423
import javax.sql.DataSource;
2524
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
26-
import org.springframework.data.mapping.PersistentProperty;
25+
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
2726
import org.springframework.data.mapping.PropertyHandler;
2827
import org.springframework.data.repository.CrudRepository;
2928
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@@ -37,117 +36,116 @@ public class SimpleJdbcRepository<T, ID extends Serializable> implements CrudRep
3736

3837
private final JdbcPersistentEntity<T> entity;
3938
private final NamedParameterJdbcOperations template;
39+
private final SqlGenerator sql;
4040

41-
private final String findOneSql;
42-
private final String insertSql;
41+
private final EntityRowMapper<T> entityRowMapper;
4342

4443
public SimpleJdbcRepository(JdbcPersistentEntity<T> entity, DataSource dataSource) {
4544

4645
this.entity = entity;
4746
this.template = new NamedParameterJdbcTemplate(dataSource);
4847

49-
findOneSql = createFindOneSelectSql();
50-
insertSql = createInsertSql();
48+
entityRowMapper = new EntityRowMapper<T>(entity);
49+
sql = new SqlGenerator(entity);
5150
}
5251

5352
@Override
5453
public <S extends T> S save(S entity) {
5554

56-
template.update(insertSql, getPropertyMap(entity));
55+
template.update(sql.getInsert(), getPropertyMap(entity));
5756

5857
return entity;
5958
}
6059

6160
@Override
6261
public <S extends T> Iterable<S> save(Iterable<S> entities) {
63-
return null;
62+
63+
Map<String, ?>[] batchValues = StreamSupport
64+
.stream(entities.spliterator(), false)
65+
.map(i -> getPropertyMap(i))
66+
.toArray(size -> new Map[size]);
67+
68+
template.batchUpdate(sql.getInsert(), batchValues);
69+
70+
return entities;
6471
}
6572

6673
@Override
6774
public T findOne(ID id) {
6875

6976
return template.queryForObject(
70-
findOneSql,
77+
sql.getFindOne(),
7178
new MapSqlParameterSource("id", id),
72-
new EntityRowMapper<T>(entity)
79+
entityRowMapper
7380
);
7481
}
7582

7683
@Override
7784
public boolean exists(ID id) {
78-
return false;
85+
86+
return template.queryForObject(
87+
sql.getExists(),
88+
new MapSqlParameterSource("id", id),
89+
Boolean.class
90+
);
7991
}
8092

8193
@Override
8294
public Iterable<T> findAll() {
83-
return null;
95+
return template.query(sql.getFindAll(), entityRowMapper);
8496
}
8597

8698
@Override
8799
public Iterable<T> findAll(Iterable<ID> ids) {
88-
return null;
100+
return template.query(sql.getFindAllInList(), new MapSqlParameterSource("ids", ids), entityRowMapper);
89101
}
90102

91103
@Override
92104
public long count() {
93-
return 0;
105+
return template.getJdbcOperations().queryForObject(sql.getCount(), Long.class);
94106
}
95107

96108
@Override
97109
public void delete(ID id) {
98-
110+
template.update(sql.getDeleteById(), new MapSqlParameterSource("id", id));
99111
}
100112

101113
@Override
102-
public void delete(T entity) {
114+
public void delete(T instance) {
103115

116+
template.update(
117+
sql.getDeleteById(),
118+
new MapSqlParameterSource("id",
119+
entity.getIdValue(instance)));
104120
}
105121

106122
@Override
107123
public void delete(Iterable<? extends T> entities) {
108124

125+
template.update(
126+
sql.getDeleteByList(),
127+
new MapSqlParameterSource("ids",
128+
StreamSupport
129+
.stream(entities.spliterator(), false)
130+
.map(entity::getIdValue)
131+
.collect(Collectors.toList())
132+
)
133+
);
109134
}
110135

111136
@Override
112137
public void deleteAll() {
113-
114-
}
115-
116-
private String createFindOneSelectSql() {
117-
118-
String tableName = entity.getType().getSimpleName();
119-
String idColumn = entity.getIdProperty().getName();
120-
121-
return String.format("select * from %s where %s = :id", tableName, idColumn);
122-
}
123-
124-
private String createInsertSql() {
125-
126-
List<String> propertyNames = new ArrayList<>();
127-
entity.doWithProperties((PropertyHandler) persistentProperty -> propertyNames.add(persistentProperty.getName()));
128-
129-
String insertTemplate = "insert into %s (%s) values (%s)";
130-
131-
String tableName = entity.getType().getSimpleName();
132-
133-
String tableColumns = propertyNames.stream().collect(Collectors.joining(", "));
134-
String parameterNames = propertyNames.stream().collect(Collectors.joining(", :", ":", ""));
135-
136-
return String.format(insertTemplate, tableName, tableColumns, parameterNames);
138+
template.getJdbcOperations().update(sql.getDeleteAll());
137139
}
138140

139-
private <S extends T> Map<String, Object> getPropertyMap(final S entity) {
141+
private <S extends T> Map<String, Object> getPropertyMap(final S instance) {
140142

141143
Map<String, Object> parameters = new HashMap<>();
142144

143-
this.entity.doWithProperties(new PropertyHandler() {
145+
this.entity.doWithProperties(new PropertyHandler<JdbcPersistentProperty>() {
144146
@Override
145-
public void doWithPersistentProperty(PersistentProperty persistentProperty) {
146-
try {
147-
parameters.put(persistentProperty.getName(), persistentProperty.getGetter().invoke(entity));
148-
} catch (Exception e) {
149-
throw new RuntimeException(String.format("Couldn't get value of property %s", persistentProperty.getName()));
150-
}
147+
public void doWithPersistentProperty(JdbcPersistentProperty persistentProperty) {
148+
parameters.put(persistentProperty.getColumnName(), entity.getPropertyAccessor(instance).getProperty(persistentProperty));
151149
}
152150
});
153151

0 commit comments

Comments
 (0)