Skip to content

Commit 644bbd2

Browse files
committed
Initial checkin for http://code.google.com/p/mybatis/issues/detail?id=10 - add @SelectKey annotation
1 parent db4ab6c commit 644bbd2

File tree

7 files changed

+182
-21
lines changed

7 files changed

+182
-21
lines changed

pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@
166166
</execution>
167167
</executions>
168168
</plugin>
169+
<plugin>
170+
<groupId>org.apache.maven.plugins</groupId>
171+
<artifactId>maven-surefire-plugin</artifactId>
172+
<configuration>
173+
<forkMode>pertest</forkMode>
174+
</configuration>
175+
</plugin>
169176
</plugins>
170177
<resources>
171178
<resource>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.apache.ibatis.annotations;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
import org.apache.ibatis.mapping.StatementType;
9+
10+
@Retention(RetentionPolicy.RUNTIME)
11+
@Target(ElementType.METHOD)
12+
public @interface SelectKey {
13+
public abstract String[] statement();
14+
public abstract String keyProperty();
15+
public abstract boolean before();
16+
public abstract Class<?> resultType();
17+
public abstract StatementType statementType() default StatementType.PREPARED;
18+
}

src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.apache.ibatis.annotations.Result;
2929
import org.apache.ibatis.annotations.Results;
3030
import org.apache.ibatis.annotations.Select;
31+
import org.apache.ibatis.annotations.SelectKey;
3132
import org.apache.ibatis.annotations.SelectProvider;
3233
import org.apache.ibatis.annotations.TypeDiscriminator;
3334
import org.apache.ibatis.annotations.Update;
@@ -43,8 +44,10 @@
4344
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
4445
import org.apache.ibatis.executor.keygen.KeyGenerator;
4546
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
47+
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
4648
import org.apache.ibatis.io.Resources;
4749
import org.apache.ibatis.mapping.Discriminator;
50+
import org.apache.ibatis.mapping.MappedStatement;
4851
import org.apache.ibatis.mapping.ResultFlag;
4952
import org.apache.ibatis.mapping.ResultMapping;
5053
import org.apache.ibatis.mapping.ResultSetType;
@@ -113,14 +116,14 @@ private void loadXmlResource() {
113116
}
114117

115118
private void parseCache() {
116-
CacheNamespace cacheDomain = (CacheNamespace) type.getAnnotation(CacheNamespace.class);
119+
CacheNamespace cacheDomain = type.getAnnotation(CacheNamespace.class);
117120
if (cacheDomain != null) {
118121
assistant.useNewCache(cacheDomain.implementation(), cacheDomain.eviction(), cacheDomain.flushInterval(), cacheDomain.size(), cacheDomain.readWrite(), null);
119122
}
120123
}
121124

122125
private void parseCacheRef() {
123-
CacheNamespaceRef cacheDomainRef = (CacheNamespaceRef) type.getAnnotation(CacheNamespaceRef.class);
126+
CacheNamespaceRef cacheDomainRef = type.getAnnotation(CacheNamespaceRef.class);
124127
if (cacheDomainRef != null) {
125128
assistant.useCacheRef(cacheDomainRef.value().getName());
126129
}
@@ -218,19 +221,40 @@ private void parseStatement(Method method) {
218221
StatementType statementType = StatementType.PREPARED;
219222
ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
220223
SqlCommandType sqlCommandType = getSqlCommandType(method);
221-
KeyGenerator keyGenerator = configuration.isUseGeneratedKeys()
222-
&& SqlCommandType.INSERT.equals(sqlCommandType) ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
224+
225+
KeyGenerator keyGenerator;
223226
String keyProperty = "id";
227+
if (SqlCommandType.INSERT.equals(sqlCommandType)) {
228+
// first check for SelectKey annotation - that overrides everything else
229+
SelectKey selectKey = method.getAnnotation(SelectKey.class);
230+
if (selectKey != null) {
231+
keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method));
232+
keyProperty = selectKey.keyProperty();
233+
} else {
234+
if (configuration.isUseGeneratedKeys()) {
235+
if (options == null) {
236+
keyGenerator = new Jdbc3KeyGenerator();
237+
} else {
238+
keyProperty = options.keyProperty();
239+
keyGenerator = options.useGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
240+
}
241+
} else {
242+
keyGenerator = new NoKeyGenerator();
243+
}
244+
}
245+
} else {
246+
keyGenerator = new NoKeyGenerator();
247+
}
248+
224249
if (options != null) {
225250
flushCache = options.flushCache();
226251
useCache = options.useCache();
227252
fetchSize = options.fetchSize() > -1 ? options.fetchSize() : null;
228253
timeout = options.timeout() > -1 ? options.timeout() : null;
229254
statementType = options.statementType();
230255
resultSetType = options.resultSetType();
231-
keyGenerator = options.useGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
232-
keyProperty = options.keyProperty();
233256
}
257+
234258
assistant.addMappedStatement(
235259
mappedStatementId,
236260
sqlSource,
@@ -304,15 +328,7 @@ private SqlSource getSqlSourceFromAnnotations(Method method) {
304328
}
305329
Annotation sqlAnnotation = method.getAnnotation(sqlAnnotationType);
306330
final String[] strings = (String[]) sqlAnnotation.getClass().getMethod("value").invoke(sqlAnnotation);
307-
final StringBuilder sql = new StringBuilder();
308-
for (String fragment : strings) {
309-
sql.append(fragment);
310-
sql.append(" ");
311-
}
312-
ArrayList<SqlNode> contents = new ArrayList<SqlNode>();
313-
contents.add(new TextSqlNode(sql.toString()));
314-
MixedSqlNode rootSqlNode = new MixedSqlNode(contents);
315-
return new DynamicSqlSource(configuration, rootSqlNode);
331+
return buildSqlSourceFromStrings(strings);
316332
} else if (sqlProviderAnnotationType != null) {
317333
Annotation sqlProviderAnnotation = method.getAnnotation(sqlProviderAnnotationType);
318334
return new ProviderSqlSource(assistant.getConfiguration(), sqlProviderAnnotation);
@@ -323,6 +339,18 @@ private SqlSource getSqlSourceFromAnnotations(Method method) {
323339
}
324340
}
325341

342+
private SqlSource buildSqlSourceFromStrings(String[] strings) {
343+
final StringBuilder sql = new StringBuilder();
344+
for (String fragment : strings) {
345+
sql.append(fragment);
346+
sql.append(" ");
347+
}
348+
ArrayList<SqlNode> contents = new ArrayList<SqlNode>();
349+
contents.add(new TextSqlNode(sql.toString()));
350+
MixedSqlNode rootSqlNode = new MixedSqlNode(contents);
351+
return new DynamicSqlSource(configuration, rootSqlNode);
352+
}
353+
326354
private SqlCommandType getSqlCommandType(Method method) {
327355
Class<? extends Annotation> type = getSqlAnnotationType(method);
328356

@@ -431,4 +459,35 @@ private Arg[] argsIf(ConstructorArgs args) {
431459
return args == null ? new Arg[0] : args.value();
432460
}
433461

462+
private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, String baseStatementId, Class<?> parameterTypeClass) {
463+
String id = baseStatementId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
464+
Class<?> resultTypeClass = selectKeyAnnotation.resultType();
465+
StatementType statementType = selectKeyAnnotation.statementType();
466+
String keyProperty = selectKeyAnnotation.keyProperty();
467+
boolean executeBefore = selectKeyAnnotation.before();
468+
469+
// defaults
470+
boolean useCache = false;
471+
KeyGenerator keyGenerator = new NoKeyGenerator();
472+
Integer fetchSize = null;
473+
Integer timeout = null;
474+
boolean flushCache = false;
475+
String parameterMap = null;
476+
String resultMap = null;
477+
ResultSetType resultSetTypeEnum = null;
478+
479+
SqlSource sqlSource = buildSqlSourceFromStrings(selectKeyAnnotation.statement());
480+
SqlCommandType sqlCommandType = SqlCommandType.SELECT;
481+
482+
assistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
483+
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
484+
resultSetTypeEnum, flushCache, useCache, keyGenerator, keyProperty);
485+
486+
id = assistant.applyCurrentNamespace(id);
487+
488+
MappedStatement keyStatement = configuration.getMappedStatement(id);
489+
SelectKeyGenerator answer = new SelectKeyGenerator(keyStatement, executeBefore);
490+
configuration.addKeyGenerator(id, answer);
491+
return answer;
492+
}
434493
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.apache.ibatis.submitted.selectkey;
2+
3+
import org.apache.ibatis.annotations.Insert;
4+
import org.apache.ibatis.annotations.SelectKey;
5+
6+
public interface AnnotatedMapper {
7+
8+
@Insert("insert into table2 (name) values(#{name})")
9+
@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
10+
int insertTable2(Name name);
11+
12+
@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
13+
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
14+
int insertTable3(Name name);
15+
}

src/test/java/org/apache/ibatis/submitted/selectkey/CreateDB.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
drop sequence if exists TestSequence;
2+
drop table if exists table1;
3+
drop table if exists table2;
4+
drop table if exists table3;
5+
16
create table table1 (
27
id int generated by default as identity (start with 11) not null,
38
name varchar(20)
@@ -7,3 +12,10 @@ create table table2 (
712
id int generated by default as identity (start with 22) not null,
813
name varchar(20)
914
);
15+
16+
create sequence TestSequence as integer start with 33;
17+
18+
create table table3 (
19+
id int not null,
20+
name varchar(20)
21+
);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.apache.ibatis.submitted.selectkey;
2+
3+
public class Name {
4+
private int nameId;
5+
private String name;
6+
public String getName() {
7+
return name;
8+
}
9+
public void setName(String name) {
10+
this.name = name;
11+
}
12+
public int getNameId() {
13+
return nameId;
14+
}
15+
public void setNameId(int nameId) {
16+
this.nameId = nameId;
17+
}
18+
}

src/test/java/org/apache/ibatis/submitted/selectkey/SelectKeyTest.java

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
88
import static org.junit.Assert.assertEquals;
99
import static org.junit.Assert.assertNotNull;
10-
import org.junit.BeforeClass;
10+
11+
import org.junit.Before;
1112
import org.junit.Test;
1213

13-
import java.io.PrintWriter;
1414
import java.io.Reader;
1515
import java.sql.Connection;
1616
import java.sql.DriverManager;
@@ -21,8 +21,8 @@ public class SelectKeyTest {
2121

2222
protected static SqlSessionFactory sqlSessionFactory;
2323

24-
@BeforeClass
25-
public static void setUp() throws Exception {
24+
@Before
25+
public void setUp() throws Exception {
2626
Connection conn = null;
2727

2828
try {
@@ -42,6 +42,7 @@ public static void setUp() throws Exception {
4242
reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/selectkey/MapperConfig.xml");
4343
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
4444
reader.close();
45+
sqlSessionFactory.getConfiguration().addMapper(AnnotatedMapper.class);
4546
} finally {
4647
if (conn != null) {
4748
conn.close();
@@ -65,7 +66,7 @@ public void testInsertTable1() {
6566
SqlSession sqlSession = sqlSessionFactory.openSession();
6667

6768
try {
68-
Map parms = new HashMap();
69+
Map<String, String> parms = new HashMap<String, String>();
6970
parms.put("name", "Fred");
7071
int rows = sqlSession.insert("org.apache.ibatis.submitted.selectkey.Table1.insert", parms);
7172
assertEquals(1, rows);
@@ -81,7 +82,7 @@ public void testInsertTable2() {
8182
SqlSession sqlSession = sqlSessionFactory.openSession();
8283

8384
try {
84-
Map parms = new HashMap();
85+
Map<String, String> parms = new HashMap<String, String>();
8586
parms.put("name", "Fred");
8687
int rows = sqlSession.insert("org.apache.ibatis.submitted.selectkey.Table2.insert", parms);
8788
assertEquals(1, rows);
@@ -91,5 +92,36 @@ public void testInsertTable2() {
9192
sqlSession.close();
9293
}
9394
}
95+
96+
@Test
97+
public void testAnnotatedInsertTable2() {
98+
SqlSession sqlSession = sqlSessionFactory.openSession();
99+
100+
try {
101+
Name name = new Name();
102+
name.setName("barney");
103+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
104+
int rows = mapper.insertTable2(name);
105+
assertEquals(1, rows);
106+
assertEquals(22, name.getNameId());
107+
} finally {
108+
sqlSession.close();
109+
}
110+
}
94111

112+
@Test
113+
public void testAnnotatedInsertTable3() {
114+
SqlSession sqlSession = sqlSessionFactory.openSession();
115+
116+
try {
117+
Name name = new Name();
118+
name.setName("barney");
119+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
120+
int rows = mapper.insertTable3(name);
121+
assertEquals(1, rows);
122+
assertEquals(33, name.getNameId());
123+
} finally {
124+
sqlSession.close();
125+
}
126+
}
95127
}

0 commit comments

Comments
 (0)