From 8569785fdcf28581f9105de5423df636b387e242 Mon Sep 17 00:00:00 2001 From: Thibaud Lepretre Date: Wed, 26 Jun 2019 10:06:58 +0200 Subject: [PATCH] Create spring boot starter with spring factory --- gradle.properties | 3 +- .../build.gradle | 19 ++++++++++ .../PicocliAutoConfiguration.java | 24 ++++++++++++ .../autoconfigure/SpringPicocliFactory.java | 37 +++++++++++++++++++ picocli-spring-boot-starter/build.gradle | 17 +++++++++ .../main/resources/META-INF/spring.provides | 1 + settings.gradle | 3 ++ 7 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 picocli-spring-boot-autoconfigure/build.gradle create mode 100644 picocli-spring-boot-autoconfigure/src/main/java/picocli/spring/boot/autoconfigure/PicocliAutoConfiguration.java create mode 100644 picocli-spring-boot-autoconfigure/src/main/java/picocli/spring/boot/autoconfigure/SpringPicocliFactory.java create mode 100644 picocli-spring-boot-starter/build.gradle create mode 100644 picocli-spring-boot-starter/src/main/resources/META-INF/spring.provides diff --git a/gradle.properties b/gradle.properties index db546335..4e06bd50 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,6 +10,7 @@ jlineVersion = 2.14.6 jline3Version = 3.9.0 junitDepVersion = 4.11 junitVersion = 4.12 +springBootVersion = 2.1.6.RELEASE # projectPreviousReleaseVersion is non-SNAPSHOT, only published releases projectPreviousReleaseVersion = 4\\.0\\.0-beta-2 @@ -20,4 +21,4 @@ projectVersion = 4.0.0-rc-1-SNAPSHOT releaseDate = 2019-06-20 releaseDatePreviousRegex = 2019\\-06\\-20 -systemRulesVersion = 1.17.1 \ No newline at end of file +systemRulesVersion = 1.17.1 diff --git a/picocli-spring-boot-autoconfigure/build.gradle b/picocli-spring-boot-autoconfigure/build.gradle new file mode 100644 index 00000000..005c0063 --- /dev/null +++ b/picocli-spring-boot-autoconfigure/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java' +} + +group 'info.picocli' +version '4.0.0-rc-1-SNAPSHOT' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + compile rootProject + compile (group: 'org.springframework.boot', name: 'spring-boot-starter', version: "$springBootVersion" ) + compileOnly("org.springframework.boot:spring-boot-configuration-processor:$springBootVersion") + testCompile group: 'junit', name: 'junit', version: '4.12' +} diff --git a/picocli-spring-boot-autoconfigure/src/main/java/picocli/spring/boot/autoconfigure/PicocliAutoConfiguration.java b/picocli-spring-boot-autoconfigure/src/main/java/picocli/spring/boot/autoconfigure/PicocliAutoConfiguration.java new file mode 100644 index 00000000..3c5d6e3d --- /dev/null +++ b/picocli-spring-boot-autoconfigure/src/main/java/picocli/spring/boot/autoconfigure/PicocliAutoConfiguration.java @@ -0,0 +1,24 @@ +package picocli.spring.boot.autoconfigure; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import picocli.CommandLine; + +/** + * @author Thibaud LeprĂȘtre + */ +@Configuration +@ConditionalOnClass(CommandLine.class) +public class PicocliAutoConfiguration { + + @Bean + @ConditionalOnMissingBean(CommandLine.IFactory.class) + CommandLine.IFactory springPicocliFactory(ApplicationContext applicationContext) { + return new SpringPicocliFactory(applicationContext); + } + + +} diff --git a/picocli-spring-boot-autoconfigure/src/main/java/picocli/spring/boot/autoconfigure/SpringPicocliFactory.java b/picocli-spring-boot-autoconfigure/src/main/java/picocli/spring/boot/autoconfigure/SpringPicocliFactory.java new file mode 100644 index 00000000..eeec0c6b --- /dev/null +++ b/picocli-spring-boot-autoconfigure/src/main/java/picocli/spring/boot/autoconfigure/SpringPicocliFactory.java @@ -0,0 +1,37 @@ +package picocli.spring.boot.autoconfigure; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; +import picocli.CommandLine; + +/** + * @author Thibaud LeprĂȘtre + */ +public class SpringPicocliFactory implements CommandLine.IFactory { + private static final Logger logger = LoggerFactory.getLogger(SpringPicocliFactory.class); + + private final ApplicationContext applicationContext; + + public SpringPicocliFactory(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Override + public K create(Class clazz) throws Exception { + try { + return getBeanOrCreate(clazz); + } catch (Exception e) { + logger.warn("unable to get bean of class {}, use default Picocli factory creation", clazz); + return CommandLine.defaultFactory().create(clazz); + } + } + + private K getBeanOrCreate(Class clazz) { + try { + return applicationContext.getBean(clazz); + } catch (Exception e) { + return applicationContext.getAutowireCapableBeanFactory().createBean(clazz); + } + } +} diff --git a/picocli-spring-boot-starter/build.gradle b/picocli-spring-boot-starter/build.gradle new file mode 100644 index 00000000..ccc350f2 --- /dev/null +++ b/picocli-spring-boot-starter/build.gradle @@ -0,0 +1,17 @@ +plugins { + id 'java' +} + +group 'info.picocli' +version '4.0.0-rc-1-SNAPSHOT' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + compile (group: 'org.springframework.boot', name: 'spring-boot-starter', version: '2.1.6.RELEASE' ) + compileOnly("org.springframework.boot:spring-boot-configuration-processor:2.1.6.RELEASE") +} diff --git a/picocli-spring-boot-starter/src/main/resources/META-INF/spring.provides b/picocli-spring-boot-starter/src/main/resources/META-INF/spring.provides new file mode 100644 index 00000000..06237372 --- /dev/null +++ b/picocli-spring-boot-starter/src/main/resources/META-INF/spring.provides @@ -0,0 +1 @@ +provides: picocli diff --git a/settings.gradle b/settings.gradle index 37fa9adb..29448df9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,3 +10,6 @@ if (org.gradle.api.JavaVersion.current().isJava8Compatible()) { } else { println("Excluding module picocli-annotation-processing-tests from the build: they require Java 8 but we have Java version ${org.gradle.api.JavaVersion.current()}") } +include 'picocli-spring-boot-starter' +include 'picocli-spring-boot-autoconfigure' +