Spring Framework 4.1 is the latest release of the popular open source application framework for Java developers with continued innovation for Java SE 8 and enterprise Java. In this presentation core Spring committer Sam Brannen will provide attendees an overview of the new enterprise features in the framework as well as new programming models and testing features.
Specifically, this talk will cover support for annotation-driven JMS listeners, JMS 2.0's shared subscriptions, JCache (JSR-107) annotations, a compiler mode for the Spring Expression Language (SpEL), flexible resolution and transformation of static web resources, and Web MVC support for Groovy markup templates.
The presentation also provides an overview of Spring 4.1's refinements in other areas, for example: Java 8's Optional type for injection points, declarative MVC view resolution, Jackson's JsonView, WebSocket scope, SockJS client support, declarative SQL scripts and programmatic transactions in the TestContext framework, integration testing with Groovy scripts, and more.
2. Sam Brannen
• Spring and Java Consultant @ Swiftmind
• Java Developer for over 15 years
• Spring Framework Core Committer since 2007
• Component lead for spring-test
• Spring Trainer
• Speaker on Spring, Java, and testing
• Swiss Spring User Group Lead
2
3. Areas of expertise
– Spring *
– Java EE
– Software Architecture
– Software Engineering Best
Practices
Where you find us
• Zurich, Switzerland
• @swiftmind
• http://www.swiftmind.com
3
Your experts for Spring & Enterprise Java
8. Injection point with required flag
@Service
public class MyService {
@Autowired(required=false)
NotificationService notificationService;
public Book findBook(long id) {
if (notificationService != null) { /* ... */ }
}
}
8
before
9. Injection point with java.util.Optional
@Service
public class MyService {
@Autowired
Optional<NotificationService> notificationService;
public Book findBook(long id) {
notificationService.ifPresent(service -> /* ... */ );
}
}
9
after
10. @Order on Components (4.0)
@Service @Order(1)
public class ServiceA implements MyService { /* ... */ }
@Service @Order(2)
public class ServiceB implements MyService { /* ... */ }
@Autowired
List<MyService> myServices;
10
ServiceA is 1st
11. @Order on @Bean Methods (4.1)
@Bean @Order(1)
public MyService serviceA() { return new ServiceA(); }
@Bean @Order(2)
public MyService serviceB() { return new ServiceB(); }
@Autowired
List<MyService> myServices;
11
ServiceA is 1st
13. New Caching Features
• @CacheConfig
• common class-level configuration
• CacheResolver
• fine grained, programmatic cache resolution
• JCache (JSR-107)
• New putIfAbsent() method in Cache API
13
17. JCache (JSR 107) and Spring
• JCache 1.0 annotations now supported in Spring
• Integration based on Spring’s own Cache and CacheManager APIs
• JCacheCache and JCacheCacheManager
• Enabled via Spring’s standard mechanisms:
• XML: <cache:annotation-driven />
• Java: @EnableCaching
• Cache Abstraction: JCache (JSR-107) Annotations Support
• https://spring.io/blog/2014/04/14/cache-abstraction-jcache-jsr-107-annotations-support
17
28. ResponseBodyAdvice
• Callback for @ResponseBody / ResponseEntity methods
• just before the response is written (and committed)
• you can still modify headers
• or the object to be written to the response
• Two implementations already
• JsonViewResponseBodyAdvice
• AbstractJsonpResponseBodyAdvice
28
29. Jackson @JsonView Support
interface PublicView {}
class User {
@JsonView(PublicView.class)
String username;
String password;
// ...
}
29
@RestController
class UserController {
@RequestMapping("/user")
@JsonView(PublicView.class)
public User getUser() {
return new User("eric",
"7!#H2");
}
}
30. JSONP Support
• Simply declare as a Spring-managed component…
@ControllerAdvice
class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
super("callback");
}
}
30
Name of JSONP
query param(s)
31. HttpMessageConverter Additions
• Gson
• lighter footprint (vs Jackson); used in Spring Android
• Google Protocol Buffers
• effective inter-service communication data protocol
• Jackson / XML
• just add jackson-dataformat-xml to the classpath
31
32. Static Resource Handling in Web MVC
• ResourceTransformer API
• Transforms the content of a resource
• ResourceResolver API for resolving:
• Internal static resources
• External resource paths (i.e., links)
• ResourceResolverChain
• Maintains a chain of resolvers
• Allowing for delegation
• Configured via ResourceHandlerRegistry
• For example, via WebMvcConfigurationSupport
32
33. ResourceResolver Implementations
• PathResourceResolver
• simple path lookup under configured locations
• VersionResourceResolver
• resolution with version in URL path
• GzipResourceResolver
• lookup with .gz extension when “Accept-Encoding: gzip”
• CachingResourceResolver
• caching of resolved resource
33
34. ResourceTransformer Implementations
• CssLinkResourceTransformer
• update links in CSS file (e.g. insert version)
• AppCacheManifestTransformer
• update links in HTML5 AppCache manifest
• insert comment with content-based hash
• CachingResourceTransformer
• caching of transformed resource
34
35. Ex: Fingerprinting URLs w/ content-based version
boolean useResourceCache = !this.environment.acceptsProfiles("dev");
VersionResourceResolver resolver = new VersionResourceResolver();
resolver.addContentVersionStrategy("/**");
registry.addResourceHandler("/**").addResourceLocations(locations)
.resourceChain(useResourceCache).addResolver(resolver);
Example URL: “/css/font-awesome.min-7fbe76cdac.css”
35
36. Additional New Features in Spring MVC
• Groovy markup templates
• Declarative MVC view resolution
• Enhanced view controllers
• Linking to @RequestMapping methods
• See HandlerMethodMappingNamingStrategy
• ListenableFuture return type for handler methods
• ResponseEntity Builder API
• RequestEntity & RestTemplate.exchange()
36
38. Bootstrap Strategy & TestExecutionListeners
• TestContext bootstrap strategy
• TestContextBootstrapper & @BootstrapWith
• Automatic discovery of default TestExecutionListeners
• Uses SpringFactoriesLoader
• Already used by Spring Security
• Merging custom TestExecutionListeners with defaults
• @TestExecutionListeners(mergeMode=MERGE_WITH_DEFAULTS)
• Defaults to REPLACE_DEFAULTS
38
39. Spring MVC Test
• Assert JSON responses with JSON Assert
• Complements JSONPath support
• Create MockMvcBuilder recipes with MockMvcConfigurer
• Developed to apply Spring Security setup but can be used by anyone
• AsyncRestTemplate support in MockRestServiceServer
• For asynchronous client-side testing
39
40. Groovy Beans in Spring
• Spring Framework 4.0 introduced support for the Groovy Bean
Definition DSL via the GroovyBeanDefinitionReader and
GenericGroovyApplicationContext
• Spring Framework 4.1 introduces support for Groovy scripts in
web applications via the GroovyWebApplicationContext
• Testing support added in 4.1…
40
41. Groovy Scripts for Context Config in Tests
• Spring Framework 4.1 introduces support for Groovy scripts in
integration tests via @ContextConfiguration
• Scripts are configured via the locations or value attribute
o Resource semantics identical to XML
o Default detected with “Context.groovy” suffix in same package
• The inheritLocations flag is fully supported
• Groovy and XML configuration can be declared together
• Groovy WebApplicationContexts supported via
@WebAppConfiguration
41
42. Ex: Groovy Script Config
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/context.groovy")
public class GroovyPersonTests {
@Autowired
private Person person;
/* test methods using person bean */
}
42
43. Ex: Default Groovy Script Detection
public com.example;
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from
// “classpath:com/example/MyTestContext.groovy”
@ContextConfiguration
public class MyTest {
/* ... */
}
43
44. Ex: Groovy & XML Config Together
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from
// “/context.groovy” and “/context.xml”
@ContextConfiguration({ "/context.groovy", "/context.xml" })
public class MyTest {
/* ... */
}
44
45. Test Property Sources
• Spring 3.1 introduced PropertySources abstraction
• Configured via Environment or via @PropertySource
• Spring 4.1 supports declarative test property sources
• Configured via @TestPropertySource
• Test property sources are declared via annotation attributes
• locations or value: resource locations
• properties: inlined properties
• both are inherited by default
45
46. @TestPropertySource – locations
• String array of resource locations for Java Properties files
• Both traditional *.properties and XML formats are supported
• Resource semantics are identical to those for locations in
@ContextConfiguration
46
47. Ex: @TestPropertySource – locations
@ContextConfiguration
@TestPropertySource("/test.properties")
public class MyIntegrationTests {
// class body...
}
47
48. @TestPropertySource – properties
• Inlined properties can be declared as key/value pairs
• Uses syntax for entries in Java properties files:
• "key=value"
• "key:value"
• "key value"
48
49. Ex: @TestPropertySource – properties
@ContextConfiguration
@TestPropertySource(
properties = {"foo=bar", "port: 4242"}
)
public class MyIntegrationTests {
// class body...
}
49
50. Default Properties File Detection
• If neither locations nor properties are defined, a default properties
file will be detected
• Default is detected with “.properties” suffix in same package
• If the class is com.example.MyTest, the default properties file is
“classpath:com/example/MyTest.properties”
• Exception is thrown if default is not present
50
52. Ex: @TestPropertySource – locations & properties
@ContextConfiguration
@TestPropertySource(
locations = "/test.properties",
properties = "port: 4242"
)
public class MyIntegrationTests {
// class body...
}
52
53. Programmatic Transaction Management in Tests
• History Lesson: Spring’s JUnit 3.8 testing framework supported
endTransaction() and startNewTransaction() methods in
AbstractTransactionalSpringContextTests
• But… the Spring TestContext Framework, introduced in Spring
2.5, did not… until now
• Due to popular demand, Spring 4.1 introduces a new
TestTransaction API
53
54. Transactions in Spring
• Spring-managed transactions: managed by Spring in the
ApplicationContext
• @Transactional and AOP
• Application-managed transactions: managed programmatically within
application code
• TransactionTemplate and TransactionSynchronizationManager
• Test-managed transactions: managed by the Spring TestContext
Framework
• @Transactional on test classes and test methods
• Transaction is rolled back by default!
54
55. Ex: Declarative Transaction Management in Tests
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@Transactional
public class TransactionalTests {
@Test
public void withinTransaction() {
/* ... */
}
55
What if we want to
stop & start the
transaction within the
test method?
56. TestTransaction API
• Static methods for interacting with test-managed transactions
• isActive()
• isFlaggedForRollback()
• flagForCommit()
• flagForRollback()
• end()
• start()
56
query status
change default rollback setting
end: roll back or commit based on flag
start: new tx with default rollback setting
57. Ex: Programmatic Tx Management in Tests
@Test
public void withinTransaction() {
// assert initial state in test database:
assertNumUsers(2);
deleteFromTables("user");
// changes to the database will be committed
TestTransaction.flagForCommit();
TestTransaction.end();
assertFalse(TestTransaction.isActive());
assertNumUsers(0);
TestTransaction.start();
// perform other actions against the database that will
// be automatically rolled back after the test completes...
}
57
59. Ex: Embedded Database in Java Config
59
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(H2)
.setScriptEncoding("UTF-8")
.ignoreFailedDrops(true)
.addScript("schema.sql")
.addScripts("user_data.sql", "country_data.sql")
.build();
}
API greatly improved
in Spring 4.0.3
60. Ex: Embedded Database in XML Config
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:/schema.sql" />
<jdbc:script location="classpath:/user_data.sql" />
</jdbc:embedded-database>
60
62. Executing SQL per Test Method
• The previous techniques are very useful for setting up the initial
database state
• Q: But how can we execute SQL scripts per test method?
• A: Programmatically via ScriptUtils,
ResourceDatabasePopulator, or abstract transactional base test
classes for JUnit and TestNG.
• Q: OK, but how can we do that declaratively?
• A: Via @Sql in Spring Framework 4.1!
62
63. Executing SQL Scripts Declaratively with @Sql
• @Sql: declared on a test class or test method
• method-level overrides class-level
• The scripts attribute is used to declare resource locations for
SQL scripts
• semantics analogous to locations in @ContextConfiguration
• Scripts can be executed before or after a test method
• configured via the executionPhase attribute of @Sql
63
64. Ex: @Sql in Action
@ContextConfiguration
@Sql({ "schema1.sql", "data1.sql" })
public class SqlScriptsTests {
@Test
public void classLevelScripts() { /* ... */ }
@Test
@Sql({ "schema2.sql", "data2.sql" })
public void methodLevelScripts() { /* ... */ }
64
65. Default SQL Script Detection
• If no scripts are declared, a default script will be detected
• Depending on where @Sql is declared
• Class-level: for com.example.DbTest, the default is “classpath:com/
example/DbTest.sql”
• Method-level: for com.example.DbTest.test(), the default is
“classpath:com/example/DbTest.test.sql”
• If the default is not present, an exception is thrown
65
66. Declaring Multiple @Sql Sets
• Declare multiple sets of @Sql scripts for varying configuration
• Java 8: use @Sql as a repeatable annotation
• Java 6 & 7: wrap @Sql sets in @SqlGroup
66
67. @Sql as a Repeatable Annotation (Java 8)
67
@Test
@Sql(
scripts="/test-schema.sql",
config = @SqlConfig(commentPrefix = "`")
@Sql("/user-data.sql")
public void userTest() {
// code that uses the test schema and test data
}
Schema uses
custom syntax
68. @Sql wrapped in @SqlGroup (Java 6 & 7)
68
@Test
@SqlGroup({
@Sql(
scripts="/test-schema.sql",
config = @SqlConfig(commentPrefix = "`"),
@Sql("/user-data.sql")
})
public void userTest() {
// code that uses the test schema and test data
}
69. Configuring SQL Scripts with @SqlConfig
• @SqlConfig: configures script parsing and error handling
• Class-level: serves as global configuration for the test class
• @Sql(config): serves as local configuration for the enclosing @Sql
• Local configuration inherits global configuration and can
selectively override global configuration
• Transaction management for script execution is configured via
the dataSource, transactionManager, and transactionMode
attributes
• See Javadoc and reference manual for details
69
71. Spring Resources
Spring Framework: http://projects.spring.io/spring-framework
Spring Guides: http://spring.io/guides
Spring JIRA: https://jira.spring.io
Spring on GitHub: https://github.com/spring-projects/spring-framework
Stack Overflow: spring, spring-test, spring-mvc, …
71