Skip to content

Commit 307321f

Browse files
Spring Boot Starter Modules (#5)
* Skeleton for WebMVC Spring Boot auto configuration. * Add support for package scanning in webmvc auto configuration. * Add webflux auto configuration module. * Polishing * Move conditional to class level. Add dependency to platform. * Add some unit tests for auto configuration. * Add header. * Use starter dependency. * Use ObjectProvider instead of Optional. * Update Spring versions.
1 parent 6bfe8ff commit 307321f

File tree

10 files changed

+496
-2
lines changed

10 files changed

+496
-2
lines changed

build.gradle

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ plugins {
44
id 'org.sonarqube' version '2.8'
55
}
66

7-
def springVersion = '5.3.5'
7+
def springVersion = '5.3.8'
8+
def springBootVersion = '2.4.7'
89

910
ext {
1011
projectsWithCoverage = []
@@ -17,7 +18,8 @@ ext {
1718
ext.javadocLinks = [
1819
'https://docs.oracle.com/javase/8/docs/api/',
1920
'https://docs.oracle.com/javaee/7/api/',
20-
"https://docs.spring.io/spring/docs/$springVersion/javadoc-api/"
21+
"https://docs.spring.io/spring/docs/$springVersion/javadoc-api/",
22+
"https://docs.spring.io/spring-boot/docs/$springBootVersion/api/"
2123
] as String[]
2224

2325
subprojects {
@@ -38,6 +40,11 @@ subprojects {
3840
implementation platform('javax.servlet:javax.servlet-api:3.1.0')
3941
implementation platform('com.google.code.findbugs:jsr305:3.0.2')
4042

43+
constraints {
44+
implementation "org.springframework.boot:spring-boot-starter:$springBootVersion"
45+
implementation "org.springframework.boot:spring-boot-test:$springBootVersion"
46+
}
47+
4148
// Test
4249
implementation platform('org.junit:junit-bom:5.6.1')
4350
implementation platform('org.assertj:assertj-core:3.15.0')

settings.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ include 'spring-webmvc-annotated-data-binder'
44
include 'spring-webflux-annotated-data-binder'
55
include 'integration-tests'
66
include 'docs'
7+
include 'webmvc-annotated-data-binder-spring-boot-starter'
8+
include 'webflux-annotated-data-binder-spring-boot-starter'
9+
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
plugins {
2+
id 'java-library'
3+
id 'jacoco'
4+
id 'maven-publish'
5+
id 'signing'
6+
}
7+
8+
repositories {
9+
mavenCentral()
10+
}
11+
12+
dependencies {
13+
api project(':spring-webflux-annotated-data-binder')
14+
api 'org.springframework.boot:spring-boot-starter'
15+
16+
testImplementation 'org.junit.jupiter:junit-jupiter-api'
17+
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
18+
testImplementation 'org.assertj:assertj-core'
19+
testImplementation 'org.springframework.boot:spring-boot-test'
20+
}
21+
22+
jar {
23+
manifest {
24+
attributes(
25+
'Implementation-Title': project.name,
26+
'Implementation-Version': archiveVersion,
27+
'Automatic-Module-Name': 'com.mattbertolini.spring.web.reactive.bind.autoconfigure'
28+
)
29+
}
30+
}
31+
32+
jacocoTestReport {
33+
reports {
34+
xml.enabled true
35+
html.enabled true
36+
csv.enabled false
37+
}
38+
}
39+
40+
test.finalizedBy jacocoTestReport
41+
42+
projectsWithCoverage << project
43+
44+
java {
45+
withJavadocJar()
46+
withSourcesJar()
47+
}
48+
49+
publishing {
50+
repositories {
51+
maven {
52+
def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
53+
def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
54+
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
55+
credentials {
56+
username findProperty('sonatype.ossrh.username')
57+
password findProperty('sonatype.ossrh.password')
58+
}
59+
}
60+
}
61+
62+
publications {
63+
mavenJava(MavenPublication) {
64+
groupId = project.group
65+
artifactId = project.name
66+
version = project.version
67+
68+
from components.java
69+
70+
pom {
71+
name = 'Spring WebFlux Annotated Data Binder Spring Boot Starter'
72+
description = 'Spring Boot starter for Spring WebFlux Annotated Java Bean data binder'
73+
url = 'https://github.com/mattbertolini/spring-annotated-web-data-binder'
74+
developers {
75+
developer {
76+
name = 'Matt Bertolini'
77+
}
78+
}
79+
licenses {
80+
license {
81+
name = 'The Apache License, Version 2.0'
82+
url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
83+
}
84+
}
85+
scm {
86+
connection = 'scm:git:git://github.com/mattbertolini/spring-annotated-web-data-binder.git'
87+
developerConnection = 'scm:git:ssh://github.com/mattbertolini/spring-annotated-web-data-binder.git'
88+
url = 'https://github.com/mattbertolini/spring-annotated-web-data-binder'
89+
}
90+
}
91+
}
92+
}
93+
}
94+
95+
signing {
96+
sign publishing.publications.mavenJava
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2019-2021 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+
* https://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 com.mattbertolini.spring.web.reactive.bind.autoconfigure;
18+
19+
import com.mattbertolini.spring.web.reactive.bind.PropertyResolverRegistry;
20+
import com.mattbertolini.spring.web.reactive.bind.config.BinderConfiguration;
21+
import com.mattbertolini.spring.web.reactive.bind.resolver.RequestPropertyResolver;
22+
import org.springframework.beans.factory.BeanFactory;
23+
import org.springframework.beans.factory.ObjectProvider;
24+
import org.springframework.beans.factory.config.BeanDefinition;
25+
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
27+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
28+
import org.springframework.context.annotation.Bean;
29+
import org.springframework.context.annotation.Configuration;
30+
import org.springframework.context.annotation.Role;
31+
32+
import java.util.LinkedHashSet;
33+
import java.util.LinkedList;
34+
import java.util.List;
35+
import java.util.Optional;
36+
import java.util.Set;
37+
38+
@Configuration(proxyBeanMethods = false)
39+
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
40+
@ConditionalOnMissingBean(BinderConfiguration.class)
41+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
42+
public class WebFluxBinderAutoConfiguration {
43+
private final List<String> packagesToScan = new LinkedList<>();
44+
private final Set<RequestPropertyResolver> customResolvers = new LinkedHashSet<>();
45+
private final Set<PropertyResolverRegistry> propertyResolverRegistries = new LinkedHashSet<>();
46+
47+
public WebFluxBinderAutoConfiguration(BeanFactory beanFactory,
48+
ObjectProvider<List<RequestPropertyResolver>> customResolvers,
49+
ObjectProvider<List<PropertyResolverRegistry>> propertyResolverRegistries) {
50+
if (AutoConfigurationPackages.has(beanFactory)) {
51+
packagesToScan.addAll(AutoConfigurationPackages.get(beanFactory));
52+
}
53+
customResolvers.ifAvailable(this.customResolvers::addAll);
54+
propertyResolverRegistries.ifAvailable(this.propertyResolverRegistries::addAll);
55+
}
56+
57+
@Bean
58+
public BinderConfiguration binderConfiguration() {
59+
BinderConfiguration binderConfiguration = new BinderConfiguration();
60+
packagesToScan.forEach(binderConfiguration::addPackageToScan);
61+
binderConfiguration.addResolvers(customResolvers);
62+
propertyResolverRegistries.forEach(binderConfiguration::addResolvers);
63+
return binderConfiguration;
64+
}
65+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2+
com.mattbertolini.spring.web.reactive.bind.autoconfigure.WebFluxBinderAutoConfiguration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2019-2021 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+
* https://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 com.mattbertolini.spring.web.reactive.bind.autoconfigure;
18+
19+
import com.mattbertolini.spring.web.reactive.bind.config.BinderConfiguration;
20+
import org.junit.jupiter.api.Test;
21+
import org.springframework.boot.autoconfigure.AutoConfigurations;
22+
import org.springframework.boot.autoconfigure.SpringBootApplication;
23+
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.ComponentScan;
26+
import org.springframework.context.annotation.FilterType;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
30+
class WebFluxBinderAutoConfigurationTest {
31+
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
32+
.withConfiguration(AutoConfigurations.of(WebFluxBinderAutoConfiguration.class));
33+
34+
@Test
35+
void autoConfiguredWithPackagesToScan() {
36+
contextRunner.withUserConfiguration(EmptyConfig.class).run(context -> {
37+
assertThat(context).hasSingleBean(BinderConfiguration.class);
38+
BinderConfiguration binderConfiguration = context.getBean(BinderConfiguration.class);
39+
assertThat(binderConfiguration.getPackagesToScan()).hasSize(1)
40+
.contains(EmptyConfig.class.getPackage().getName());
41+
});
42+
}
43+
44+
@Test
45+
void noPackagesToScanWhenAutoConfigurationNotEnabled() {
46+
contextRunner.run(context -> {
47+
assertThat(context).hasSingleBean(BinderConfiguration.class);
48+
BinderConfiguration binderConfiguration = context.getBean(BinderConfiguration.class);
49+
assertThat(binderConfiguration.getPackagesToScan()).isEmpty();
50+
});
51+
}
52+
53+
@Test
54+
void overridesAutoConfigurationWhenBeanIsDefined() {
55+
contextRunner.withUserConfiguration(OverrideBeanDefinition.class).run(context -> {
56+
assertThat(context).hasSingleBean(BinderConfiguration.class);
57+
assertThat(context).getBean("customBinderConfig")
58+
.isEqualTo(context.getBean(BinderConfiguration.class));
59+
BinderConfiguration binderConfiguration = context.getBean(BinderConfiguration.class);
60+
assertThat(binderConfiguration.getPackagesToScan())
61+
.containsOnly("com.mattbertolini.override");
62+
});
63+
}
64+
65+
@SpringBootApplication(proxyBeanMethods = false)
66+
@ComponentScan(excludeFilters = {
67+
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = OverrideBeanDefinition.class)
68+
})
69+
private static class EmptyConfig {}
70+
71+
@SpringBootApplication(proxyBeanMethods = false)
72+
private static class OverrideBeanDefinition {
73+
@Bean
74+
public BinderConfiguration customBinderConfig() {
75+
return new BinderConfiguration().addPackageToScan("com.mattbertolini.override");
76+
}
77+
}
78+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
plugins {
2+
id 'java-library'
3+
id 'jacoco'
4+
id 'maven-publish'
5+
id 'signing'
6+
}
7+
8+
repositories {
9+
mavenCentral()
10+
}
11+
12+
dependencies {
13+
api project(':spring-webmvc-annotated-data-binder')
14+
api 'org.springframework.boot:spring-boot-starter'
15+
16+
testImplementation 'org.junit.jupiter:junit-jupiter-api'
17+
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
18+
testImplementation 'org.assertj:assertj-core'
19+
testImplementation 'org.springframework:spring-test'
20+
testImplementation 'org.springframework.boot:spring-boot-test'
21+
}
22+
23+
jar {
24+
manifest {
25+
attributes(
26+
'Implementation-Title': project.name,
27+
'Implementation-Version': archiveVersion,
28+
'Automatic-Module-Name': 'com.mattbertolini.spring.web.mvc.bind.autoconfigure'
29+
)
30+
}
31+
}
32+
33+
jacocoTestReport {
34+
reports {
35+
xml.enabled true
36+
html.enabled true
37+
csv.enabled false
38+
}
39+
}
40+
41+
test.finalizedBy jacocoTestReport
42+
43+
projectsWithCoverage << project
44+
45+
java {
46+
withJavadocJar()
47+
withSourcesJar()
48+
}
49+
50+
publishing {
51+
repositories {
52+
maven {
53+
def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
54+
def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
55+
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
56+
credentials {
57+
username findProperty('sonatype.ossrh.username')
58+
password findProperty('sonatype.ossrh.password')
59+
}
60+
}
61+
}
62+
63+
publications {
64+
mavenJava(MavenPublication) {
65+
groupId = project.group
66+
artifactId = project.name
67+
version = project.version
68+
69+
from components.java
70+
71+
pom {
72+
name = 'Spring MVC Annotated Data Binder Spring Boot Starter'
73+
description = 'Spring Boot starter for Spring MVC Annotated Java Bean data binder'
74+
url = 'https://github.com/mattbertolini/spring-annotated-web-data-binder'
75+
developers {
76+
developer {
77+
name = 'Matt Bertolini'
78+
}
79+
}
80+
licenses {
81+
license {
82+
name = 'The Apache License, Version 2.0'
83+
url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
84+
}
85+
}
86+
scm {
87+
connection = 'scm:git:git://github.com/mattbertolini/spring-annotated-web-data-binder.git'
88+
developerConnection = 'scm:git:ssh://github.com/mattbertolini/spring-annotated-web-data-binder.git'
89+
url = 'https://github.com/mattbertolini/spring-annotated-web-data-binder'
90+
}
91+
}
92+
}
93+
}
94+
}
95+
96+
signing {
97+
sign publishing.publications.mavenJava
98+
}

0 commit comments

Comments
 (0)