Skip to content

Commit ae29f48

Browse files
committed
Merge pull request #557 from sbrannen/SPR-7655
Introduce annotation to execute SQL scripts in the TCF
2 parents 8fb0f5c + 5fd6ebb commit ae29f48

File tree

37 files changed

+1912
-128
lines changed

37 files changed

+1912
-128
lines changed

spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.core.io.Resource;
2727
import org.springframework.core.io.support.EncodedResource;
2828
import org.springframework.util.Assert;
29+
import org.springframework.util.StringUtils;
2930

3031
/**
3132
* Populates, initializes, or cleans up a database using SQL scripts defined in
@@ -95,7 +96,7 @@ public ResourceDatabasePopulator(Resource... scripts) {
9596
* @param ignoreFailedDrops flag to indicate that a failed SQL {@code DROP}
9697
* statement can be ignored
9798
* @param sqlScriptEncoding the encoding for the supplied SQL scripts, if
98-
* different from the platform encoding; may be {@code null}
99+
* different from the platform encoding; may be {@code null} or empty
99100
* @param scripts the scripts to execute to initialize or populate the database;
100101
* never {@code null}
101102
* @since 4.0.3
@@ -105,7 +106,7 @@ public ResourceDatabasePopulator(boolean continueOnError, boolean ignoreFailedDr
105106
this(scripts);
106107
this.continueOnError = continueOnError;
107108
this.ignoreFailedDrops = ignoreFailedDrops;
108-
this.sqlScriptEncoding = sqlScriptEncoding;
109+
setSqlScriptEncoding(sqlScriptEncoding);
109110
}
110111

111112
/**
@@ -143,7 +144,7 @@ public void setScripts(Resource... scripts) {
143144
* @see #addScript(Resource)
144145
*/
145146
public void setSqlScriptEncoding(String sqlScriptEncoding) {
146-
this.sqlScriptEncoding = sqlScriptEncoding;
147+
this.sqlScriptEncoding = StringUtils.hasText(sqlScriptEncoding) ? sqlScriptEncoding : null;
147148
}
148149

149150
/**
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
* Copyright 2002-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.jdbc;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.Inherited;
21+
import java.lang.annotation.Repeatable;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.Target;
24+
25+
import org.springframework.jdbc.datasource.init.ScriptUtils;
26+
import org.springframework.util.ResourceUtils;
27+
28+
import static java.lang.annotation.ElementType.*;
29+
import static java.lang.annotation.RetentionPolicy.*;
30+
31+
/**
32+
* {@code @DatabaseInitializer} is used to annotate a test class or test method
33+
* to configure SQL scripts to be executed against a given database during
34+
* integration tests.
35+
*
36+
* <p>Method-level declarations override class-level declarations.
37+
*
38+
* <p>Script execution is performed by the {@link DatabaseInitializerTestExecutionListener},
39+
* which is enabled by default.
40+
*
41+
* <p>The configuration options provided by this annotation are a superset of
42+
* those provided by the {@code <jdbc:initialize-database />} XML namespace
43+
* element. Consult the Javadoc of individual attributes for details.
44+
*
45+
* <p>Beginning with Java 8, {@code @DatabaseInitializer} can be used as a
46+
* <em>{@linkplain Repeatable repeatable}</em> annotation. Otherwise,
47+
* {@link DatabaseInitializers @DatabaseInitializers} can be used as an explicit
48+
* container for declaring multiple instances of {@code @DatabaseInitializer}.
49+
*
50+
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
51+
* <em>composed annotations</em>; however, attribute overrides are not currently
52+
* supported for {@linkplain Repeatable repeatable} annotations that are used as
53+
* meta-annotations.
54+
*
55+
* @author Sam Brannen
56+
* @author Tadaya Tsuyukubo
57+
* @since 4.1
58+
* @see DatabaseInitializers
59+
* @see DatabaseInitializerTestExecutionListener
60+
* @see org.springframework.transaction.annotation.Transactional
61+
* @see org.springframework.test.context.transaction.TransactionalTestExecutionListener
62+
* @see org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
63+
* @see org.springframework.jdbc.datasource.init.ScriptUtils
64+
*/
65+
@Documented
66+
@Inherited
67+
@Retention(RUNTIME)
68+
@Target({ TYPE, METHOD })
69+
@Repeatable(DatabaseInitializers.class)
70+
public @interface DatabaseInitializer {
71+
72+
/**
73+
* Enumeration of <em>phases</em> that dictate when SQL scripts are executed.
74+
*/
75+
static enum ExecutionPhase {
76+
77+
/**
78+
* The configured SQL scripts will be executed <em>before</em> the
79+
* corresponding test method.
80+
*/
81+
BEFORE_TEST_METHOD,
82+
83+
/**
84+
* The configured SQL scripts will be executed <em>after</em> the
85+
* corresponding test method.
86+
*/
87+
AFTER_TEST_METHOD;
88+
}
89+
90+
91+
/**
92+
* Alias for {@link #scripts}.
93+
* <p>This attribute may <strong>not</strong> be used in conjunction with
94+
* {@link #scripts}, but it may be used instead of {@link #scripts}.
95+
*/
96+
String[] value() default {};
97+
98+
/**
99+
* The paths to the SQL scripts to execute.
100+
*
101+
* <p>This attribute may <strong>not</strong> be used in conjunction with
102+
* {@link #value}, but it may be used instead of {@link #value}.
103+
*
104+
* <h3>Path Resource Semantics</h3>
105+
* <p>Each path will be interpreted as a Spring
106+
* {@link org.springframework.core.io.Resource Resource}. A plain path
107+
* &mdash; for example, {@code "schema.sql"} &mdash; will be treated as a
108+
* classpath resource that is <em>relative</em> to the package in which the
109+
* test class is defined. A path starting with a slash will be treated as an
110+
* <em>absolute</em> classpath resource, for example:
111+
* {@code "/org/example/schema.sql"}. A path which references a
112+
* URL (e.g., a path prefixed with
113+
* {@link ResourceUtils#CLASSPATH_URL_PREFIX classpath:},
114+
* {@link ResourceUtils#FILE_URL_PREFIX file:}, {@code http:}, etc.) will be
115+
* loaded using the specified resource protocol.
116+
*
117+
* <h3>Default Script Detection</h3>
118+
* <p>If no SQL scripts are specified, an attempt will be made to detect a
119+
* <em>default</em> script depending on where this annotation is declared.
120+
* If a default cannot be detected, an {@link IllegalStateException} will be
121+
* thrown.
122+
* <ul>
123+
* <li><strong>class-level declaration</strong>: if the annotated test class
124+
* is {@code com.example.MyTest}, the corresponding default script is
125+
* {@code "classpath:com/example/MyTest.sql"}.</li>
126+
* <li><strong>method-level declaration</strong>: if the annotated test
127+
* method is named {@code testMethod()} and is defined in the class
128+
* {@code com.example.MyTest}, the corresponding default script is
129+
* {@code "classpath:com/example/MyTest.testMethod.sql"}.</li>
130+
* </ul>
131+
*/
132+
String[] scripts() default {};
133+
134+
/**
135+
* The encoding for the supplied SQL scripts, if different from the platform
136+
* encoding.
137+
* <p>An empty string denotes that the platform encoding should be used.
138+
*/
139+
String encoding() default "";
140+
141+
/**
142+
* The bean name of the {@link javax.sql.DataSource} against which the scripts
143+
* should be executed.
144+
* <p>The name is only used if there is more than one bean of type
145+
* {@code DataSource} in the test's {@code ApplicationContext}. If there is
146+
* only one such bean, it is not necessary to specify a bean name.
147+
* <p>Defaults to an empty string, requiring that one of the following is
148+
* true:
149+
* <ol>
150+
* <li>There is only one bean of type {@code DataSource} in the test's
151+
* {@code ApplicationContext}.</li>
152+
* <li>The {@code DataSource} to use is named {@code "dataSource"}.</li>
153+
* </ol>
154+
*/
155+
String dataSource() default "";
156+
157+
/**
158+
* The bean name of the {@link org.springframework.transaction.PlatformTransactionManager
159+
* PlatformTransactionManager} that should be used to drive transactions.
160+
* <p>The name is only used if there is more than one bean of type
161+
* {@code PlatformTransactionManager} in the test's {@code ApplicationContext}.
162+
* If there is only one such bean, it is not necessary to specify a bean name.
163+
* <p>Defaults to an empty string, requiring that one of the following is
164+
* true:
165+
* <ol>
166+
* <li>There is only one bean of type {@code PlatformTransactionManager} in
167+
* the test's {@code ApplicationContext}.</li>
168+
* <li>{@link org.springframework.transaction.annotation.TransactionManagementConfigurer
169+
* TransactionManagementConfigurer} has been implemented to specify which
170+
* {@code PlatformTransactionManager} bean should be used for annotation-driven
171+
* transaction management.</li>
172+
* <li>The {@code PlatformTransactionManager} to use is named
173+
* {@code "transactionManager"}.</li>
174+
* </ol>
175+
*/
176+
String transactionManager() default "";
177+
178+
/**
179+
* Flag to indicate that the SQL scripts must be executed in a new transaction.
180+
* <p>Defaults to {@code false}, meaning that the SQL scripts will be executed
181+
* within the current transaction if present. The <em>current</em> transaction
182+
* will typically be managed by the
183+
* {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener
184+
* TransactionalTestExecutionListener}.
185+
* <p>Can be set to {@code true} to ensure that the scripts are executed in
186+
* a new, isolated transaction that will be immediately committed.
187+
*/
188+
boolean requireNewTransaction() default false;
189+
190+
/**
191+
* The character string used to separate individual statements within the
192+
* SQL scripts.
193+
* <p>Defaults to {@code ";"} if not specified and falls back to {@code "\n"}
194+
* as a last resort; may be set to {@link ScriptUtils#EOF_STATEMENT_SEPARATOR}
195+
* to signal that each script contains a single statement without a separator.
196+
*/
197+
String separator() default ScriptUtils.DEFAULT_STATEMENT_SEPARATOR;
198+
199+
/**
200+
* The prefix that identifies single-line comments within the SQL scripts.
201+
* <p>Defaults to {@code "--"}.
202+
*/
203+
String commentPrefix() default ScriptUtils.DEFAULT_COMMENT_PREFIX;
204+
205+
/**
206+
* The start delimiter that identifies block comments within the SQL scripts.
207+
* <p>Defaults to {@code "/*"}.
208+
* @see #blockCommentEndDelimiter
209+
*/
210+
String blockCommentStartDelimiter() default ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER;
211+
212+
/**
213+
* The end delimiter that identifies block comments within the SQL scripts.
214+
* <p>Defaults to <code>"*&#47;"</code>.
215+
* @see #blockCommentStartDelimiter
216+
*/
217+
String blockCommentEndDelimiter() default ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER;
218+
219+
/**
220+
* Flag to indicate that all failures in SQL should be logged but not cause
221+
* a failure.
222+
* <p>Defaults to {@code false}.
223+
* @see #ignoreFailedDrops
224+
*/
225+
boolean continueOnError() default false;
226+
227+
/**
228+
* Flag to indicate that a failed SQL {@code DROP} statement can be ignored.
229+
* <p>This is useful for a non-embedded database whose SQL dialect does not
230+
* support an {@code IF EXISTS} clause in a {@code DROP} statement.
231+
* <p>The default is {@code false} so that if a script is accidentally
232+
* executed, it will fail fast if the script starts with a {@code DROP}
233+
* statement.
234+
* @see #continueOnError
235+
*/
236+
boolean ignoreFailedDrops() default false;
237+
238+
/**
239+
* When the SQL scripts should be executed.
240+
* <p>Defaults to {@link ExecutionPhase#BEFORE_TEST_METHOD BEFORE_TEST_METHOD}.
241+
*/
242+
ExecutionPhase executionPhase() default ExecutionPhase.BEFORE_TEST_METHOD;
243+
244+
}

0 commit comments

Comments
 (0)