From 621ecd390154b6897edc4282ebe04979c3d686a5 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 13 Sep 2013 07:25:42 -0700 Subject: [PATCH] Added JDBC and @Transactional support to Groovy CLI * @EnableTransactionManagement triggers spring-tx imports * Field or method of type JdbcTemplate or NamedParameterJdbcTemplate of DataSource triggers spring-jdbc imports --- spring-boot-cli/samples/tx.groovy | 18 ++++++ .../boot/cli/compiler/AstUtils.java | 34 ++++++++++++ .../JdbcCompilerAutoConfiguration.java | 52 ++++++++++++++++++ .../SpringBootCompilerAutoConfiguration.java | 2 +- ...onManagementCompilerAutoConfiguration.java | 55 +++++++++++++++++++ ...oot.cli.compiler.CompilerAutoConfiguration | 2 + .../boot/cli/SampleIntegrationTests.java | 7 +++ .../src/test/resources/logback.xml | 2 +- .../src/test/resources/schema-all.sql | 4 ++ 9 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 spring-boot-cli/samples/tx.groovy create mode 100644 spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/JdbcCompilerAutoConfiguration.java create mode 100644 spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/TransactionManagementCompilerAutoConfiguration.java create mode 100644 spring-boot-cli/src/test/resources/schema-all.sql diff --git a/spring-boot-cli/samples/tx.groovy b/spring-boot-cli/samples/tx.groovy new file mode 100644 index 0000000000..a9b98fa719 --- /dev/null +++ b/spring-boot-cli/samples/tx.groovy @@ -0,0 +1,18 @@ +package org.test + +@Grab("org.hsqldb:hsqldb:2.2.9") + +@Configuration +@EnableTransactionManagement +class Example implements CommandLineRunner { + + @Autowired + JdbcTemplate jdbcTemplate + + @Transactional + void run(String... args) { + println "Foo count=" + jdbcTemplate.queryForObject("SELECT COUNT(*) from FOO", Integer) + } + +} + diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/AstUtils.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/AstUtils.java index 024e14c4d5..406ca862f3 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/AstUtils.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/AstUtils.java @@ -16,18 +16,28 @@ package org.springframework.boot.cli.compiler; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import org.codehaus.groovy.ast.AnnotatedNode; import org.codehaus.groovy.ast.AnnotationNode; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.FieldNode; +import org.codehaus.groovy.ast.MethodNode; /** * General purpose AST utilities. * * @author Phillip Webb + * @author Dave Syer */ public abstract class AstUtils { /** * Determine if an {@link AnnotatedNode} has one or more of the specified annotations. + * N.B. the annotation type names are not normally fully qualified. */ public static boolean hasAtLeastOneAnnotation(AnnotatedNode node, String... annotations) { @@ -43,4 +53,28 @@ public abstract class AstUtils { } + /** + * Determine if an {@link ClassNode} has one or more fields of the specified types or + * method returning one or more of the specified types. N.B. the type names are not + * normally fully qualified. + */ + public static boolean hasAtLeastOneFieldOrMethod(ClassNode node, String... types) { + + Set set = new HashSet(Arrays.asList(types)); + List fields = node.getFields(); + for (FieldNode field : fields) { + if (set.contains(field.getType().getName())) { + return true; + } + } + List methods = node.getMethods(); + for (MethodNode method : methods) { + if (set.contains(method.getReturnType().getName())) { + return true; + } + } + return false; + + } + } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/JdbcCompilerAutoConfiguration.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/JdbcCompilerAutoConfiguration.java new file mode 100644 index 0000000000..4ad44195f7 --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/JdbcCompilerAutoConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.cli.compiler.autoconfigure; + +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.control.customizers.ImportCustomizer; +import org.springframework.boot.cli.compiler.AstUtils; +import org.springframework.boot.cli.compiler.CompilerAutoConfiguration; +import org.springframework.boot.cli.compiler.DependencyCustomizer; + +/** + * {@link CompilerAutoConfiguration} for Spring JDBC. + * + * @author Dave Syer + */ +public class JdbcCompilerAutoConfiguration extends CompilerAutoConfiguration { + + @Override + public void applyDependencies(DependencyCustomizer dependencies) { + dependencies.ifAnyMissingClasses("org.springframework.jdbc.core.JdbcTemplate") + .add("org.springframework.boot", "spring-boot-starter-jdbc", + dependencies.getProperty("spring-boot.version")); + } + + @Override + public boolean matches(ClassNode classNode) { + return AstUtils.hasAtLeastOneFieldOrMethod(classNode, "JdbcTemplate", + "NamedParameterJdbcTemplate", "DataSource"); + } + + @Override + public void applyImports(ImportCustomizer imports) { + imports.addStarImports("org.springframework.jdbc.core", + "org.springframework.jdbc.core.namedparam"); + imports.addImports("javax.sql.DataSource"); + } + +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/SpringBootCompilerAutoConfiguration.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/SpringBootCompilerAutoConfiguration.java index 6d63f888c9..00cf78920e 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/SpringBootCompilerAutoConfiguration.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/SpringBootCompilerAutoConfiguration.java @@ -45,7 +45,7 @@ public class SpringBootCompilerAutoConfiguration extends CompilerAutoConfigurati @Override public void applyImports(ImportCustomizer imports) { - imports.addImports("javax.sql.DataSource", "javax.annotation.PostConstruct", + imports.addImports("javax.annotation.PostConstruct", "javax.annotation.PreDestroy", "groovy.util.logging.Log", "org.springframework.stereotype.Controller", "org.springframework.stereotype.Service", diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/TransactionManagementCompilerAutoConfiguration.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/TransactionManagementCompilerAutoConfiguration.java new file mode 100644 index 0000000000..46906d84eb --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/autoconfigure/TransactionManagementCompilerAutoConfiguration.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.cli.compiler.autoconfigure; + +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.control.customizers.ImportCustomizer; +import org.springframework.boot.cli.compiler.AstUtils; +import org.springframework.boot.cli.compiler.CompilerAutoConfiguration; +import org.springframework.boot.cli.compiler.DependencyCustomizer; + +/** + * {@link CompilerAutoConfiguration} for Spring MVC. + * + * @author Dave Syer + * @author Phillip Webb + */ +public class TransactionManagementCompilerAutoConfiguration extends + CompilerAutoConfiguration { + + @Override + public void applyDependencies(DependencyCustomizer dependencies) { + dependencies.ifAnyMissingClasses( + "org.springframework.transaction.annotation.Transactional").add( + "org.springframework", "spring-tx", + dependencies.getProperty("spring.version")); + } + + @Override + public boolean matches(ClassNode classNode) { + return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableTransactionManagement"); + } + + @Override + public void applyImports(ImportCustomizer imports) { + imports.addStarImports("org.springframework.transaction.annotation", + "org.springframework.transaction.support"); + imports.addImports("org.springframework.transaction.PlatformTransactionManager", + "org.springframework.transaction.support.AbstractPlatformTransactionManager"); + } + +} diff --git a/spring-boot-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.CompilerAutoConfiguration b/spring-boot-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.CompilerAutoConfiguration index 6154a02032..ac2b474d5b 100644 --- a/spring-boot-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.CompilerAutoConfiguration +++ b/spring-boot-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.CompilerAutoConfiguration @@ -2,5 +2,7 @@ org.springframework.boot.cli.compiler.autoconfigure.SpringBootCompilerAutoConfig org.springframework.boot.cli.compiler.autoconfigure.SpringMvcCompilerAutoConfiguration org.springframework.boot.cli.compiler.autoconfigure.SpringBatchCompilerAutoConfiguration org.springframework.boot.cli.compiler.autoconfigure.ReactorCompilerAutoConfiguration +org.springframework.boot.cli.compiler.autoconfigure.JdbcCompilerAutoConfiguration +org.springframework.boot.cli.compiler.autoconfigure.TransactionManagementCompilerAutoConfiguration org.springframework.boot.cli.compiler.autoconfigure.SpringIntegrationCompilerAutoConfiguration org.springframework.boot.cli.compiler.autoconfigure.SpringSecurityCompilerAutoConfiguration diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/SampleIntegrationTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/SampleIntegrationTests.java index 8c398c8964..f0fae17ea7 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/SampleIntegrationTests.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/SampleIntegrationTests.java @@ -178,4 +178,11 @@ public class SampleIntegrationTests { assertTrue("Wrong output: " + output, output.contains("Hello World")); } + @Test + public void txSample() throws Exception { + start("samples/app.xml", "samples/tx.groovy"); + String output = this.outputCapture.getOutputAndRelease(); + assertTrue("Wrong output: " + output, output.contains("Foo count=")); + } + } diff --git a/spring-boot-cli/src/test/resources/logback.xml b/spring-boot-cli/src/test/resources/logback.xml index c0f98c6ae8..ab0a65c9a9 100644 --- a/spring-boot-cli/src/test/resources/logback.xml +++ b/spring-boot-cli/src/test/resources/logback.xml @@ -1,5 +1,5 @@ - + diff --git a/spring-boot-cli/src/test/resources/schema-all.sql b/spring-boot-cli/src/test/resources/schema-all.sql new file mode 100644 index 0000000000..38de881057 --- /dev/null +++ b/spring-boot-cli/src/test/resources/schema-all.sql @@ -0,0 +1,4 @@ +CREATE TABLE FOO ( + id INTEGER IDENTITY PRIMARY KEY, + name VARCHAR(30), +); \ No newline at end of file