parent
e112657e1a
commit
0555dda63d
@ -1,12 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@Grab("spring-boot-starter-actuator")
|
||||
|
||||
@RestController
|
||||
class SampleController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public def hello() {
|
||||
[message: "Hello World!"]
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@Component
|
||||
class Example implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
private MyService myService
|
||||
|
||||
void run(String... args) {
|
||||
println "Hello ${this.myService.sayWorld()} From ${getClass().getClassLoader().getResource('samples/app.groovy')}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Service
|
||||
class MyService {
|
||||
|
||||
String sayWorld() {
|
||||
return "World!"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
@RestController
|
||||
class Application {
|
||||
|
||||
@Autowired
|
||||
String foo
|
||||
|
||||
@RequestMapping("/")
|
||||
String home() {
|
||||
"Hello ${foo}!"
|
||||
}
|
||||
}
|
||||
|
||||
beans {
|
||||
foo String, "World"
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package org.test
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableCaching
|
||||
class Sample {
|
||||
|
||||
@Bean CacheManager cacheManager() {
|
||||
new ConcurrentMapCacheManager()
|
||||
}
|
||||
|
||||
@Component
|
||||
static class MyClient implements CommandLineRunner {
|
||||
|
||||
private final MyService myService
|
||||
|
||||
@Autowired
|
||||
MyClient(MyService myService) {
|
||||
this.myService = myService
|
||||
}
|
||||
|
||||
void run(String... args) {
|
||||
long counter = myService.get('someKey')
|
||||
long counter2 = myService.get('someKey')
|
||||
if (counter == counter2) {
|
||||
println 'Hello World'
|
||||
} else {
|
||||
println 'Something went wrong with the cache setup'
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
static class MyService {
|
||||
|
||||
private final AtomicLong counter = new AtomicLong()
|
||||
|
||||
@Cacheable('foo')
|
||||
Long get(String id) {
|
||||
return counter.getAndIncrement()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package org.test
|
||||
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Controller
|
||||
class Example implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
ApplicationContext context
|
||||
|
||||
@RequestMapping("/")
|
||||
@ResponseBody
|
||||
public String helloWorld() {
|
||||
return "World!"
|
||||
}
|
||||
|
||||
void run(String... args) {
|
||||
def port = context.webServer.port
|
||||
def world = new RestTemplate().getForObject("http://localhost:" + port + "/", String.class);
|
||||
print "Hello " + world
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
class SpringIntegrationExample implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context
|
||||
|
||||
@Bean
|
||||
DirectChannel input() {
|
||||
new DirectChannel()
|
||||
}
|
||||
|
||||
@Override
|
||||
void run(String... args) {
|
||||
println()
|
||||
println '>>>> ' + new MessagingTemplate(input()).convertSendAndReceive("World", String) + ' <<<<'
|
||||
println()
|
||||
/*
|
||||
* Since this is a simple application that we want to exit right away,
|
||||
* close the context. For an active integration application, with pollers
|
||||
* etc, you can either suspend the main thread here (e.g. with System.in.read()),
|
||||
* or exit the run() method without closing the context, and stop the
|
||||
* application later using some other technique (kill, JMX etc).
|
||||
*/
|
||||
context.close()
|
||||
}
|
||||
}
|
||||
|
||||
@MessageEndpoint
|
||||
class HelloTransformer {
|
||||
|
||||
@Transformer(inputChannel="input")
|
||||
String transform(String payload) {
|
||||
"Hello, ${payload}"
|
||||
}
|
||||
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@Grab("spring-boot-starter-artemis")
|
||||
@Grab("artemis-jakarta-server")
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@Log
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableJms
|
||||
class JmsExample implements CommandLineRunner {
|
||||
|
||||
private CountDownLatch latch = new CountDownLatch(1)
|
||||
|
||||
@Autowired
|
||||
JmsTemplate jmsTemplate
|
||||
|
||||
void run(String... args) {
|
||||
def messageCreator = { session ->
|
||||
session.createObjectMessage("Greetings from Spring Boot via Artemis")
|
||||
} as MessageCreator
|
||||
log.info "Sending JMS message..."
|
||||
jmsTemplate.send("spring-boot", messageCreator)
|
||||
log.info "Send JMS message, waiting..."
|
||||
latch.await()
|
||||
}
|
||||
|
||||
@JmsListener(destination = 'spring-boot')
|
||||
def receive(String message) {
|
||||
log.info "Received ${message}"
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package org.test
|
||||
|
||||
import org.springframework.transaction.TransactionManager
|
||||
|
||||
@Grab("hsqldb")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableBatchProcessing
|
||||
class JobConfig {
|
||||
|
||||
@Autowired
|
||||
private JobBuilderFactory jobs
|
||||
|
||||
@Autowired
|
||||
private StepBuilderFactory steps
|
||||
|
||||
@Autowired
|
||||
private TransactionManager transactionManager
|
||||
|
||||
@Bean
|
||||
protected Tasklet tasklet() {
|
||||
return new Tasklet() {
|
||||
@Override
|
||||
RepeatStatus execute(StepContribution contribution, ChunkContext context) {
|
||||
return RepeatStatus.FINISHED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
Job job() throws Exception {
|
||||
return jobs.get("job").start(step1()).build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected Step step1() throws Exception {
|
||||
return steps.get("step1").tasklet(tasklet()).transactionManager(this.transactionManager).build()
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package org.test
|
||||
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@Log
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRabbit
|
||||
class RabbitExample implements CommandLineRunner {
|
||||
|
||||
private CountDownLatch latch = new CountDownLatch(1)
|
||||
|
||||
@Autowired
|
||||
RabbitTemplate rabbitTemplate
|
||||
|
||||
void run(String... args) {
|
||||
log.info "Sending RabbitMQ message..."
|
||||
rabbitTemplate.convertAndSend("spring-boot", "Greetings from Spring Boot via RabbitMQ")
|
||||
latch.await()
|
||||
}
|
||||
|
||||
@RabbitListener(queues = 'spring-boot')
|
||||
def receive(String message) {
|
||||
log.info "Received ${message}"
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
@Bean
|
||||
org.springframework.amqp.core.Queue queue() {
|
||||
new org.springframework.amqp.core.Queue("spring-boot", false)
|
||||
}
|
||||
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@EnableRetry
|
||||
@Component
|
||||
class Example implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
private MyService myService
|
||||
|
||||
void run(String... args) {
|
||||
println "Hello ${this.myService.sayWorld()} From ${getClass().getClassLoader().getResource('samples/retry.groovy')}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Service
|
||||
class MyService {
|
||||
|
||||
static int count = 0
|
||||
|
||||
@Retryable
|
||||
String sayWorld() {
|
||||
if (count++==0) {
|
||||
throw new IllegalStateException("Planned")
|
||||
}
|
||||
return "World!"
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package org.test
|
||||
|
||||
class Runner implements CommandLineRunner {
|
||||
|
||||
void run(String... args) {
|
||||
print "Hello World!"
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="runner" class="org.test.Runner"/>
|
||||
|
||||
</beans>
|
||||
|
@ -1,13 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@Grab("spring-boot-starter-security")
|
||||
@Grab("spring-boot-starter-actuator")
|
||||
|
||||
@RestController
|
||||
class SampleController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public def hello() {
|
||||
[message: "Hello World!"]
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package org.test
|
||||
|
||||
import static org.springframework.boot.groovy.GroovyTemplate.*
|
||||
|
||||
@Component
|
||||
class Example implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
private MyService myService
|
||||
|
||||
@Override
|
||||
void run(String... args) {
|
||||
print template("test.txt", ["message":myService.sayWorld()])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Service
|
||||
class MyService {
|
||||
|
||||
String sayWorld() {
|
||||
return "World"
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@Grab("hsqldb")
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableTransactionManagement
|
||||
class Example implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
JdbcTemplate jdbcTemplate
|
||||
|
||||
@Transactional
|
||||
void run(String... args) {
|
||||
println "Foo count=" + jdbcTemplate.queryForObject("SELECT COUNT(*) from FOO", Integer)
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
package app
|
||||
|
||||
@Grab("thymeleaf-spring6")
|
||||
@Controller
|
||||
class Example {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String helloWorld(Map<String,Object> model) {
|
||||
model.putAll([title: "My Page", date: new Date(), message: "Hello World"])
|
||||
return "home"
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
@Controller
|
||||
class Example {
|
||||
|
||||
@Autowired
|
||||
private MyService myService
|
||||
|
||||
@RequestMapping("/")
|
||||
@ResponseBody
|
||||
public String helloWorld() {
|
||||
return myService.sayWorld()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Service
|
||||
class MyService {
|
||||
|
||||
public String sayWorld() {
|
||||
return "World!"
|
||||
}
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import org.springframework.boot.cli.command.archive.JarCommand;
|
||||
import org.springframework.boot.cli.infrastructure.CommandLineInvoker;
|
||||
import org.springframework.boot.cli.infrastructure.CommandLineInvoker.Invocation;
|
||||
import org.springframework.boot.loader.tools.JavaExecutable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration test for {@link JarCommand}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class JarCommandIT {
|
||||
|
||||
private static final boolean JAVA_9_OR_LATER = isClassPresent("java.security.cert.URICertStoreParameters");
|
||||
|
||||
private CommandLineInvoker cli;
|
||||
|
||||
private File tempDir;
|
||||
|
||||
@BeforeEach
|
||||
void setup(@TempDir File tempDir) {
|
||||
this.cli = new CommandLineInvoker(new File("src/intTest/resources/jar-command"), tempDir);
|
||||
this.tempDir = tempDir;
|
||||
}
|
||||
|
||||
@Test
|
||||
void noArguments() throws Exception {
|
||||
Invocation invocation = this.cli.invoke("jar");
|
||||
invocation.await();
|
||||
assertThat(invocation.getStandardOutput()).isEqualTo("");
|
||||
assertThat(invocation.getErrorOutput())
|
||||
.contains("The name of the resulting jar and at least one source file must be specified");
|
||||
}
|
||||
|
||||
@Test
|
||||
void noSources() throws Exception {
|
||||
Invocation invocation = this.cli.invoke("jar", "test-app.jar");
|
||||
invocation.await();
|
||||
assertThat(invocation.getStandardOutput()).isEqualTo("");
|
||||
assertThat(invocation.getErrorOutput())
|
||||
.contains("The name of the resulting jar and at least one source file must be specified");
|
||||
}
|
||||
|
||||
@Test
|
||||
void jarCreationWithGrabResolver() throws Exception {
|
||||
File jar = new File(this.tempDir, "test-app.jar");
|
||||
Invocation invocation = this.cli.invoke("run", jar.getAbsolutePath(), "bad.groovy");
|
||||
invocation.await();
|
||||
if (!JAVA_9_OR_LATER) {
|
||||
assertThat(invocation.getErrorOutput()).isEqualTo("");
|
||||
}
|
||||
invocation = this.cli.invoke("jar", jar.getAbsolutePath(), "bad.groovy");
|
||||
invocation.await();
|
||||
if (!JAVA_9_OR_LATER) {
|
||||
assertThat(invocation.getErrorOutput()).isEmpty();
|
||||
}
|
||||
assertThat(jar).exists();
|
||||
|
||||
Process process = new JavaExecutable().processBuilder("-jar", jar.getAbsolutePath()).start();
|
||||
invocation = new Invocation(process);
|
||||
invocation.await();
|
||||
|
||||
if (!JAVA_9_OR_LATER) {
|
||||
assertThat(invocation.getErrorOutput()).isEqualTo("");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void jarCreation() throws Exception {
|
||||
File jar = new File(this.tempDir, "test-app.jar");
|
||||
Invocation invocation = this.cli.invoke("jar", jar.getAbsolutePath(), "jar.groovy");
|
||||
invocation.await();
|
||||
if (!JAVA_9_OR_LATER) {
|
||||
assertThat(invocation.getErrorOutput()).isEmpty();
|
||||
}
|
||||
assertThat(jar).exists();
|
||||
|
||||
Process process = new JavaExecutable().processBuilder("-jar", jar.getAbsolutePath()).start();
|
||||
invocation = new Invocation(process);
|
||||
invocation.await();
|
||||
|
||||
if (!JAVA_9_OR_LATER) {
|
||||
assertThat(invocation.getErrorOutput()).isEqualTo("");
|
||||
}
|
||||
assertThat(invocation.getStandardOutput()).contains("Hello World!")
|
||||
.contains("/BOOT-INF/classes!/public/public.txt").contains("/BOOT-INF/classes!/resources/resource.txt")
|
||||
.contains("/BOOT-INF/classes!/static/static.txt").contains("/BOOT-INF/classes!/templates/template.txt")
|
||||
.contains("/BOOT-INF/classes!/root.properties").contains("Goodbye Mama");
|
||||
}
|
||||
|
||||
@Test
|
||||
void jarCreationWithIncludes() throws Exception {
|
||||
File jar = new File(this.tempDir, "test-app.jar");
|
||||
Invocation invocation = this.cli.invoke("jar", jar.getAbsolutePath(), "--include", "-public/**,-resources/**",
|
||||
"jar.groovy");
|
||||
invocation.await();
|
||||
if (!JAVA_9_OR_LATER) {
|
||||
assertThat(invocation.getErrorOutput()).isEmpty();
|
||||
}
|
||||
assertThat(jar).exists();
|
||||
|
||||
Process process = new JavaExecutable().processBuilder("-jar", jar.getAbsolutePath()).start();
|
||||
invocation = new Invocation(process);
|
||||
invocation.await();
|
||||
|
||||
if (!JAVA_9_OR_LATER) {
|
||||
assertThat(invocation.getErrorOutput()).isEqualTo("");
|
||||
}
|
||||
assertThat(invocation.getStandardOutput()).contains("Hello World!").doesNotContain("/public/public.txt")
|
||||
.doesNotContain("/resources/resource.txt").contains("/static/static.txt")
|
||||
.contains("/templates/template.txt").contains("Goodbye Mama");
|
||||
}
|
||||
|
||||
private static boolean isClassPresent(String name) {
|
||||
try {
|
||||
Class.forName(name);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import org.springframework.boot.cli.command.archive.WarCommand;
|
||||
import org.springframework.boot.cli.infrastructure.CommandLineInvoker;
|
||||
import org.springframework.boot.cli.infrastructure.CommandLineInvoker.Invocation;
|
||||
import org.springframework.boot.loader.tools.JavaExecutable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration test for {@link WarCommand}.
|
||||
*
|
||||
* @author Andrey Stolyarov
|
||||
* @author Henri Kerola
|
||||
*/
|
||||
class WarCommandIT {
|
||||
|
||||
private CommandLineInvoker cli;
|
||||
|
||||
private File tempDir;
|
||||
|
||||
@BeforeEach
|
||||
void setup(@TempDir File tempDir) {
|
||||
this.cli = new CommandLineInvoker(new File("src/intTest/resources/war-command"), tempDir);
|
||||
this.tempDir = tempDir;
|
||||
}
|
||||
|
||||
@Test
|
||||
void warCreation() throws Exception {
|
||||
File war = new File(this.tempDir, "test-app.war");
|
||||
Invocation invocation = this.cli.invoke("war", war.getAbsolutePath(), "war.groovy");
|
||||
invocation.await();
|
||||
assertThat(war.exists()).isTrue();
|
||||
Process process = new JavaExecutable().processBuilder("-jar", war.getAbsolutePath(), "--server.port=0").start();
|
||||
invocation = new Invocation(process);
|
||||
invocation.await();
|
||||
assertThat(invocation.getOutput()).contains("onStart error");
|
||||
assertThat(invocation.getOutput()).contains("Tomcat started");
|
||||
assertThat(invocation.getOutput()).contains("/WEB-INF/lib-provided/tomcat-embed-core");
|
||||
assertThat(invocation.getOutput()).contains("WEB-INF/classes!/root.properties");
|
||||
process.destroy();
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
@GrabResolver(name='clojars.org', root='https://clojars.org/repo')
|
||||
@Grab('redis.embedded:embedded-redis:0.2')
|
||||
|
||||
@Component
|
||||
class EmbeddedRedis {
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@EnableGroovyTemplates
|
||||
@Component
|
||||
class Example implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
private MyService myService
|
||||
|
||||
void run(String... args) {
|
||||
println "Hello ${this.myService.sayWorld()}"
|
||||
println getClass().getResource('/public/public.txt')
|
||||
println getClass().getResource('/resources/resource.txt')
|
||||
println getClass().getResource('/static/static.txt')
|
||||
println getClass().getResource('/templates/template.txt')
|
||||
println getClass().getResource('/root.properties')
|
||||
println template('template.txt', [world:'Mama'])
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
class MyService {
|
||||
|
||||
String sayWorld() {
|
||||
return 'World!'
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
Goodbye ${world}
|
@ -1,10 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@Component
|
||||
class Example implements CommandLineRunner {
|
||||
|
||||
void run(String... args) {
|
||||
print "Ssshh"
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@RestController
|
||||
class WarExample implements CommandLineRunner {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String hello() {
|
||||
return "Hello"
|
||||
}
|
||||
|
||||
void run(String... args) {
|
||||
println getClass().getResource('/org/apache/tomcat/InstanceManager.class')
|
||||
println getClass().getResource('/root.properties')
|
||||
throw new RuntimeException("onStart error")
|
||||
}
|
||||
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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.app;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A launcher for {@code SpringApplication} or a {@code SpringApplication} subclass. The
|
||||
* class that is used can be configured using the System property
|
||||
* {@code spring.application.class.name} or the {@code SPRING_APPLICATION_CLASS_NAME}
|
||||
* environment variable. Uses reflection to allow the launching code to exist in a
|
||||
* separate ClassLoader from the application code.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
* @see System#getProperty(String)
|
||||
* @see System#getenv(String)
|
||||
*/
|
||||
public class SpringApplicationLauncher {
|
||||
|
||||
private static final String DEFAULT_SPRING_APPLICATION_CLASS = "org.springframework.boot.SpringApplication";
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
/**
|
||||
* Creates a new launcher that will use the given {@code classLoader} to load the
|
||||
* configured {@code SpringApplication} class.
|
||||
* @param classLoader the {@code ClassLoader} to use
|
||||
*/
|
||||
public SpringApplicationLauncher(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the application created using the given {@code sources}. The application
|
||||
* is launched with the given {@code args}.
|
||||
* @param sources the sources for the application
|
||||
* @param args the args for the application
|
||||
* @return the application's {@code ApplicationContext}
|
||||
* @throws Exception if the launch fails
|
||||
*/
|
||||
public Object launch(Class<?>[] sources, String[] args) throws Exception {
|
||||
Map<String, Object> defaultProperties = new HashMap<>();
|
||||
defaultProperties.put("spring.groovy.template.check-template-location", "false");
|
||||
Class<?> applicationClass = Class.forName(getSpringApplicationClassName(), false, this.classLoader);
|
||||
Constructor<?> constructor = applicationClass.getDeclaredConstructor(Class[].class);
|
||||
constructor.setAccessible(true);
|
||||
Object application = constructor.newInstance((Object) sources);
|
||||
applicationClass.getMethod("setDefaultProperties", Map.class).invoke(application, defaultProperties);
|
||||
Method method = applicationClass.getMethod("run", String[].class);
|
||||
return method.invoke(application, (Object) args);
|
||||
}
|
||||
|
||||
private String getSpringApplicationClassName() {
|
||||
String className = System.getProperty("spring.application.class.name");
|
||||
if (className == null) {
|
||||
className = getEnvironmentVariable("SPRING_APPLICATION_CLASS_NAME");
|
||||
}
|
||||
if (className == null) {
|
||||
className = DEFAULT_SPRING_APPLICATION_CLASS;
|
||||
}
|
||||
return className;
|
||||
}
|
||||
|
||||
protected String getEnvironmentVariable(String name) {
|
||||
return System.getenv(name);
|
||||
}
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.app;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.ServletException;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
/**
|
||||
* {@link SpringBootServletInitializer} for CLI packaged WAR files.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class SpringApplicationWebApplicationInitializer extends SpringBootServletInitializer {
|
||||
|
||||
/**
|
||||
* The entry containing the source class.
|
||||
*/
|
||||
public static final String SOURCE_ENTRY = "Spring-Application-Source-Classes";
|
||||
|
||||
private String[] sources;
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||
try {
|
||||
this.sources = getSources(servletContext);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
super.onStartup(servletContext);
|
||||
}
|
||||
|
||||
private String[] getSources(ServletContext servletContext) throws IOException {
|
||||
Manifest manifest = getManifest(servletContext);
|
||||
if (manifest == null) {
|
||||
throw new IllegalStateException("Unable to read manifest");
|
||||
}
|
||||
String sources = manifest.getMainAttributes().getValue(SOURCE_ENTRY);
|
||||
return sources.split(",");
|
||||
}
|
||||
|
||||
private Manifest getManifest(ServletContext servletContext) throws IOException {
|
||||
InputStream stream = servletContext.getResourceAsStream("/META-INF/MANIFEST.MF");
|
||||
return (stream != null) ? new Manifest(stream) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
|
||||
try {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
Class<?>[] sourceClasses = new Class<?>[this.sources.length];
|
||||
for (int i = 0; i < this.sources.length; i++) {
|
||||
sourceClasses[i] = Class.forName(this.sources[i], false, classLoader);
|
||||
}
|
||||
return builder.sources(sourceClasses).properties("spring.groovy.template.check-template-location=false");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support classes for CLI applications.
|
||||
*/
|
||||
package org.springframework.boot.cli.app;
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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.archive;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.springframework.boot.cli.app.SpringApplicationLauncher;
|
||||
|
||||
/**
|
||||
* A launcher for a CLI application that has been compiled and packaged as a jar file.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class PackagedSpringApplicationLauncher {
|
||||
|
||||
/**
|
||||
* The entry containing the source class.
|
||||
*/
|
||||
public static final String SOURCE_ENTRY = "Spring-Application-Source-Classes";
|
||||
|
||||
/**
|
||||
* The entry containing the start class.
|
||||
*/
|
||||
public static final String START_CLASS_ENTRY = "Start-Class";
|
||||
|
||||
private PackagedSpringApplicationLauncher() {
|
||||
}
|
||||
|
||||
private void run(String[] args) throws Exception {
|
||||
URLClassLoader classLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
|
||||
new SpringApplicationLauncher(classLoader).launch(getSources(classLoader), args);
|
||||
}
|
||||
|
||||
private Class<?>[] getSources(URLClassLoader classLoader) throws Exception {
|
||||
Enumeration<URL> urls = classLoader.getResources("META-INF/MANIFEST.MF");
|
||||
while (urls.hasMoreElements()) {
|
||||
URL url = urls.nextElement();
|
||||
Manifest manifest = new Manifest(url.openStream());
|
||||
if (isCliPackaged(manifest)) {
|
||||
String sources = manifest.getMainAttributes().getValue(SOURCE_ENTRY);
|
||||
return loadClasses(classLoader, sources.split(","));
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Cannot locate " + SOURCE_ENTRY + " in MANIFEST.MF");
|
||||
}
|
||||
|
||||
private boolean isCliPackaged(Manifest manifest) {
|
||||
Attributes attributes = manifest.getMainAttributes();
|
||||
String startClass = attributes.getValue(START_CLASS_ENTRY);
|
||||
return getClass().getName().equals(startClass);
|
||||
}
|
||||
|
||||
private Class<?>[] loadClasses(ClassLoader classLoader, String[] names) throws ClassNotFoundException {
|
||||
Class<?>[] classes = new Class<?>[names.length];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
classes[i] = Class.forName(names[i], false, classLoader);
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new PackagedSpringApplicationLauncher().run(args);
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that are packaged as part of CLI generated JARs.
|
||||
* @see org.springframework.boot.cli.command.archive.JarCommand
|
||||
*/
|
||||
package org.springframework.boot.cli.archive;
|
@ -1,317 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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.command.archive;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import groovy.lang.Grab;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
import org.codehaus.groovy.ast.ASTNode;
|
||||
import org.codehaus.groovy.ast.AnnotatedNode;
|
||||
import org.codehaus.groovy.ast.AnnotationNode;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
import org.codehaus.groovy.ast.expr.ConstantExpression;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.transform.ASTTransformation;
|
||||
|
||||
import org.springframework.boot.cli.app.SpringApplicationLauncher;
|
||||
import org.springframework.boot.cli.archive.PackagedSpringApplicationLauncher;
|
||||
import org.springframework.boot.cli.command.Command;
|
||||
import org.springframework.boot.cli.command.OptionParsingCommand;
|
||||
import org.springframework.boot.cli.command.archive.ResourceMatcher.MatchedResource;
|
||||
import org.springframework.boot.cli.command.options.CompilerOptionHandler;
|
||||
import org.springframework.boot.cli.command.options.OptionHandler;
|
||||
import org.springframework.boot.cli.command.options.OptionSetGroovyCompilerConfiguration;
|
||||
import org.springframework.boot.cli.command.options.SourceOptions;
|
||||
import org.springframework.boot.cli.command.status.ExitStatus;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompiler;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
||||
import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory;
|
||||
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
||||
import org.springframework.boot.loader.tools.JarWriter;
|
||||
import org.springframework.boot.loader.tools.Layout;
|
||||
import org.springframework.boot.loader.tools.Library;
|
||||
import org.springframework.boot.loader.tools.LibraryScope;
|
||||
import org.springframework.boot.loader.tools.Repackager;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract {@link Command} to create a self-contained executable archive file from a CLI
|
||||
* application.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @author Andrey Stolyarov
|
||||
* @author Henri Kerola
|
||||
*/
|
||||
abstract class ArchiveCommand extends OptionParsingCommand {
|
||||
|
||||
protected ArchiveCommand(String name, String description, OptionHandler optionHandler) {
|
||||
super(name, description, optionHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageHelp() {
|
||||
return "[options] <" + getName() + "-name> <files>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base {@link CompilerOptionHandler} for archive commands.
|
||||
*/
|
||||
protected abstract static class ArchiveOptionHandler extends CompilerOptionHandler {
|
||||
|
||||
private final String type;
|
||||
|
||||
private final Layout layout;
|
||||
|
||||
private OptionSpec<String> includeOption;
|
||||
|
||||
private OptionSpec<String> excludeOption;
|
||||
|
||||
public ArchiveOptionHandler(String type, Layout layout) {
|
||||
this.type = type;
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
protected Layout getLayout() {
|
||||
return this.layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOptions() {
|
||||
this.includeOption = option("include",
|
||||
"Pattern applied to directories on the classpath to find files to include in the resulting ")
|
||||
.withRequiredArg().withValuesSeparatedBy(",").defaultsTo("");
|
||||
this.excludeOption = option("exclude", "Pattern applied to directories on the classpath to find files to "
|
||||
+ "exclude from the resulting " + this.type).withRequiredArg().withValuesSeparatedBy(",")
|
||||
.defaultsTo("");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExitStatus run(OptionSet options) throws Exception {
|
||||
List<?> nonOptionArguments = new ArrayList<Object>(options.nonOptionArguments());
|
||||
Assert.isTrue(nonOptionArguments.size() >= 2,
|
||||
() -> "The name of the resulting " + this.type + " and at least one source file must be specified");
|
||||
|
||||
File output = new File((String) nonOptionArguments.remove(0));
|
||||
Assert.isTrue(output.getName().toLowerCase(Locale.ENGLISH).endsWith("." + this.type),
|
||||
() -> "The output '" + output + "' is not a " + this.type.toUpperCase(Locale.ENGLISH) + " file.");
|
||||
deleteIfExists(output);
|
||||
|
||||
GroovyCompiler compiler = createCompiler(options);
|
||||
|
||||
List<URL> classpath = getClassPathUrls(compiler);
|
||||
List<MatchedResource> classpathEntries = findMatchingClasspathEntries(classpath, options);
|
||||
|
||||
String[] sources = new SourceOptions(nonOptionArguments).getSourcesArray();
|
||||
Class<?>[] compiledClasses = compiler.compile(sources);
|
||||
|
||||
List<URL> dependencies = getClassPathUrls(compiler);
|
||||
dependencies.removeAll(classpath);
|
||||
|
||||
writeJar(output, compiledClasses, classpathEntries, dependencies);
|
||||
return ExitStatus.OK;
|
||||
}
|
||||
|
||||
private void deleteIfExists(File file) {
|
||||
if (file.exists() && !file.delete()) {
|
||||
throw new IllegalStateException("Failed to delete existing file " + file.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private GroovyCompiler createCompiler(OptionSet options) {
|
||||
List<RepositoryConfiguration> repositoryConfiguration = RepositoryConfigurationFactory
|
||||
.createDefaultRepositoryConfiguration();
|
||||
GroovyCompilerConfiguration configuration = new OptionSetGroovyCompilerConfiguration(options, this,
|
||||
repositoryConfiguration);
|
||||
GroovyCompiler groovyCompiler = new GroovyCompiler(configuration);
|
||||
groovyCompiler.getAstTransformations().add(0, new GrabAnnotationTransform());
|
||||
return groovyCompiler;
|
||||
}
|
||||
|
||||
private List<URL> getClassPathUrls(GroovyCompiler compiler) {
|
||||
return new ArrayList<>(Arrays.asList(compiler.getLoader().getURLs()));
|
||||
}
|
||||
|
||||
private List<MatchedResource> findMatchingClasspathEntries(List<URL> classpath, OptionSet options)
|
||||
throws IOException {
|
||||
ResourceMatcher matcher = new ResourceMatcher(options.valuesOf(this.includeOption),
|
||||
options.valuesOf(this.excludeOption));
|
||||
List<File> roots = new ArrayList<>();
|
||||
for (URL classpathEntry : classpath) {
|
||||
roots.add(new File(URI.create(classpathEntry.toString())));
|
||||
}
|
||||
return matcher.find(roots);
|
||||
}
|
||||
|
||||
private void writeJar(File file, Class<?>[] compiledClasses, List<MatchedResource> classpathEntries,
|
||||
List<URL> dependencies) throws IOException, URISyntaxException {
|
||||
final List<Library> libraries;
|
||||
try (JarWriter writer = new JarWriter(file)) {
|
||||
addManifest(writer, compiledClasses);
|
||||
addCliClasses(writer);
|
||||
for (Class<?> compiledClass : compiledClasses) {
|
||||
addClass(writer, compiledClass);
|
||||
}
|
||||
libraries = addClasspathEntries(writer, classpathEntries);
|
||||
}
|
||||
libraries.addAll(createLibraries(dependencies));
|
||||
Repackager repackager = new Repackager(file);
|
||||
repackager.setMainClass(PackagedSpringApplicationLauncher.class.getName());
|
||||
repackager.repackage((callback) -> {
|
||||
for (Library library : libraries) {
|
||||
callback.library(library);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<Library> createLibraries(List<URL> dependencies) throws URISyntaxException {
|
||||
List<Library> libraries = new ArrayList<>();
|
||||
for (URL dependency : dependencies) {
|
||||
File file = new File(dependency.toURI());
|
||||
libraries.add(new Library(null, file, getLibraryScope(file), null, false, false, true));
|
||||
}
|
||||
return libraries;
|
||||
}
|
||||
|
||||
private void addManifest(JarWriter writer, Class<?>[] compiledClasses) throws IOException {
|
||||
Manifest manifest = new Manifest();
|
||||
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
|
||||
manifest.getMainAttributes().putValue(PackagedSpringApplicationLauncher.SOURCE_ENTRY,
|
||||
commaDelimitedClassNames(compiledClasses));
|
||||
writer.writeManifest(manifest);
|
||||
}
|
||||
|
||||
private String commaDelimitedClassNames(Class<?>[] classes) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
if (i != 0) {
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(classes[i].getName());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected void addCliClasses(JarWriter writer) throws IOException {
|
||||
addClass(writer, PackagedSpringApplicationLauncher.class);
|
||||
addClass(writer, SpringApplicationLauncher.class);
|
||||
Resource[] resources = new PathMatchingResourcePatternResolver()
|
||||
.getResources("org/springframework/boot/groovy/**");
|
||||
for (Resource resource : resources) {
|
||||
String url = resource.getURL().toString();
|
||||
addResource(writer, resource, url.substring(url.indexOf("org/springframework/boot/groovy/")));
|
||||
}
|
||||
}
|
||||
|
||||
protected final void addClass(JarWriter writer, Class<?> sourceClass) throws IOException {
|
||||
addClass(writer, sourceClass.getClassLoader(), sourceClass.getName());
|
||||
}
|
||||
|
||||
protected final void addClass(JarWriter writer, ClassLoader classLoader, String sourceClass)
|
||||
throws IOException {
|
||||
if (classLoader == null) {
|
||||
classLoader = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
String name = sourceClass.replace('.', '/') + ".class";
|
||||
InputStream stream = classLoader.getResourceAsStream(name);
|
||||
writer.writeEntry(this.layout.getClassesLocation() + name, stream);
|
||||
}
|
||||
|
||||
private void addResource(JarWriter writer, Resource resource, String name) throws IOException {
|
||||
InputStream stream = resource.getInputStream();
|
||||
writer.writeEntry(name, stream);
|
||||
}
|
||||
|
||||
private List<Library> addClasspathEntries(JarWriter writer, List<MatchedResource> entries) throws IOException {
|
||||
List<Library> libraries = new ArrayList<>();
|
||||
for (MatchedResource entry : entries) {
|
||||
if (entry.isRoot()) {
|
||||
libraries.add(new Library(null, entry.getFile(), LibraryScope.COMPILE, null, false, false, true));
|
||||
}
|
||||
else {
|
||||
writeClasspathEntry(writer, entry);
|
||||
}
|
||||
}
|
||||
return libraries;
|
||||
}
|
||||
|
||||
protected void writeClasspathEntry(JarWriter writer, MatchedResource entry) throws IOException {
|
||||
writer.writeEntry(entry.getName(), new FileInputStream(entry.getFile()));
|
||||
}
|
||||
|
||||
protected abstract LibraryScope getLibraryScope(File file);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ASTTransformation} to change {@code @Grab} annotation values.
|
||||
*/
|
||||
private static class GrabAnnotationTransform implements ASTTransformation {
|
||||
|
||||
@Override
|
||||
public void visit(ASTNode[] nodes, SourceUnit source) {
|
||||
for (ASTNode node : nodes) {
|
||||
if (node instanceof ModuleNode moduleNode) {
|
||||
visitModule(moduleNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visitModule(ModuleNode module) {
|
||||
for (ClassNode classNode : module.getClasses()) {
|
||||
AnnotationNode annotation = new AnnotationNode(new ClassNode(Grab.class));
|
||||
annotation.addMember("value", new ConstantExpression("groovy"));
|
||||
classNode.addAnnotation(annotation);
|
||||
// We only need to do it at most once
|
||||
break;
|
||||
}
|
||||
// Disable the addition of a static initializer that calls Grape.addResolver
|
||||
// because all the dependencies are local now
|
||||
disableGrabResolvers(module.getClasses());
|
||||
disableGrabResolvers(module.getImports());
|
||||
}
|
||||
|
||||
private void disableGrabResolvers(List<? extends AnnotatedNode> nodes) {
|
||||
for (AnnotatedNode classNode : nodes) {
|
||||
List<AnnotationNode> annotations = classNode.getAnnotations();
|
||||
for (AnnotationNode node : new ArrayList<>(annotations)) {
|
||||
if (node.getClassNode().getNameWithoutPackage().equals("GrabResolver")) {
|
||||
node.setMember("initClass", new ConstantExpression(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.archive;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.springframework.boot.cli.command.Command;
|
||||
import org.springframework.boot.loader.tools.Layouts;
|
||||
import org.springframework.boot.loader.tools.LibraryScope;
|
||||
|
||||
/**
|
||||
* {@link Command} to create a self-contained executable jar file from a CLI application.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class JarCommand extends ArchiveCommand {
|
||||
|
||||
public JarCommand() {
|
||||
super("jar", "Create a self-contained executable jar file from a Spring Groovy script", new JarOptionHandler());
|
||||
}
|
||||
|
||||
private static final class JarOptionHandler extends ArchiveOptionHandler {
|
||||
|
||||
JarOptionHandler() {
|
||||
super("jar", new Layouts.Jar());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LibraryScope getLibraryScope(File file) {
|
||||
return LibraryScope.COMPILE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,222 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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.command.archive;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Used to match resources for inclusion in a CLI application's jar file.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ResourceMatcher {
|
||||
|
||||
private static final String[] DEFAULT_INCLUDES = { "public/**", "resources/**", "static/**", "templates/**",
|
||||
"META-INF/**", "*" };
|
||||
|
||||
private static final String[] DEFAULT_EXCLUDES = { ".*", "repository/**", "build/**", "target/**", "**/*.jar",
|
||||
"**/*.groovy" };
|
||||
|
||||
private final AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
private final List<String> includes;
|
||||
|
||||
private final List<String> excludes;
|
||||
|
||||
ResourceMatcher(List<String> includes, List<String> excludes) {
|
||||
this.includes = getOptions(includes, DEFAULT_INCLUDES);
|
||||
this.excludes = getOptions(excludes, DEFAULT_EXCLUDES);
|
||||
}
|
||||
|
||||
List<MatchedResource> find(List<File> roots) throws IOException {
|
||||
List<MatchedResource> matchedResources = new ArrayList<>();
|
||||
for (File root : roots) {
|
||||
if (root.isFile()) {
|
||||
matchedResources.add(new MatchedResource(root));
|
||||
}
|
||||
else {
|
||||
matchedResources.addAll(findInDirectory(root));
|
||||
}
|
||||
}
|
||||
return matchedResources;
|
||||
}
|
||||
|
||||
private List<MatchedResource> findInDirectory(File directory) throws IOException {
|
||||
List<MatchedResource> matchedResources = new ArrayList<>();
|
||||
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
|
||||
new DirectoryResourceLoader(directory));
|
||||
|
||||
for (String include : this.includes) {
|
||||
for (Resource candidate : resolver.getResources(include)) {
|
||||
File file = candidate.getFile();
|
||||
if (file.isFile()) {
|
||||
MatchedResource matchedResource = new MatchedResource(directory, file);
|
||||
if (!isExcluded(matchedResource)) {
|
||||
matchedResources.add(matchedResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchedResources;
|
||||
}
|
||||
|
||||
private boolean isExcluded(MatchedResource matchedResource) {
|
||||
for (String exclude : this.excludes) {
|
||||
if (this.pathMatcher.match(exclude, matchedResource.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<String> getOptions(List<String> values, String[] defaults) {
|
||||
Set<String> result = new LinkedHashSet<>();
|
||||
Set<String> minus = new LinkedHashSet<>();
|
||||
boolean deltasFound = false;
|
||||
for (String value : values) {
|
||||
if (value.startsWith("+")) {
|
||||
deltasFound = true;
|
||||
value = value.substring(1);
|
||||
result.add(value);
|
||||
}
|
||||
else if (value.startsWith("-")) {
|
||||
deltasFound = true;
|
||||
value = value.substring(1);
|
||||
minus.add(value);
|
||||
}
|
||||
else if (!value.trim().isEmpty()) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
for (String value : defaults) {
|
||||
if (!minus.contains(value) || !deltasFound) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ResourceLoader} to get load resource from a directory.
|
||||
*/
|
||||
private static class DirectoryResourceLoader extends DefaultResourceLoader {
|
||||
|
||||
private final File rootDirectory;
|
||||
|
||||
DirectoryResourceLoader(File root) throws MalformedURLException {
|
||||
super(new DirectoryClassLoader(root));
|
||||
this.rootDirectory = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resource getResourceByPath(String path) {
|
||||
return new FileSystemResource(new File(this.rootDirectory, path));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ClassLoader} backed by a directory.
|
||||
*/
|
||||
private static class DirectoryClassLoader extends URLClassLoader {
|
||||
|
||||
DirectoryClassLoader(File rootDirectory) throws MalformedURLException {
|
||||
super(new URL[] { rootDirectory.toURI().toURL() });
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
return findResources(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getResource(String name) {
|
||||
return findResource(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A single matched resource.
|
||||
*/
|
||||
public static final class MatchedResource {
|
||||
|
||||
private final File file;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final boolean root;
|
||||
|
||||
private MatchedResource(File file) {
|
||||
this.name = file.getName();
|
||||
this.file = file;
|
||||
this.root = this.name.endsWith(".jar");
|
||||
}
|
||||
|
||||
private MatchedResource(File rootDirectory, File file) {
|
||||
String filePath = file.getAbsolutePath();
|
||||
String rootDirectoryPath = rootDirectory.getAbsolutePath();
|
||||
this.name = StringUtils.cleanPath(filePath.substring(rootDirectoryPath.length() + 1));
|
||||
this.file = file;
|
||||
this.root = false;
|
||||
}
|
||||
|
||||
private MatchedResource(File resourceFile, String path, boolean root) {
|
||||
this.file = resourceFile;
|
||||
this.name = path;
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return this.file;
|
||||
}
|
||||
|
||||
public boolean isRoot() {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.file.getAbsolutePath();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.archive;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.boot.cli.command.Command;
|
||||
import org.springframework.boot.loader.tools.JarWriter;
|
||||
import org.springframework.boot.loader.tools.Layouts;
|
||||
import org.springframework.boot.loader.tools.LibraryScope;
|
||||
|
||||
/**
|
||||
* {@link Command} to create a self-contained executable jar file from a CLI application.
|
||||
*
|
||||
* @author Andrey Stolyarov
|
||||
* @author Phillip Webb
|
||||
* @author Henri Kerola
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class WarCommand extends ArchiveCommand {
|
||||
|
||||
public WarCommand() {
|
||||
super("war", "Create a self-contained executable war file from a Spring Groovy script", new WarOptionHandler());
|
||||
}
|
||||
|
||||
private static final class WarOptionHandler extends ArchiveOptionHandler {
|
||||
|
||||
WarOptionHandler() {
|
||||
super("war", new Layouts.War());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LibraryScope getLibraryScope(File file) {
|
||||
String fileName = file.getName();
|
||||
if (fileName.contains("tomcat-embed") || fileName.contains("spring-boot-starter-tomcat")) {
|
||||
return LibraryScope.PROVIDED;
|
||||
}
|
||||
return LibraryScope.COMPILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addCliClasses(JarWriter writer) throws IOException {
|
||||
addClass(writer, null, "org.springframework.boot.cli.app.SpringApplicationWebApplicationInitializer");
|
||||
super.addCliClasses(writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeClasspathEntry(JarWriter writer, ResourceMatcher.MatchedResource entry) throws IOException {
|
||||
writer.writeEntry(getLayout().getClassesLocation() + entry.getName(), new FileInputStream(entry.getFile()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* CLI commands for creating jars and wars.
|
||||
*/
|
||||
package org.springframework.boot.cli.command.archive;
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.grab;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import joptsimple.OptionSet;
|
||||
|
||||
import org.springframework.boot.cli.command.Command;
|
||||
import org.springframework.boot.cli.command.OptionParsingCommand;
|
||||
import org.springframework.boot.cli.command.options.CompilerOptionHandler;
|
||||
import org.springframework.boot.cli.command.options.OptionSetGroovyCompilerConfiguration;
|
||||
import org.springframework.boot.cli.command.options.SourceOptions;
|
||||
import org.springframework.boot.cli.command.status.ExitStatus;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompiler;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
||||
import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory;
|
||||
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
||||
|
||||
/**
|
||||
* {@link Command} to grab the dependencies of one or more Groovy scripts.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class GrabCommand extends OptionParsingCommand {
|
||||
|
||||
public GrabCommand() {
|
||||
super("grab", "Download a spring groovy script's dependencies to ./repository", new GrabOptionHandler());
|
||||
}
|
||||
|
||||
private static final class GrabOptionHandler extends CompilerOptionHandler {
|
||||
|
||||
@Override
|
||||
protected ExitStatus run(OptionSet options) throws Exception {
|
||||
SourceOptions sourceOptions = new SourceOptions(options);
|
||||
List<RepositoryConfiguration> repositoryConfiguration = RepositoryConfigurationFactory
|
||||
.createDefaultRepositoryConfiguration();
|
||||
GroovyCompilerConfiguration configuration = new OptionSetGroovyCompilerConfiguration(options, this,
|
||||
repositoryConfiguration);
|
||||
if (System.getProperty("grape.root") == null) {
|
||||
System.setProperty("grape.root", ".");
|
||||
}
|
||||
GroovyCompiler groovyCompiler = new GroovyCompiler(configuration);
|
||||
groovyCompiler.compile(sourceOptions.getSourcesArray());
|
||||
return ExitStatus.OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* CLI command for grabbing dependencies.
|
||||
*/
|
||||
package org.springframework.boot.cli.command.grab;
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.install;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Resolve artifact identifiers (typically in the form {@literal group:artifact:version})
|
||||
* to {@link File}s.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface DependencyResolver {
|
||||
|
||||
/**
|
||||
* Resolves the given {@code artifactIdentifiers}, typically in the form
|
||||
* "group:artifact:version", and their dependencies.
|
||||
* @param artifactIdentifiers the artifacts to resolve
|
||||
* @return the {@code File}s for the resolved artifacts
|
||||
* @throws Exception if dependency resolution fails
|
||||
*/
|
||||
List<File> resolve(List<String> artifactIdentifiers) throws Exception;
|
||||
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.install;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
|
||||
import org.springframework.boot.cli.compiler.GroovyCompiler;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
||||
|
||||
/**
|
||||
* A {@code DependencyResolver} implemented using Groovy's {@code @Grab}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class GroovyGrabDependencyResolver implements DependencyResolver {
|
||||
|
||||
private final GroovyCompilerConfiguration configuration;
|
||||
|
||||
GroovyGrabDependencyResolver(GroovyCompilerConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<File> resolve(List<String> artifactIdentifiers) throws CompilationFailedException, IOException {
|
||||
GroovyCompiler groovyCompiler = new GroovyCompiler(this.configuration);
|
||||
List<File> artifactFiles = new ArrayList<>();
|
||||
if (!artifactIdentifiers.isEmpty()) {
|
||||
List<URL> initialUrls = getClassPathUrls(groovyCompiler);
|
||||
groovyCompiler.compile(createSources(artifactIdentifiers));
|
||||
List<URL> artifactUrls = getClassPathUrls(groovyCompiler);
|
||||
artifactUrls.removeAll(initialUrls);
|
||||
for (URL artifactUrl : artifactUrls) {
|
||||
artifactFiles.add(toFile(artifactUrl));
|
||||
}
|
||||
}
|
||||
return artifactFiles;
|
||||
}
|
||||
|
||||
private List<URL> getClassPathUrls(GroovyCompiler compiler) {
|
||||
return new ArrayList<>(Arrays.asList(compiler.getLoader().getURLs()));
|
||||
}
|
||||
|
||||
private String createSources(List<String> artifactIdentifiers) throws IOException {
|
||||
File file = File.createTempFile("SpringCLIDependency", ".groovy");
|
||||
file.deleteOnExit();
|
||||
try (OutputStreamWriter stream = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
|
||||
for (String artifactIdentifier : artifactIdentifiers) {
|
||||
stream.write("@Grab('" + artifactIdentifier + "')");
|
||||
}
|
||||
// Dummy class to force compiler to do grab
|
||||
stream.write("class Installer {}");
|
||||
}
|
||||
// Windows paths get tricky unless you work with URI
|
||||
return file.getAbsoluteFile().toURI().toString();
|
||||
}
|
||||
|
||||
private File toFile(URL url) {
|
||||
try {
|
||||
return new File(url.toURI());
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
return new File(url.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.install;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import joptsimple.OptionSet;
|
||||
|
||||
import org.springframework.boot.cli.command.Command;
|
||||
import org.springframework.boot.cli.command.OptionParsingCommand;
|
||||
import org.springframework.boot.cli.command.options.CompilerOptionHandler;
|
||||
import org.springframework.boot.cli.command.status.ExitStatus;
|
||||
import org.springframework.boot.cli.util.Log;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Command} to install additional dependencies into the CLI.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class InstallCommand extends OptionParsingCommand {
|
||||
|
||||
public InstallCommand() {
|
||||
super("install", "Install dependencies to the lib/ext directory", new InstallOptionHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageHelp() {
|
||||
return "[options] <coordinates>";
|
||||
}
|
||||
|
||||
private static final class InstallOptionHandler extends CompilerOptionHandler {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ExitStatus run(OptionSet options) throws Exception {
|
||||
List<String> args = (List<String>) options.nonOptionArguments();
|
||||
Assert.notEmpty(args,
|
||||
"Please specify at least one dependency, in the form group:artifact:version, to install");
|
||||
try {
|
||||
new Installer(options, this).install(args);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
String message = ex.getMessage();
|
||||
Log.error((message != null) ? message : ex.getClass().toString());
|
||||
}
|
||||
return ExitStatus.OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.install;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import joptsimple.OptionSet;
|
||||
|
||||
import org.springframework.boot.cli.command.options.CompilerOptionHandler;
|
||||
import org.springframework.boot.cli.command.options.OptionSetGroovyCompilerConfiguration;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
||||
import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory;
|
||||
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
||||
import org.springframework.boot.cli.util.Log;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.SystemPropertyUtils;
|
||||
|
||||
/**
|
||||
* Shared logic for the {@link InstallCommand} and {@link UninstallCommand}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class Installer {
|
||||
|
||||
private final DependencyResolver dependencyResolver;
|
||||
|
||||
private final Properties installCounts;
|
||||
|
||||
Installer(OptionSet options, CompilerOptionHandler compilerOptionHandler) throws IOException {
|
||||
this(new GroovyGrabDependencyResolver(createCompilerConfiguration(options, compilerOptionHandler)));
|
||||
}
|
||||
|
||||
Installer(DependencyResolver resolver) throws IOException {
|
||||
this.dependencyResolver = resolver;
|
||||
this.installCounts = loadInstallCounts();
|
||||
}
|
||||
|
||||
private static GroovyCompilerConfiguration createCompilerConfiguration(OptionSet options,
|
||||
CompilerOptionHandler compilerOptionHandler) {
|
||||
List<RepositoryConfiguration> repositoryConfiguration = RepositoryConfigurationFactory
|
||||
.createDefaultRepositoryConfiguration();
|
||||
return new OptionSetGroovyCompilerConfiguration(options, compilerOptionHandler, repositoryConfiguration) {
|
||||
@Override
|
||||
public boolean isAutoconfigure() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Properties loadInstallCounts() throws IOException {
|
||||
Properties properties = new Properties();
|
||||
File installed = getInstalled();
|
||||
if (installed.exists()) {
|
||||
FileReader reader = new FileReader(installed);
|
||||
properties.load(reader);
|
||||
reader.close();
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void saveInstallCounts() throws IOException {
|
||||
try (FileWriter writer = new FileWriter(getInstalled())) {
|
||||
this.installCounts.store(writer, null);
|
||||
}
|
||||
}
|
||||
|
||||
void install(List<String> artifactIdentifiers) throws Exception {
|
||||
File extDirectory = getDefaultExtDirectory();
|
||||
extDirectory.mkdirs();
|
||||
Log.info("Installing into: " + extDirectory);
|
||||
List<File> artifactFiles = this.dependencyResolver.resolve(artifactIdentifiers);
|
||||
for (File artifactFile : artifactFiles) {
|
||||
int installCount = getInstallCount(artifactFile);
|
||||
if (installCount == 0) {
|
||||
FileCopyUtils.copy(artifactFile, new File(extDirectory, artifactFile.getName()));
|
||||
}
|
||||
setInstallCount(artifactFile, installCount + 1);
|
||||
}
|
||||
saveInstallCounts();
|
||||
}
|
||||
|
||||
private int getInstallCount(File file) {
|
||||
String countString = this.installCounts.getProperty(file.getName());
|
||||
if (countString == null) {
|
||||
return 0;
|
||||
}
|
||||
return Integer.parseInt(countString);
|
||||
}
|
||||
|
||||
private void setInstallCount(File file, int count) {
|
||||
if (count == 0) {
|
||||
this.installCounts.remove(file.getName());
|
||||
}
|
||||
else {
|
||||
this.installCounts.setProperty(file.getName(), Integer.toString(count));
|
||||
}
|
||||
}
|
||||
|
||||
void uninstall(List<String> artifactIdentifiers) throws Exception {
|
||||
File extDirectory = getDefaultExtDirectory();
|
||||
Log.info("Uninstalling from: " + extDirectory);
|
||||
List<File> artifactFiles = this.dependencyResolver.resolve(artifactIdentifiers);
|
||||
for (File artifactFile : artifactFiles) {
|
||||
int installCount = getInstallCount(artifactFile);
|
||||
if (installCount <= 1) {
|
||||
new File(extDirectory, artifactFile.getName()).delete();
|
||||
}
|
||||
setInstallCount(artifactFile, installCount - 1);
|
||||
}
|
||||
saveInstallCounts();
|
||||
}
|
||||
|
||||
void uninstallAll() throws Exception {
|
||||
File extDirectory = getDefaultExtDirectory();
|
||||
Log.info("Uninstalling from: " + extDirectory);
|
||||
for (String name : this.installCounts.stringPropertyNames()) {
|
||||
new File(extDirectory, name).delete();
|
||||
}
|
||||
this.installCounts.clear();
|
||||
saveInstallCounts();
|
||||
}
|
||||
|
||||
private File getDefaultExtDirectory() {
|
||||
String home = SystemPropertyUtils.resolvePlaceholders("${spring.home:${SPRING_HOME:.}}");
|
||||
File extDirectory = new File(new File(home, "lib"), "ext");
|
||||
if (!extDirectory.isDirectory() && !extDirectory.mkdirs()) {
|
||||
throw new IllegalStateException("Failed to create ext directory " + extDirectory);
|
||||
}
|
||||
return extDirectory;
|
||||
}
|
||||
|
||||
private File getInstalled() {
|
||||
return new File(getDefaultExtDirectory(), ".installed");
|
||||
}
|
||||
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.install;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
|
||||
import org.springframework.boot.cli.command.Command;
|
||||
import org.springframework.boot.cli.command.OptionParsingCommand;
|
||||
import org.springframework.boot.cli.command.options.CompilerOptionHandler;
|
||||
import org.springframework.boot.cli.command.status.ExitStatus;
|
||||
import org.springframework.boot.cli.util.Log;
|
||||
|
||||
/**
|
||||
* {@link Command} to uninstall dependencies from the CLI's lib/ext directory.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class UninstallCommand extends OptionParsingCommand {
|
||||
|
||||
public UninstallCommand() {
|
||||
super("uninstall", "Uninstall dependencies from the lib/ext directory", new UninstallOptionHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageHelp() {
|
||||
return "[options] <coordinates>";
|
||||
}
|
||||
|
||||
private static class UninstallOptionHandler extends CompilerOptionHandler {
|
||||
|
||||
private OptionSpec<Void> allOption;
|
||||
|
||||
@Override
|
||||
protected void doOptions() {
|
||||
this.allOption = option("all", "Uninstall all");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ExitStatus run(OptionSet options) throws Exception {
|
||||
List<String> args = (List<String>) options.nonOptionArguments();
|
||||
try {
|
||||
if (options.has(this.allOption)) {
|
||||
if (!args.isEmpty()) {
|
||||
throw new IllegalArgumentException("Please use --all without specifying any dependencies");
|
||||
}
|
||||
new Installer(options, this).uninstallAll();
|
||||
}
|
||||
if (args.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Please specify at least one dependency, in the form group:artifact:version, to uninstall");
|
||||
}
|
||||
new Installer(options, this).uninstall(args);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
String message = ex.getMessage();
|
||||
Log.error((message != null) ? message : ex.getClass().toString());
|
||||
}
|
||||
return ExitStatus.OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* CLI commands for installing and uninstalling CLI dependencies.
|
||||
*/
|
||||
package org.springframework.boot.cli.command.install;
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.options;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import joptsimple.OptionSpec;
|
||||
|
||||
/**
|
||||
* An {@link OptionHandler} for commands that result in the compilation of one or more
|
||||
* Groovy scripts.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class CompilerOptionHandler extends OptionHandler {
|
||||
|
||||
private OptionSpec<Void> noGuessImportsOption;
|
||||
|
||||
private OptionSpec<Void> noGuessDependenciesOption;
|
||||
|
||||
private OptionSpec<Boolean> autoconfigureOption;
|
||||
|
||||
private OptionSpec<String> classpathOption;
|
||||
|
||||
@Override
|
||||
protected final void options() {
|
||||
this.noGuessImportsOption = option("no-guess-imports", "Do not attempt to guess imports");
|
||||
this.noGuessDependenciesOption = option("no-guess-dependencies", "Do not attempt to guess dependencies");
|
||||
this.autoconfigureOption = option("autoconfigure", "Add autoconfigure compiler transformations")
|
||||
.withOptionalArg().ofType(Boolean.class).defaultsTo(true);
|
||||
this.classpathOption = option(Arrays.asList("classpath", "cp"), "Additional classpath entries")
|
||||
.withRequiredArg();
|
||||
doOptions();
|
||||
}
|
||||
|
||||
protected void doOptions() {
|
||||
}
|
||||
|
||||
public OptionSpec<Void> getNoGuessImportsOption() {
|
||||
return this.noGuessImportsOption;
|
||||
}
|
||||
|
||||
public OptionSpec<Void> getNoGuessDependenciesOption() {
|
||||
return this.noGuessDependenciesOption;
|
||||
}
|
||||
|
||||
public OptionSpec<String> getClasspathOption() {
|
||||
return this.classpathOption;
|
||||
}
|
||||
|
||||
public OptionSpec<Boolean> getAutoconfigureOption() {
|
||||
return this.autoconfigureOption;
|
||||
}
|
||||
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.options;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerScope;
|
||||
import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory;
|
||||
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
||||
|
||||
/**
|
||||
* Simple adapter class to present an {@link OptionSet} as a
|
||||
* {@link GroovyCompilerConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class OptionSetGroovyCompilerConfiguration implements GroovyCompilerConfiguration {
|
||||
|
||||
private final OptionSet options;
|
||||
|
||||
private final CompilerOptionHandler optionHandler;
|
||||
|
||||
private final List<RepositoryConfiguration> repositoryConfiguration;
|
||||
|
||||
protected OptionSetGroovyCompilerConfiguration(OptionSet optionSet, CompilerOptionHandler compilerOptionHandler) {
|
||||
this(optionSet, compilerOptionHandler, RepositoryConfigurationFactory.createDefaultRepositoryConfiguration());
|
||||
}
|
||||
|
||||
public OptionSetGroovyCompilerConfiguration(OptionSet optionSet, CompilerOptionHandler compilerOptionHandler,
|
||||
List<RepositoryConfiguration> repositoryConfiguration) {
|
||||
this.options = optionSet;
|
||||
this.optionHandler = compilerOptionHandler;
|
||||
this.repositoryConfiguration = repositoryConfiguration;
|
||||
}
|
||||
|
||||
protected OptionSet getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroovyCompilerScope getScope() {
|
||||
return GroovyCompilerScope.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGuessImports() {
|
||||
return !this.options.has(this.optionHandler.getNoGuessImportsOption());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGuessDependencies() {
|
||||
return !this.options.has(this.optionHandler.getNoGuessDependenciesOption());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoconfigure() {
|
||||
return this.optionHandler.getAutoconfigureOption().value(this.options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getClasspath() {
|
||||
OptionSpec<String> classpathOption = this.optionHandler.getClasspathOption();
|
||||
if (this.options.has(classpathOption)) {
|
||||
return this.options.valueOf(classpathOption).split(":");
|
||||
}
|
||||
return DEFAULT_CLASSPATH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RepositoryConfiguration> getRepositoryConfiguration() {
|
||||
return this.repositoryConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQuiet() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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.command.options;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import joptsimple.OptionSet;
|
||||
|
||||
import org.springframework.boot.cli.util.ResourceUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Extract source file options (anything following '--' in an {@link OptionSet}).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @author Greg Turnquist
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SourceOptions {
|
||||
|
||||
private final List<String> sources;
|
||||
|
||||
private final List<?> args;
|
||||
|
||||
/**
|
||||
* Create a new {@link SourceOptions} instance.
|
||||
* @param options the source option set
|
||||
*/
|
||||
public SourceOptions(OptionSet options) {
|
||||
this(options, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SourceOptions} instance.
|
||||
* @param arguments the source arguments
|
||||
*/
|
||||
public SourceOptions(List<?> arguments) {
|
||||
this(arguments, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SourceOptions} instance. If it is an error to pass options that
|
||||
* specify non-existent sources, but the default paths are allowed not to exist (the
|
||||
* paths are tested before use). If default paths are provided and the option set
|
||||
* contains no source file arguments it is not an error even if none of the default
|
||||
* paths exist.
|
||||
* @param optionSet the source option set
|
||||
* @param classLoader an optional classloader used to try and load files that are not
|
||||
* found in the local filesystem
|
||||
*/
|
||||
public SourceOptions(OptionSet optionSet, ClassLoader classLoader) {
|
||||
this(optionSet.nonOptionArguments(), classLoader);
|
||||
}
|
||||
|
||||
private SourceOptions(List<?> nonOptionArguments, ClassLoader classLoader) {
|
||||
List<String> sources = new ArrayList<>();
|
||||
int sourceArgCount = 0;
|
||||
for (Object option : nonOptionArguments) {
|
||||
if (option instanceof String filename) {
|
||||
if ("--".equals(filename)) {
|
||||
break;
|
||||
}
|
||||
List<String> urls = new ArrayList<>();
|
||||
File fileCandidate = new File(filename);
|
||||
if (fileCandidate.isFile()) {
|
||||
urls.add(fileCandidate.getAbsoluteFile().toURI().toString());
|
||||
}
|
||||
else if (!isAbsoluteWindowsFile(fileCandidate)) {
|
||||
urls.addAll(ResourceUtils.getUrls(filename, classLoader));
|
||||
}
|
||||
for (String url : urls) {
|
||||
if (isSource(url)) {
|
||||
sources.add(url);
|
||||
}
|
||||
}
|
||||
if (isSource(filename)) {
|
||||
if (urls.isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't find " + filename);
|
||||
}
|
||||
else {
|
||||
sourceArgCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.args = Collections.unmodifiableList(nonOptionArguments.subList(sourceArgCount, nonOptionArguments.size()));
|
||||
Assert.isTrue(!sources.isEmpty(), "Please specify at least one file");
|
||||
this.sources = Collections.unmodifiableList(sources);
|
||||
}
|
||||
|
||||
private boolean isAbsoluteWindowsFile(File file) {
|
||||
return isWindows() && file.isAbsolute();
|
||||
}
|
||||
|
||||
private boolean isWindows() {
|
||||
return File.separatorChar == '\\';
|
||||
}
|
||||
|
||||
private boolean isSource(String name) {
|
||||
return name.endsWith(".java") || name.endsWith(".groovy");
|
||||
}
|
||||
|
||||
public List<?> getArgs() {
|
||||
return this.args;
|
||||
}
|
||||
|
||||
public String[] getArgsArray() {
|
||||
return this.args.stream().map(this::asString).toArray(String[]::new);
|
||||
}
|
||||
|
||||
private String asString(Object arg) {
|
||||
return (arg != null) ? String.valueOf(arg) : null;
|
||||
}
|
||||
|
||||
public List<String> getSources() {
|
||||
return this.sources;
|
||||
}
|
||||
|
||||
public String[] getSourcesArray() {
|
||||
return StringUtils.toStringArray(this.sources);
|
||||
}
|
||||
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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.command.run;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
|
||||
import org.springframework.boot.cli.command.Command;
|
||||
import org.springframework.boot.cli.command.OptionParsingCommand;
|
||||
import org.springframework.boot.cli.command.options.CompilerOptionHandler;
|
||||
import org.springframework.boot.cli.command.options.OptionSetGroovyCompilerConfiguration;
|
||||
import org.springframework.boot.cli.command.options.SourceOptions;
|
||||
import org.springframework.boot.cli.command.status.ExitStatus;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerScope;
|
||||
import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory;
|
||||
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
||||
|
||||
/**
|
||||
* {@link Command} to 'run' a groovy script or scripts.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
* @see SpringApplicationRunner
|
||||
*/
|
||||
public class RunCommand extends OptionParsingCommand {
|
||||
|
||||
public RunCommand() {
|
||||
super("run", "Run a spring groovy script", new RunOptionHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageHelp() {
|
||||
return "[options] <files> [--] [args]";
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (getHandler() != null) {
|
||||
((RunOptionHandler) getHandler()).stop();
|
||||
}
|
||||
}
|
||||
|
||||
private static class RunOptionHandler extends CompilerOptionHandler {
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private OptionSpec<Void> watchOption;
|
||||
|
||||
private OptionSpec<Void> verboseOption;
|
||||
|
||||
private OptionSpec<Void> quietOption;
|
||||
|
||||
private SpringApplicationRunner runner;
|
||||
|
||||
@Override
|
||||
protected void doOptions() {
|
||||
this.watchOption = option("watch", "Watch the specified file for changes");
|
||||
this.verboseOption = option(Arrays.asList("verbose", "v"), "Verbose logging of dependency resolution");
|
||||
this.quietOption = option(Arrays.asList("quiet", "q"), "Quiet logging");
|
||||
}
|
||||
|
||||
void stop() {
|
||||
synchronized (this.monitor) {
|
||||
if (this.runner != null) {
|
||||
this.runner.stop();
|
||||
}
|
||||
this.runner = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized ExitStatus run(OptionSet options) throws Exception {
|
||||
synchronized (this.monitor) {
|
||||
if (this.runner != null) {
|
||||
throw new RuntimeException(
|
||||
"Already running. Please stop the current application before running another (use the 'stop' command).");
|
||||
}
|
||||
|
||||
SourceOptions sourceOptions = new SourceOptions(options);
|
||||
|
||||
List<RepositoryConfiguration> repositoryConfiguration = RepositoryConfigurationFactory
|
||||
.createDefaultRepositoryConfiguration();
|
||||
repositoryConfiguration.add(0,
|
||||
new RepositoryConfiguration("local", new File("repository").toURI(), true));
|
||||
|
||||
SpringApplicationRunnerConfiguration configuration = new SpringApplicationRunnerConfigurationAdapter(
|
||||
options, this, repositoryConfiguration);
|
||||
|
||||
this.runner = new SpringApplicationRunner(configuration, sourceOptions.getSourcesArray(),
|
||||
sourceOptions.getArgsArray());
|
||||
this.runner.compileAndRun();
|
||||
|
||||
return ExitStatus.OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple adapter class to present the {@link OptionSet} as a
|
||||
* {@link SpringApplicationRunnerConfiguration}.
|
||||
*/
|
||||
private class SpringApplicationRunnerConfigurationAdapter extends OptionSetGroovyCompilerConfiguration
|
||||
implements SpringApplicationRunnerConfiguration {
|
||||
|
||||
SpringApplicationRunnerConfigurationAdapter(OptionSet options, CompilerOptionHandler optionHandler,
|
||||
List<RepositoryConfiguration> repositoryConfiguration) {
|
||||
super(options, optionHandler, repositoryConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroovyCompilerScope getScope() {
|
||||
return GroovyCompilerScope.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWatchForFileChanges() {
|
||||
return getOptions().has(RunOptionHandler.this.watchOption);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Level getLogLevel() {
|
||||
if (isQuiet()) {
|
||||
return Level.OFF;
|
||||
}
|
||||
if (getOptions().has(RunOptionHandler.this.verboseOption)) {
|
||||
return Level.FINEST;
|
||||
}
|
||||
return Level.INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQuiet() {
|
||||
return getOptions().has(RunOptionHandler.this.quietOption);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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.command.run;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.springframework.boot.cli.app.SpringApplicationLauncher;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompiler;
|
||||
import org.springframework.boot.cli.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
* Compiles Groovy code running the resulting classes using a {@code SpringApplication}.
|
||||
* Takes care of threading and class-loading issues and can optionally monitor sources for
|
||||
* changes.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SpringApplicationRunner {
|
||||
|
||||
private static int watcherCounter = 0;
|
||||
|
||||
private static int runnerCounter = 0;
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final SpringApplicationRunnerConfiguration configuration;
|
||||
|
||||
private final String[] sources;
|
||||
|
||||
private final String[] args;
|
||||
|
||||
private final GroovyCompiler compiler;
|
||||
|
||||
private RunThread runThread;
|
||||
|
||||
private FileWatchThread fileWatchThread;
|
||||
|
||||
/**
|
||||
* Create a new {@link SpringApplicationRunner} instance.
|
||||
* @param configuration the configuration
|
||||
* @param sources the files to compile/watch
|
||||
* @param args input arguments
|
||||
*/
|
||||
SpringApplicationRunner(SpringApplicationRunnerConfiguration configuration, String[] sources, String... args) {
|
||||
this.configuration = configuration;
|
||||
this.sources = sources.clone();
|
||||
this.args = args.clone();
|
||||
this.compiler = new GroovyCompiler(configuration);
|
||||
int level = configuration.getLogLevel().intValue();
|
||||
if (level <= Level.FINER.intValue()) {
|
||||
System.setProperty("org.springframework.boot.cli.compiler.grape.ProgressReporter", "detail");
|
||||
System.setProperty("trace", "true");
|
||||
}
|
||||
else if (level <= Level.FINE.intValue()) {
|
||||
System.setProperty("debug", "true");
|
||||
}
|
||||
else if (level == Level.OFF.intValue()) {
|
||||
System.setProperty("spring.main.banner-mode", "OFF");
|
||||
System.setProperty("logging.level.ROOT", "OFF");
|
||||
System.setProperty("org.springframework.boot.cli.compiler.grape.ProgressReporter", "none");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile and run the application.
|
||||
* @throws Exception on error
|
||||
*/
|
||||
public void compileAndRun() throws Exception {
|
||||
synchronized (this.monitor) {
|
||||
try {
|
||||
stop();
|
||||
Class<?>[] compiledSources = compile();
|
||||
monitorForChanges();
|
||||
// Run in new thread to ensure that the context classloader is set up
|
||||
this.runThread = new RunThread(compiledSources);
|
||||
this.runThread.start();
|
||||
this.runThread.join();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (this.fileWatchThread == null) {
|
||||
throw ex;
|
||||
}
|
||||
else {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
synchronized (this.monitor) {
|
||||
if (this.runThread != null) {
|
||||
this.runThread.shutdown();
|
||||
this.runThread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?>[] compile() throws IOException {
|
||||
Class<?>[] compiledSources = this.compiler.compile(this.sources);
|
||||
if (compiledSources.length == 0) {
|
||||
throw new RuntimeException("No classes found in '" + Arrays.toString(this.sources) + "'");
|
||||
}
|
||||
return compiledSources;
|
||||
}
|
||||
|
||||
private void monitorForChanges() {
|
||||
if (this.fileWatchThread == null && this.configuration.isWatchForFileChanges()) {
|
||||
this.fileWatchThread = new FileWatchThread();
|
||||
this.fileWatchThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread used to launch the Spring Application with the correct context classloader.
|
||||
*/
|
||||
private class RunThread extends Thread {
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final Class<?>[] compiledSources;
|
||||
|
||||
private Object applicationContext;
|
||||
|
||||
/**
|
||||
* Create a new {@link RunThread} instance.
|
||||
* @param compiledSources the sources to launch
|
||||
*/
|
||||
RunThread(Class<?>... compiledSources) {
|
||||
super("runner-" + (runnerCounter++));
|
||||
this.compiledSources = compiledSources;
|
||||
if (compiledSources.length != 0) {
|
||||
setContextClassLoader(compiledSources[0].getClassLoader());
|
||||
}
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (this.monitor) {
|
||||
try {
|
||||
this.applicationContext = new SpringApplicationLauncher(getContextClassLoader())
|
||||
.launch(this.compiledSources, SpringApplicationRunner.this.args);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the thread, closing any previously opened application context.
|
||||
*/
|
||||
void shutdown() {
|
||||
synchronized (this.monitor) {
|
||||
if (this.applicationContext != null) {
|
||||
try {
|
||||
Method method = this.applicationContext.getClass().getMethod("close");
|
||||
method.invoke(this.applicationContext);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
// Not an application context that we can close
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
this.applicationContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread to watch for file changes and trigger recompile/reload.
|
||||
*/
|
||||
private class FileWatchThread extends Thread {
|
||||
|
||||
private long previous;
|
||||
|
||||
private List<File> sources;
|
||||
|
||||
FileWatchThread() {
|
||||
super("filewatcher-" + (watcherCounter++));
|
||||
this.previous = 0;
|
||||
this.sources = getSourceFiles();
|
||||
for (File file : this.sources) {
|
||||
if (file.exists()) {
|
||||
long current = file.lastModified();
|
||||
if (current > this.previous) {
|
||||
this.previous = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
setDaemon(false);
|
||||
}
|
||||
|
||||
private List<File> getSourceFiles() {
|
||||
List<File> sources = new ArrayList<>();
|
||||
for (String source : SpringApplicationRunner.this.sources) {
|
||||
List<String> paths = ResourceUtils.getUrls(source, SpringApplicationRunner.this.compiler.getLoader());
|
||||
for (String path : paths) {
|
||||
try {
|
||||
URL url = new URL(path);
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
sources.add(new File(url.getFile()));
|
||||
}
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
|
||||
for (File file : this.sources) {
|
||||
if (file.exists()) {
|
||||
long current = file.lastModified();
|
||||
if (this.previous < current) {
|
||||
this.previous = current;
|
||||
compileAndRun();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Swallow, will be reported by compileAndRun
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.command.run;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
||||
|
||||
/**
|
||||
* Configuration for the {@link SpringApplicationRunner}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface SpringApplicationRunnerConfiguration extends GroovyCompilerConfiguration {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the source file should be monitored for changes and
|
||||
* automatically recompiled.
|
||||
* @return {@code true} if file watching should be performed, otherwise {@code false}
|
||||
*/
|
||||
boolean isWatchForFileChanges();
|
||||
|
||||
/**
|
||||
* Returns the logging level to use.
|
||||
* @return the logging level
|
||||
*/
|
||||
Level getLogLevel();
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes for running CLI applications.
|
||||
*/
|
||||
package org.springframework.boot.cli.command.run;
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.codehaus.groovy.ast.ASTNode;
|
||||
import org.codehaus.groovy.ast.AnnotatedNode;
|
||||
import org.codehaus.groovy.ast.AnnotationNode;
|
||||
import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.ImportNode;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.transform.ASTTransformation;
|
||||
|
||||
/**
|
||||
* A base class for {@link ASTTransformation AST transformations} that are solely
|
||||
* interested in {@link AnnotatedNode AnnotatedNodes}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public abstract class AnnotatedNodeASTTransformation implements ASTTransformation {
|
||||
|
||||
private final Set<String> interestingAnnotationNames;
|
||||
|
||||
private final boolean removeAnnotations;
|
||||
|
||||
private SourceUnit sourceUnit;
|
||||
|
||||
protected AnnotatedNodeASTTransformation(Set<String> interestingAnnotationNames, boolean removeAnnotations) {
|
||||
this.interestingAnnotationNames = interestingAnnotationNames;
|
||||
this.removeAnnotations = removeAnnotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ASTNode[] nodes, SourceUnit source) {
|
||||
this.sourceUnit = source;
|
||||
List<AnnotationNode> annotationNodes = new ArrayList<>();
|
||||
ClassVisitor classVisitor = new ClassVisitor(source, annotationNodes);
|
||||
for (ASTNode node : nodes) {
|
||||
if (node instanceof ModuleNode module) {
|
||||
visitAnnotatedNode(module.getPackage(), annotationNodes);
|
||||
for (ImportNode importNode : module.getImports()) {
|
||||
visitAnnotatedNode(importNode, annotationNodes);
|
||||
}
|
||||
for (ImportNode importNode : module.getStarImports()) {
|
||||
visitAnnotatedNode(importNode, annotationNodes);
|
||||
}
|
||||
module.getStaticImports()
|
||||
.forEach((name, importNode) -> visitAnnotatedNode(importNode, annotationNodes));
|
||||
module.getStaticStarImports()
|
||||
.forEach((name, importNode) -> visitAnnotatedNode(importNode, annotationNodes));
|
||||
for (ClassNode classNode : module.getClasses()) {
|
||||
visitAnnotatedNode(classNode, annotationNodes);
|
||||
classNode.visitContents(classVisitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
processAnnotationNodes(annotationNodes);
|
||||
}
|
||||
|
||||
protected SourceUnit getSourceUnit() {
|
||||
return this.sourceUnit;
|
||||
}
|
||||
|
||||
protected abstract void processAnnotationNodes(List<AnnotationNode> annotationNodes);
|
||||
|
||||
private void visitAnnotatedNode(AnnotatedNode annotatedNode, List<AnnotationNode> annotatedNodes) {
|
||||
if (annotatedNode != null) {
|
||||
Iterator<AnnotationNode> annotationNodes = annotatedNode.getAnnotations().iterator();
|
||||
while (annotationNodes.hasNext()) {
|
||||
AnnotationNode annotationNode = annotationNodes.next();
|
||||
if (this.interestingAnnotationNames.contains(annotationNode.getClassNode().getName())) {
|
||||
annotatedNodes.add(annotationNode);
|
||||
if (this.removeAnnotations) {
|
||||
annotationNodes.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassVisitor extends ClassCodeVisitorSupport {
|
||||
|
||||
private final SourceUnit source;
|
||||
|
||||
private final List<AnnotationNode> annotationNodes;
|
||||
|
||||
ClassVisitor(SourceUnit source, List<AnnotationNode> annotationNodes) {
|
||||
this.source = source;
|
||||
this.annotationNodes = annotationNodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SourceUnit getSourceUnit() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnnotations(AnnotatedNode node) {
|
||||
visitAnnotatedNode(node, this.annotationNodes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
|
||||
import org.codehaus.groovy.ast.expr.ClosureExpression;
|
||||
import org.codehaus.groovy.ast.expr.ConstantExpression;
|
||||
import org.codehaus.groovy.ast.expr.Expression;
|
||||
import org.codehaus.groovy.ast.expr.MethodCallExpression;
|
||||
import org.codehaus.groovy.ast.stmt.BlockStatement;
|
||||
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
|
||||
import org.codehaus.groovy.ast.stmt.Statement;
|
||||
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* General purpose AST utilities.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @author Greg Turnquist
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class AstUtils {
|
||||
|
||||
/**
|
||||
* Determine if a {@link ClassNode} has one or more of the specified annotations on
|
||||
* the class or any of its methods. N.B. the type names are not normally fully
|
||||
* qualified.
|
||||
* @param node the class to examine
|
||||
* @param annotations the annotations to look for
|
||||
* @return {@code true} if at least one of the annotations is found, otherwise
|
||||
* {@code false}
|
||||
*/
|
||||
public static boolean hasAtLeastOneAnnotation(ClassNode node, String... annotations) {
|
||||
if (hasAtLeastOneAnnotation((AnnotatedNode) node, annotations)) {
|
||||
return true;
|
||||
}
|
||||
for (MethodNode method : node.getMethods()) {
|
||||
if (hasAtLeastOneAnnotation(method, annotations)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an {@link AnnotatedNode} has one or more of the specified annotations.
|
||||
* N.B. the annotation type names are not normally fully qualified.
|
||||
* @param node the node to examine
|
||||
* @param annotations the annotations to look for
|
||||
* @return {@code true} if at least one of the annotations is found, otherwise
|
||||
* {@code false}
|
||||
*/
|
||||
public static boolean hasAtLeastOneAnnotation(AnnotatedNode node, String... annotations) {
|
||||
for (AnnotationNode annotationNode : node.getAnnotations()) {
|
||||
for (String annotation : annotations) {
|
||||
if (PatternMatchUtils.simpleMatch(annotation, annotationNode.getClassNode().getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a {@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.
|
||||
* @param node the class to examine
|
||||
* @param types the types to look for
|
||||
* @return {@code true} if at least one of the types is found, otherwise {@code false}
|
||||
*/
|
||||
public static boolean hasAtLeastOneFieldOrMethod(ClassNode node, String... types) {
|
||||
Set<String> typesSet = new HashSet<>(Arrays.asList(types));
|
||||
for (FieldNode field : node.getFields()) {
|
||||
if (typesSet.contains(field.getType().getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (MethodNode method : node.getMethods()) {
|
||||
if (typesSet.contains(method.getReturnType().getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a {@link ClassNode} subclasses any of the specified types N.B. the
|
||||
* type names are not normally fully qualified.
|
||||
* @param node the class to examine
|
||||
* @param types the types that may have been sub-classed
|
||||
* @return {@code true} if the class subclasses any of the specified types, otherwise
|
||||
* {@code false}
|
||||
*/
|
||||
public static boolean subclasses(ClassNode node, String... types) {
|
||||
for (String type : types) {
|
||||
if (node.getSuperClass().getName().equals(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasAtLeastOneInterface(ClassNode classNode, String... types) {
|
||||
Set<String> typesSet = new HashSet<>(Arrays.asList(types));
|
||||
for (ClassNode inter : classNode.getInterfaces()) {
|
||||
if (typesSet.contains(inter.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a top-level {@code name} closure from inside this block if there is one,
|
||||
* optionally removing it from the block at the same time.
|
||||
* @param block a block statement (class definition)
|
||||
* @param name the name to look for
|
||||
* @param remove whether the extracted closure should be removed
|
||||
* @return a beans Closure if one can be found, null otherwise
|
||||
*/
|
||||
public static ClosureExpression getClosure(BlockStatement block, String name, boolean remove) {
|
||||
for (ExpressionStatement statement : getExpressionStatements(block)) {
|
||||
Expression expression = statement.getExpression();
|
||||
if (expression instanceof MethodCallExpression methodCallExpression) {
|
||||
ClosureExpression closure = getClosure(name, methodCallExpression);
|
||||
if (closure != null) {
|
||||
if (remove) {
|
||||
block.getStatements().remove(statement);
|
||||
}
|
||||
return closure;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<ExpressionStatement> getExpressionStatements(BlockStatement block) {
|
||||
List<ExpressionStatement> statements = new ArrayList<>();
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if (statement instanceof ExpressionStatement expressionStatement) {
|
||||
statements.add(expressionStatement);
|
||||
}
|
||||
}
|
||||
return statements;
|
||||
}
|
||||
|
||||
private static ClosureExpression getClosure(String name, MethodCallExpression expression) {
|
||||
Expression method = expression.getMethod();
|
||||
if (method instanceof ConstantExpression constantExpression && name.equals(constantExpression.getValue())) {
|
||||
return (ClosureExpression) ((ArgumentListExpression) expression.getArguments()).getExpression(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ClosureExpression getClosure(BlockStatement block, String name) {
|
||||
return getClosure(block, name, false);
|
||||
}
|
||||
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.classgen.GeneratorContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
|
||||
/**
|
||||
* Strategy that can be used to apply some auto-configuration during the
|
||||
* {@link CompilePhase#CONVERSION} Groovy compile phase.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class CompilerAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Strategy method used to determine when compiler auto-configuration should be
|
||||
* applied. Defaults to always.
|
||||
* @param classNode the class node
|
||||
* @return {@code true} if the compiler should be auto-configured using this class. If
|
||||
* this method returns {@code false} no other strategy methods will be called.
|
||||
*/
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any dependency customizations. This method will only be called if
|
||||
* {@link #matches} returns {@code true}.
|
||||
* @param dependencies dependency customizer
|
||||
* @throws CompilationFailedException if the dependencies cannot be applied
|
||||
*/
|
||||
public void applyDependencies(DependencyCustomizer dependencies) throws CompilationFailedException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any import customizations. This method will only be called if
|
||||
* {@link #matches} returns {@code true}.
|
||||
* @param imports import customizer
|
||||
* @throws CompilationFailedException if the imports cannot be applied
|
||||
*/
|
||||
public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any customizations to the main class. This method will only be called if
|
||||
* {@link #matches} returns {@code true}. This method is useful when a groovy file
|
||||
* defines more than one class but customization only applies to the first class.
|
||||
* @param loader the class loader being used during compilation
|
||||
* @param configuration the compiler configuration
|
||||
* @param generatorContext the current context
|
||||
* @param source the source unit
|
||||
* @param classNode the main class
|
||||
* @throws CompilationFailedException if the customizations cannot be applied
|
||||
*/
|
||||
public void applyToMainClass(GroovyClassLoader loader, GroovyCompilerConfiguration configuration,
|
||||
GeneratorContext generatorContext, SourceUnit source, ClassNode classNode)
|
||||
throws CompilationFailedException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any additional configuration.
|
||||
* @param loader the class loader being used during compilation
|
||||
* @param configuration the compiler configuration
|
||||
* @param generatorContext the current context
|
||||
* @param source the source unit
|
||||
* @param classNode the class
|
||||
* @throws CompilationFailedException if the configuration cannot be applied
|
||||
*/
|
||||
public void apply(GroovyClassLoader loader, GroovyCompilerConfiguration configuration,
|
||||
GeneratorContext generatorContext, SourceUnit source, ClassNode classNode)
|
||||
throws CompilationFailedException {
|
||||
}
|
||||
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.ast.ASTNode;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.transform.ASTTransformation;
|
||||
|
||||
import org.springframework.boot.cli.compiler.grape.DependencyResolutionContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* {@link ASTTransformation} to apply
|
||||
* {@link CompilerAutoConfiguration#applyDependencies(DependencyCustomizer) dependency
|
||||
* auto-configuration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Order(DependencyAutoConfigurationTransformation.ORDER)
|
||||
public class DependencyAutoConfigurationTransformation implements ASTTransformation {
|
||||
|
||||
/**
|
||||
* The order of the transformation.
|
||||
*/
|
||||
public static final int ORDER = DependencyManagementBomTransformation.ORDER + 100;
|
||||
|
||||
private final GroovyClassLoader loader;
|
||||
|
||||
private final DependencyResolutionContext dependencyResolutionContext;
|
||||
|
||||
private final Iterable<CompilerAutoConfiguration> compilerAutoConfigurations;
|
||||
|
||||
public DependencyAutoConfigurationTransformation(GroovyClassLoader loader,
|
||||
DependencyResolutionContext dependencyResolutionContext,
|
||||
Iterable<CompilerAutoConfiguration> compilerAutoConfigurations) {
|
||||
this.loader = loader;
|
||||
this.dependencyResolutionContext = dependencyResolutionContext;
|
||||
this.compilerAutoConfigurations = compilerAutoConfigurations;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ASTNode[] nodes, SourceUnit source) {
|
||||
for (ASTNode astNode : nodes) {
|
||||
if (astNode instanceof ModuleNode moduleNode) {
|
||||
visitModule(moduleNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visitModule(ModuleNode module) {
|
||||
DependencyCustomizer dependencies = new DependencyCustomizer(this.loader, module,
|
||||
this.dependencyResolutionContext);
|
||||
for (ClassNode classNode : module.getClasses()) {
|
||||
for (CompilerAutoConfiguration autoConfiguration : this.compilerAutoConfigurations) {
|
||||
if (autoConfiguration.matches(classNode)) {
|
||||
autoConfiguration.applyDependencies(dependencies);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,262 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import groovy.lang.Grab;
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.ast.AnnotationNode;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
import org.codehaus.groovy.ast.expr.ConstantExpression;
|
||||
|
||||
import org.springframework.boot.cli.compiler.dependencies.ArtifactCoordinatesResolver;
|
||||
import org.springframework.boot.cli.compiler.grape.DependencyResolutionContext;
|
||||
|
||||
/**
|
||||
* Customizer that allows dependencies to be added during compilation. Adding a dependency
|
||||
* results in a {@link Grab @Grab} annotation being added to the primary {@link ClassNode
|
||||
* class} is the {@link ModuleNode module} that's being customized.
|
||||
* <p>
|
||||
* This class provides a fluent API for conditionally adding dependencies. For example:
|
||||
* {@code dependencies.ifMissing("com.corp.SomeClass").add(module)}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class DependencyCustomizer {
|
||||
|
||||
private final GroovyClassLoader loader;
|
||||
|
||||
private final ClassNode classNode;
|
||||
|
||||
private final DependencyResolutionContext dependencyResolutionContext;
|
||||
|
||||
/**
|
||||
* Create a new {@link DependencyCustomizer} instance.
|
||||
* @param loader the current classloader
|
||||
* @param moduleNode the current module
|
||||
* @param dependencyResolutionContext the context for dependency resolution
|
||||
*/
|
||||
public DependencyCustomizer(GroovyClassLoader loader, ModuleNode moduleNode,
|
||||
DependencyResolutionContext dependencyResolutionContext) {
|
||||
this.loader = loader;
|
||||
this.classNode = moduleNode.getClasses().get(0);
|
||||
this.dependencyResolutionContext = dependencyResolutionContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new nested {@link DependencyCustomizer}.
|
||||
* @param parent the parent customizer
|
||||
*/
|
||||
protected DependencyCustomizer(DependencyCustomizer parent) {
|
||||
this.loader = parent.loader;
|
||||
this.classNode = parent.classNode;
|
||||
this.dependencyResolutionContext = parent.dependencyResolutionContext;
|
||||
}
|
||||
|
||||
public String getVersion(String artifactId) {
|
||||
return getVersion(artifactId, "");
|
||||
}
|
||||
|
||||
public String getVersion(String artifactId, String defaultVersion) {
|
||||
String version = this.dependencyResolutionContext.getArtifactCoordinatesResolver().getVersion(artifactId);
|
||||
if (version == null) {
|
||||
version = defaultVersion;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a nested {@link DependencyCustomizer} that only applies if any of the
|
||||
* specified class names are not on the class path.
|
||||
* @param classNames the class names to test
|
||||
* @return a nested {@link DependencyCustomizer}
|
||||
*/
|
||||
public DependencyCustomizer ifAnyMissingClasses(String... classNames) {
|
||||
return new DependencyCustomizer(this) {
|
||||
@Override
|
||||
protected boolean canAdd() {
|
||||
for (String className : classNames) {
|
||||
try {
|
||||
Class.forName(className, false, DependencyCustomizer.this.loader);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a nested {@link DependencyCustomizer} that only applies if all the specified
|
||||
* class names are not on the class path.
|
||||
* @param classNames the class names to test
|
||||
* @return a nested {@link DependencyCustomizer}
|
||||
*/
|
||||
public DependencyCustomizer ifAllMissingClasses(String... classNames) {
|
||||
return new DependencyCustomizer(this) {
|
||||
@Override
|
||||
protected boolean canAdd() {
|
||||
for (String className : classNames) {
|
||||
try {
|
||||
Class.forName(className, false, DependencyCustomizer.this.loader);
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// swallow exception and continue
|
||||
}
|
||||
}
|
||||
return DependencyCustomizer.this.canAdd();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a nested {@link DependencyCustomizer} that only applies if the specified
|
||||
* paths are on the class path.
|
||||
* @param paths the paths to test
|
||||
* @return a nested {@link DependencyCustomizer}
|
||||
*/
|
||||
public DependencyCustomizer ifAllResourcesPresent(String... paths) {
|
||||
return new DependencyCustomizer(this) {
|
||||
@Override
|
||||
protected boolean canAdd() {
|
||||
for (String path : paths) {
|
||||
try {
|
||||
if (DependencyCustomizer.this.loader.getResource(path) == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// swallow exception and continue
|
||||
}
|
||||
}
|
||||
return DependencyCustomizer.this.canAdd();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a nested {@link DependencyCustomizer} that only applies at least one of the
|
||||
* specified paths is on the class path.
|
||||
* @param paths the paths to test
|
||||
* @return a nested {@link DependencyCustomizer}
|
||||
*/
|
||||
public DependencyCustomizer ifAnyResourcesPresent(String... paths) {
|
||||
return new DependencyCustomizer(this) {
|
||||
@Override
|
||||
protected boolean canAdd() {
|
||||
for (String path : paths) {
|
||||
try {
|
||||
return DependencyCustomizer.this.loader.getResource(path) != null;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// swallow exception and continue
|
||||
}
|
||||
}
|
||||
return DependencyCustomizer.this.canAdd();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dependencies and all of their dependencies. The group ID and version of the
|
||||
* dependencies are resolved from the modules using the customizer's
|
||||
* {@link ArtifactCoordinatesResolver}.
|
||||
* @param modules the module IDs
|
||||
* @return this {@link DependencyCustomizer} for continued use
|
||||
*/
|
||||
public DependencyCustomizer add(String... modules) {
|
||||
for (String module : modules) {
|
||||
add(module, null, null, true);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single dependency and, optionally, all of its dependencies. The group ID and
|
||||
* version of the dependency are resolved from the module using the customizer's
|
||||
* {@link ArtifactCoordinatesResolver}.
|
||||
* @param module the module ID
|
||||
* @param transitive {@code true} if the transitive dependencies should also be added,
|
||||
* otherwise {@code false}
|
||||
* @return this {@link DependencyCustomizer} for continued use
|
||||
*/
|
||||
public DependencyCustomizer add(String module, boolean transitive) {
|
||||
return add(module, null, null, transitive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single dependency with the specified classifier and type and, optionally, all
|
||||
* of its dependencies. The group ID and version of the dependency are resolved from
|
||||
* the module by using the customizer's {@link ArtifactCoordinatesResolver}.
|
||||
* @param module the module ID
|
||||
* @param classifier the classifier, may be {@code null}
|
||||
* @param type the type, may be {@code null}
|
||||
* @param transitive {@code true} if the transitive dependencies should also be added,
|
||||
* otherwise {@code false}
|
||||
* @return this {@link DependencyCustomizer} for continued use
|
||||
*/
|
||||
public DependencyCustomizer add(String module, String classifier, String type, boolean transitive) {
|
||||
if (canAdd()) {
|
||||
ArtifactCoordinatesResolver artifactCoordinatesResolver = this.dependencyResolutionContext
|
||||
.getArtifactCoordinatesResolver();
|
||||
this.classNode.addAnnotation(createGrabAnnotation(artifactCoordinatesResolver.getGroupId(module),
|
||||
artifactCoordinatesResolver.getArtifactId(module), artifactCoordinatesResolver.getVersion(module),
|
||||
classifier, type, transitive));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private AnnotationNode createGrabAnnotation(String group, String module, String version, String classifier,
|
||||
String type, boolean transitive) {
|
||||
AnnotationNode annotationNode = new AnnotationNode(new ClassNode(Grab.class));
|
||||
annotationNode.addMember("group", new ConstantExpression(group));
|
||||
annotationNode.addMember("module", new ConstantExpression(module));
|
||||
annotationNode.addMember("version", new ConstantExpression(version));
|
||||
if (classifier != null) {
|
||||
annotationNode.addMember("classifier", new ConstantExpression(classifier));
|
||||
}
|
||||
if (type != null) {
|
||||
annotationNode.addMember("type", new ConstantExpression(type));
|
||||
}
|
||||
annotationNode.addMember("transitive", new ConstantExpression(transitive));
|
||||
annotationNode.addMember("initClass", new ConstantExpression(false));
|
||||
return annotationNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy called to test if dependencies can be added. Subclasses override as
|
||||
* required. Returns {@code true} by default.
|
||||
* @return {@code true} if dependencies can be added, otherwise {@code false}
|
||||
*/
|
||||
protected boolean canAdd() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DependencyResolutionContext}.
|
||||
* @return the dependency resolution context
|
||||
*/
|
||||
public DependencyResolutionContext getDependencyResolutionContext() {
|
||||
return this.dependencyResolutionContext;
|
||||
}
|
||||
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import groovy.grape.Grape;
|
||||
import org.apache.maven.model.Dependency;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.Parent;
|
||||
import org.apache.maven.model.Repository;
|
||||
import org.apache.maven.model.building.DefaultModelBuilder;
|
||||
import org.apache.maven.model.building.DefaultModelBuilderFactory;
|
||||
import org.apache.maven.model.building.DefaultModelBuildingRequest;
|
||||
import org.apache.maven.model.resolution.InvalidRepositoryException;
|
||||
import org.apache.maven.model.resolution.ModelResolver;
|
||||
import org.apache.maven.model.resolution.UnresolvableModelException;
|
||||
import org.codehaus.groovy.ast.ASTNode;
|
||||
import org.codehaus.groovy.ast.AnnotationNode;
|
||||
import org.codehaus.groovy.ast.expr.ConstantExpression;
|
||||
import org.codehaus.groovy.ast.expr.Expression;
|
||||
import org.codehaus.groovy.ast.expr.ListExpression;
|
||||
import org.codehaus.groovy.control.messages.Message;
|
||||
import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
|
||||
import org.codehaus.groovy.syntax.SyntaxException;
|
||||
import org.codehaus.groovy.transform.ASTTransformation;
|
||||
|
||||
import org.springframework.boot.cli.compiler.dependencies.MavenModelDependencyManagement;
|
||||
import org.springframework.boot.cli.compiler.grape.DependencyResolutionContext;
|
||||
import org.springframework.boot.groovy.DependencyManagementBom;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* {@link ASTTransformation} for processing
|
||||
* {@link DependencyManagementBom @DependencyManagementBom} annotations.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Order(DependencyManagementBomTransformation.ORDER)
|
||||
@SuppressWarnings("deprecation")
|
||||
public class DependencyManagementBomTransformation extends AnnotatedNodeASTTransformation {
|
||||
|
||||
/**
|
||||
* The order of the transformation.
|
||||
*/
|
||||
public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 100;
|
||||
|
||||
private static final Set<String> DEPENDENCY_MANAGEMENT_BOM_ANNOTATION_NAMES = Collections
|
||||
.unmodifiableSet(new HashSet<>(Arrays.asList(DependencyManagementBom.class.getName(),
|
||||
DependencyManagementBom.class.getSimpleName())));
|
||||
|
||||
private final DependencyResolutionContext resolutionContext;
|
||||
|
||||
public DependencyManagementBomTransformation(DependencyResolutionContext resolutionContext) {
|
||||
super(DEPENDENCY_MANAGEMENT_BOM_ANNOTATION_NAMES, true);
|
||||
this.resolutionContext = resolutionContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processAnnotationNodes(List<AnnotationNode> annotationNodes) {
|
||||
if (!annotationNodes.isEmpty()) {
|
||||
if (annotationNodes.size() > 1) {
|
||||
for (AnnotationNode annotationNode : annotationNodes) {
|
||||
handleDuplicateDependencyManagementBomAnnotation(annotationNode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
processDependencyManagementBomAnnotation(annotationNodes.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDependencyManagementBomAnnotation(AnnotationNode annotationNode) {
|
||||
Expression valueExpression = annotationNode.getMember("value");
|
||||
List<Map<String, String>> bomDependencies = createDependencyMaps(valueExpression);
|
||||
updateDependencyResolutionContext(bomDependencies);
|
||||
}
|
||||
|
||||
private List<Map<String, String>> createDependencyMaps(Expression valueExpression) {
|
||||
Map<String, String> dependency = null;
|
||||
List<ConstantExpression> constantExpressions = getConstantExpressions(valueExpression);
|
||||
List<Map<String, String>> dependencies = new ArrayList<>(constantExpressions.size());
|
||||
for (ConstantExpression expression : constantExpressions) {
|
||||
Object value = expression.getValue();
|
||||
if (value instanceof String string) {
|
||||
String[] components = string.split(":");
|
||||
if (components.length == 3) {
|
||||
dependency = new HashMap<>();
|
||||
dependency.put("group", components[0]);
|
||||
dependency.put("module", components[1]);
|
||||
dependency.put("version", components[2]);
|
||||
dependency.put("type", "pom");
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
else {
|
||||
handleMalformedDependency(expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
private List<ConstantExpression> getConstantExpressions(Expression valueExpression) {
|
||||
if (valueExpression instanceof ListExpression listExpression) {
|
||||
return getConstantExpressions(listExpression);
|
||||
}
|
||||
if (valueExpression instanceof ConstantExpression constantExpression
|
||||
&& constantExpression.getValue() instanceof String) {
|
||||
return Arrays.asList(constantExpression);
|
||||
}
|
||||
reportError("@DependencyManagementBom requires an inline constant that is a string or a string array",
|
||||
valueExpression);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<ConstantExpression> getConstantExpressions(ListExpression valueExpression) {
|
||||
List<ConstantExpression> expressions = new ArrayList<>();
|
||||
for (Expression expression : valueExpression.getExpressions()) {
|
||||
if (expression instanceof ConstantExpression constantExpression
|
||||
&& constantExpression.getValue() instanceof String) {
|
||||
expressions.add(constantExpression);
|
||||
}
|
||||
else {
|
||||
reportError("Each entry in the array must be an inline string constant", expression);
|
||||
}
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
private void handleMalformedDependency(Expression expression) {
|
||||
Message message = createSyntaxErrorMessage(
|
||||
String.format("The string must be of the form \"group:module:version\"%n"), expression);
|
||||
getSourceUnit().getErrorCollector().addErrorAndContinue(message);
|
||||
}
|
||||
|
||||
private void updateDependencyResolutionContext(List<Map<String, String>> bomDependencies) {
|
||||
URI[] uris = Grape.getInstance().resolve(null, bomDependencies.toArray(new Map<?, ?>[0]));
|
||||
DefaultModelBuilder modelBuilder = new DefaultModelBuilderFactory().newInstance();
|
||||
for (URI uri : uris) {
|
||||
try {
|
||||
DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
|
||||
request.setModelResolver(new GrapeModelResolver());
|
||||
request.setModelSource(new org.apache.maven.model.building.UrlModelSource(uri.toURL()));
|
||||
request.setSystemProperties(System.getProperties());
|
||||
Model model = modelBuilder.build(request).getEffectiveModel();
|
||||
this.resolutionContext.addDependencyManagement(new MavenModelDependencyManagement(model));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Failed to build model for '" + uri + "'. Is it a valid Maven bom?",
|
||||
ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDuplicateDependencyManagementBomAnnotation(AnnotationNode annotationNode) {
|
||||
Message message = createSyntaxErrorMessage(
|
||||
"Duplicate @DependencyManagementBom annotation. It must be declared at most once.", annotationNode);
|
||||
getSourceUnit().getErrorCollector().addErrorAndContinue(message);
|
||||
}
|
||||
|
||||
private void reportError(String message, ASTNode node) {
|
||||
getSourceUnit().getErrorCollector().addErrorAndContinue(createSyntaxErrorMessage(message, node));
|
||||
}
|
||||
|
||||
private Message createSyntaxErrorMessage(String message, ASTNode node) {
|
||||
return new SyntaxErrorMessage(new SyntaxException(message, node.getLineNumber(), node.getColumnNumber(),
|
||||
node.getLastLineNumber(), node.getLastColumnNumber()), getSourceUnit());
|
||||
}
|
||||
|
||||
private static class GrapeModelResolver implements ModelResolver {
|
||||
|
||||
@Override
|
||||
public org.apache.maven.model.building.ModelSource resolveModel(Parent parent)
|
||||
throws UnresolvableModelException {
|
||||
return resolveModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.apache.maven.model.building.ModelSource resolveModel(Dependency dependency)
|
||||
throws UnresolvableModelException {
|
||||
return resolveModel(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.apache.maven.model.building.ModelSource resolveModel(String groupId, String artifactId,
|
||||
String version) throws UnresolvableModelException {
|
||||
Map<String, String> dependency = new HashMap<>();
|
||||
dependency.put("group", groupId);
|
||||
dependency.put("module", artifactId);
|
||||
dependency.put("version", version);
|
||||
dependency.put("type", "pom");
|
||||
try {
|
||||
return new org.apache.maven.model.building.UrlModelSource(
|
||||
Grape.getInstance().resolve(null, dependency)[0].toURL());
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new UnresolvableModelException(ex.getMessage(), groupId, artifactId, version);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRepository(Repository repository) throws InvalidRepositoryException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRepository(Repository repository, boolean replace) throws InvalidRepositoryException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelResolver newCopy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.control.CompilationUnit;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Extension of the {@link GroovyClassLoader} with support for obtaining '.class' files as
|
||||
* resources.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ExtendedGroovyClassLoader extends GroovyClassLoader {
|
||||
|
||||
private static final String SHARED_PACKAGE = "org.springframework.boot.groovy";
|
||||
|
||||
private static final URL[] NO_URLS = new URL[] {};
|
||||
|
||||
private final Map<String, byte[]> classResources = new HashMap<>();
|
||||
|
||||
private final GroovyCompilerScope scope;
|
||||
|
||||
private final CompilerConfiguration configuration;
|
||||
|
||||
public ExtendedGroovyClassLoader(GroovyCompilerScope scope) {
|
||||
this(scope, createParentClassLoader(scope), new CompilerConfiguration());
|
||||
}
|
||||
|
||||
private static ClassLoader createParentClassLoader(GroovyCompilerScope scope) {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if (scope == GroovyCompilerScope.DEFAULT) {
|
||||
classLoader = new DefaultScopeParentClassLoader(classLoader);
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
private ExtendedGroovyClassLoader(GroovyCompilerScope scope, ClassLoader parent,
|
||||
CompilerConfiguration configuration) {
|
||||
super(parent, configuration);
|
||||
this.configuration = configuration;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
try {
|
||||
return super.findClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if (this.scope == GroovyCompilerScope.DEFAULT && name.startsWith(SHARED_PACKAGE)) {
|
||||
Class<?> sharedClass = findSharedClass(name);
|
||||
if (sharedClass != null) {
|
||||
return sharedClass;
|
||||
}
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> findSharedClass(String name) {
|
||||
try {
|
||||
String path = name.replace('.', '/').concat(".class");
|
||||
try (InputStream inputStream = getParent().getResourceAsStream(path)) {
|
||||
if (inputStream != null) {
|
||||
return defineClass(name, FileCopyUtils.copyToByteArray(inputStream));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String name) {
|
||||
InputStream resourceStream = super.getResourceAsStream(name);
|
||||
if (resourceStream == null) {
|
||||
byte[] bytes = this.classResources.get(name);
|
||||
resourceStream = (bytes != null) ? new ByteArrayInputStream(bytes) : null;
|
||||
}
|
||||
return resourceStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassCollector createCollector(CompilationUnit unit, SourceUnit su) {
|
||||
return new ExtendedClassCollector(getInnerLoader(), unit, su);
|
||||
}
|
||||
|
||||
private InnerLoader getInnerLoader() {
|
||||
return new InnerLoader(ExtendedGroovyClassLoader.this) {
|
||||
|
||||
// Don't return URLs from the inner loader so that Tomcat only
|
||||
// searches the parent. Fixes 'TLD skipped' issues
|
||||
@Override
|
||||
public URL[] getURLs() {
|
||||
return NO_URLS;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public CompilerConfiguration getConfiguration() {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner collector class used to track as classes are added.
|
||||
*/
|
||||
protected class ExtendedClassCollector extends ClassCollector {
|
||||
|
||||
protected ExtendedClassCollector(InnerLoader loader, CompilationUnit unit, SourceUnit su) {
|
||||
super(loader, unit, su);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> createClass(byte[] code, ClassNode classNode) {
|
||||
Class<?> createdClass = super.createClass(code, classNode);
|
||||
ExtendedGroovyClassLoader.this.classResources.put(classNode.getName().replace('.', '/') + ".class", code);
|
||||
return createdClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ClassLoader used for a parent that filters so that only classes from groovy-all.jar
|
||||
* are exposed.
|
||||
*/
|
||||
private static class DefaultScopeParentClassLoader extends ClassLoader {
|
||||
|
||||
private static final String[] GROOVY_JARS_PREFIXES = { "groovy", "antlr", "asm" };
|
||||
|
||||
private final URLClassLoader groovyOnlyClassLoader;
|
||||
|
||||
DefaultScopeParentClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
this.groovyOnlyClassLoader = new URLClassLoader(getGroovyJars(parent),
|
||||
getClass().getClassLoader().getParent());
|
||||
}
|
||||
|
||||
private URL[] getGroovyJars(ClassLoader parent) {
|
||||
Set<URL> urls = new HashSet<>();
|
||||
findGroovyJarsDirectly(parent, urls);
|
||||
if (urls.isEmpty()) {
|
||||
findGroovyJarsFromClassPath(urls);
|
||||
}
|
||||
Assert.state(!urls.isEmpty(), "Unable to find groovy JAR");
|
||||
return new ArrayList<>(urls).toArray(new URL[0]);
|
||||
}
|
||||
|
||||
private void findGroovyJarsDirectly(ClassLoader classLoader, Set<URL> urls) {
|
||||
while (classLoader != null) {
|
||||
if (classLoader instanceof URLClassLoader urlClassLoader) {
|
||||
for (URL url : urlClassLoader.getURLs()) {
|
||||
if (isGroovyJar(url.toString())) {
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
classLoader = classLoader.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
private void findGroovyJarsFromClassPath(Set<URL> urls) {
|
||||
String classpath = System.getProperty("java.class.path");
|
||||
String[] entries = classpath.split(System.getProperty("path.separator"));
|
||||
for (String entry : entries) {
|
||||
if (isGroovyJar(entry)) {
|
||||
File file = new File(entry);
|
||||
if (file.canRead()) {
|
||||
try {
|
||||
urls.add(file.toURI().toURL());
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
// Swallow and continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isGroovyJar(String entry) {
|
||||
entry = StringUtils.cleanPath(entry);
|
||||
for (String jarPrefix : GROOVY_JARS_PREFIXES) {
|
||||
if (entry.contains("/" + jarPrefix + "-")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
return this.groovyOnlyClassLoader.getResources(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if (!name.startsWith("java.")) {
|
||||
Class.forName(name, false, this.groovyOnlyClassLoader);
|
||||
}
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.groovy.ast.ASTNode;
|
||||
import org.codehaus.groovy.ast.AnnotatedNode;
|
||||
import org.codehaus.groovy.ast.AnnotationNode;
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
import org.codehaus.groovy.ast.PackageNode;
|
||||
import org.codehaus.groovy.ast.expr.ConstantExpression;
|
||||
import org.codehaus.groovy.ast.expr.Expression;
|
||||
import org.codehaus.groovy.ast.expr.ListExpression;
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.transform.GroovyASTTransformation;
|
||||
|
||||
import org.springframework.boot.groovy.DependencyManagementBom;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* A base class that lets plugin authors easily add additional BOMs to all apps. All the
|
||||
* dependencies in the BOM (and its transitives) will be added to the dependency
|
||||
* management lookup, so an app can use just the artifact id (e.g. "spring-jdbc") in a
|
||||
* {@code @Grab}. To install, implement the missing methods and list the class in
|
||||
* {@code META-INF/services/org.springframework.boot.cli.compiler.SpringBootAstTransformation}
|
||||
* . The {@link #getOrder()} value needs to be before
|
||||
* {@link DependencyManagementBomTransformation#ORDER}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@GroovyASTTransformation(phase = CompilePhase.CONVERSION)
|
||||
public abstract class GenericBomAstTransformation implements SpringBootAstTransformation, Ordered {
|
||||
|
||||
private static final ClassNode BOM = ClassHelper.make(DependencyManagementBom.class);
|
||||
|
||||
@Override
|
||||
public void visit(ASTNode[] nodes, SourceUnit source) {
|
||||
for (ASTNode astNode : nodes) {
|
||||
if (astNode instanceof ModuleNode moduleNode) {
|
||||
visitModule(moduleNode, getBomModule());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The bom to be added to dependency management in compact form:
|
||||
* {@code "<groupId>:<artifactId>:<version>"} (like in a {@code @Grab}).
|
||||
* @return the maven co-ordinates of the BOM to add
|
||||
*/
|
||||
protected abstract String getBomModule();
|
||||
|
||||
private void visitModule(ModuleNode node, String module) {
|
||||
addDependencyManagementBom(node, module);
|
||||
}
|
||||
|
||||
private void addDependencyManagementBom(ModuleNode node, String module) {
|
||||
AnnotatedNode annotated = getAnnotatedNode(node);
|
||||
if (annotated != null) {
|
||||
AnnotationNode bom = getAnnotation(annotated);
|
||||
List<Expression> expressions = new ArrayList<>(getConstantExpressions(bom.getMember("value")));
|
||||
expressions.add(new ConstantExpression(module));
|
||||
bom.setMember("value", new ListExpression(expressions));
|
||||
}
|
||||
}
|
||||
|
||||
private AnnotationNode getAnnotation(AnnotatedNode annotated) {
|
||||
List<AnnotationNode> annotations = annotated.getAnnotations(BOM);
|
||||
if (!annotations.isEmpty()) {
|
||||
return annotations.get(0);
|
||||
}
|
||||
AnnotationNode annotation = new AnnotationNode(BOM);
|
||||
annotated.addAnnotation(annotation);
|
||||
return annotation;
|
||||
}
|
||||
|
||||
private AnnotatedNode getAnnotatedNode(ModuleNode node) {
|
||||
PackageNode packageNode = node.getPackage();
|
||||
if (packageNode != null && !packageNode.getAnnotations(BOM).isEmpty()) {
|
||||
return packageNode;
|
||||
}
|
||||
if (!node.getClasses().isEmpty()) {
|
||||
return node.getClasses().get(0);
|
||||
}
|
||||
return packageNode;
|
||||
}
|
||||
|
||||
private List<ConstantExpression> getConstantExpressions(Expression valueExpression) {
|
||||
if (valueExpression instanceof ListExpression listExpression) {
|
||||
return getConstantExpressions(listExpression);
|
||||
}
|
||||
if (valueExpression instanceof ConstantExpression constantExpression
|
||||
&& constantExpression.getValue() instanceof String) {
|
||||
return Arrays.asList(constantExpression);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<ConstantExpression> getConstantExpressions(ListExpression valueExpression) {
|
||||
List<ConstantExpression> expressions = new ArrayList<>();
|
||||
for (Expression expression : valueExpression.getExpressions()) {
|
||||
if (expression instanceof ConstantExpression constantExpression
|
||||
&& constantExpression.getValue() instanceof String) {
|
||||
expressions.add(constantExpression);
|
||||
}
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.codehaus.groovy.ast.ASTNode;
|
||||
import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
import org.codehaus.groovy.ast.PropertyNode;
|
||||
import org.codehaus.groovy.ast.expr.ClosureExpression;
|
||||
import org.codehaus.groovy.ast.stmt.BlockStatement;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.transform.ASTTransformation;
|
||||
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* {@link ASTTransformation} to resolve beans declarations inside application source
|
||||
* files. Users only need to define a <code>beans{}</code> DSL element, and this
|
||||
* transformation will remove it and make it accessible to the Spring application via an
|
||||
* interface.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Order(GroovyBeansTransformation.ORDER)
|
||||
public class GroovyBeansTransformation implements ASTTransformation {
|
||||
|
||||
/**
|
||||
* The order of the transformation.
|
||||
*/
|
||||
public static final int ORDER = DependencyManagementBomTransformation.ORDER + 200;
|
||||
|
||||
@Override
|
||||
public void visit(ASTNode[] nodes, SourceUnit source) {
|
||||
for (ASTNode node : nodes) {
|
||||
if (node instanceof ModuleNode module) {
|
||||
for (ClassNode classNode : new ArrayList<>(module.getClasses())) {
|
||||
if (classNode.isScript()) {
|
||||
classNode.visitContents(new ClassVisitor(source, classNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassVisitor extends ClassCodeVisitorSupport {
|
||||
|
||||
private static final String SOURCE_INTERFACE = "org.springframework.boot.BeanDefinitionLoader.GroovyBeanDefinitionSource";
|
||||
|
||||
private static final String BEANS = "beans";
|
||||
|
||||
private final SourceUnit source;
|
||||
|
||||
private final ClassNode classNode;
|
||||
|
||||
private boolean xformed = false;
|
||||
|
||||
ClassVisitor(SourceUnit source, ClassNode classNode) {
|
||||
this.source = source;
|
||||
this.classNode = classNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SourceUnit getSourceUnit() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBlockStatement(BlockStatement block) {
|
||||
if (block.isEmpty() || this.xformed) {
|
||||
return;
|
||||
}
|
||||
ClosureExpression closure = beans(block);
|
||||
if (closure != null) {
|
||||
// Add a marker interface to the current script
|
||||
this.classNode.addInterface(ClassHelper.make(SOURCE_INTERFACE));
|
||||
// Implement the interface by adding a public read-only property with the
|
||||
// same name as the method in the interface (getBeans). Make it return the
|
||||
// closure.
|
||||
this.classNode.addProperty(new PropertyNode(BEANS, Modifier.PUBLIC | Modifier.FINAL,
|
||||
ClassHelper.CLOSURE_TYPE.getPlainNodeReference(), this.classNode, closure, null, null));
|
||||
// Only do this once per class
|
||||
this.xformed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a top-level <code>beans{}</code> closure from inside this block if
|
||||
* there is one. Removes it from the block at the same time.
|
||||
* @param block a block statement (class definition)
|
||||
* @return a beans Closure if one can be found, null otherwise
|
||||
*/
|
||||
private ClosureExpression beans(BlockStatement block) {
|
||||
return AstUtils.getClosure(block, BEANS, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,318 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import groovy.grape.GrapeEngine;
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import groovy.lang.GroovyClassLoader.ClassCollector;
|
||||
import groovy.lang.GroovyCodeSource;
|
||||
import org.codehaus.groovy.ast.ASTNode;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.classgen.GeneratorContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.CompilationUnit;
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.Phases;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.control.customizers.CompilationCustomizer;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
import org.codehaus.groovy.transform.ASTTransformation;
|
||||
import org.codehaus.groovy.transform.ASTTransformationVisitor;
|
||||
|
||||
import org.springframework.boot.cli.compiler.dependencies.SpringBootDependenciesDependencyManagement;
|
||||
import org.springframework.boot.cli.compiler.grape.DependencyResolutionContext;
|
||||
import org.springframework.boot.cli.compiler.grape.GrapeEngineInstaller;
|
||||
import org.springframework.boot.cli.compiler.grape.MavenResolverGrapeEngineFactory;
|
||||
import org.springframework.boot.cli.util.ResourceUtils;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Compiler for Groovy sources. Primarily a simple Facade for
|
||||
* {@link GroovyClassLoader#parseClass(GroovyCodeSource)} with the following additional
|
||||
* features:
|
||||
* <ul>
|
||||
* <li>{@link CompilerAutoConfiguration} strategies will be read from
|
||||
* {@code META-INF/services/org.springframework.boot.cli.compiler.CompilerAutoConfiguration}
|
||||
* (per the standard java {@link ServiceLoader} contract) and applied during compilation
|
||||
* </li>
|
||||
*
|
||||
* <li>Multiple classes can be returned if the Groovy source defines more than one Class
|
||||
* </li>
|
||||
*
|
||||
* <li>Generated class files can also be loaded using
|
||||
* {@link ClassLoader#getResource(String)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class GroovyCompiler {
|
||||
|
||||
private final GroovyCompilerConfiguration configuration;
|
||||
|
||||
private final ExtendedGroovyClassLoader loader;
|
||||
|
||||
private final Iterable<CompilerAutoConfiguration> compilerAutoConfigurations;
|
||||
|
||||
private final List<ASTTransformation> transformations;
|
||||
|
||||
/**
|
||||
* Create a new {@link GroovyCompiler} instance.
|
||||
* @param configuration the compiler configuration
|
||||
*/
|
||||
public GroovyCompiler(GroovyCompilerConfiguration configuration) {
|
||||
|
||||
this.configuration = configuration;
|
||||
this.loader = createLoader(configuration);
|
||||
|
||||
DependencyResolutionContext resolutionContext = new DependencyResolutionContext();
|
||||
resolutionContext.addDependencyManagement(new SpringBootDependenciesDependencyManagement());
|
||||
|
||||
GrapeEngine grapeEngine = MavenResolverGrapeEngineFactory.create(this.loader,
|
||||
configuration.getRepositoryConfiguration(), resolutionContext, configuration.isQuiet());
|
||||
|
||||
GrapeEngineInstaller.install(grapeEngine);
|
||||
|
||||
this.loader.getConfiguration().addCompilationCustomizers(new CompilerAutoConfigureCustomizer());
|
||||
if (configuration.isAutoconfigure()) {
|
||||
this.compilerAutoConfigurations = ServiceLoader.load(CompilerAutoConfiguration.class);
|
||||
}
|
||||
else {
|
||||
this.compilerAutoConfigurations = Collections.emptySet();
|
||||
}
|
||||
|
||||
this.transformations = new ArrayList<>();
|
||||
this.transformations.add(new DependencyManagementBomTransformation(resolutionContext));
|
||||
this.transformations.add(new DependencyAutoConfigurationTransformation(this.loader, resolutionContext,
|
||||
this.compilerAutoConfigurations));
|
||||
this.transformations.add(new GroovyBeansTransformation());
|
||||
if (this.configuration.isGuessDependencies()) {
|
||||
this.transformations.add(new ResolveDependencyCoordinatesTransformation(resolutionContext));
|
||||
}
|
||||
for (ASTTransformation transformation : ServiceLoader.load(SpringBootAstTransformation.class)) {
|
||||
this.transformations.add(transformation);
|
||||
}
|
||||
this.transformations.sort(AnnotationAwareOrderComparator.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a mutable list of the {@link ASTTransformation}s to be applied during
|
||||
* {@link #compile(String...)}.
|
||||
* @return the AST transformations to apply
|
||||
*/
|
||||
public List<ASTTransformation> getAstTransformations() {
|
||||
return this.transformations;
|
||||
}
|
||||
|
||||
public ExtendedGroovyClassLoader getLoader() {
|
||||
return this.loader;
|
||||
}
|
||||
|
||||
private ExtendedGroovyClassLoader createLoader(GroovyCompilerConfiguration configuration) {
|
||||
|
||||
ExtendedGroovyClassLoader loader = new ExtendedGroovyClassLoader(configuration.getScope());
|
||||
|
||||
for (URL url : getExistingUrls()) {
|
||||
loader.addURL(url);
|
||||
}
|
||||
|
||||
for (String classpath : configuration.getClasspath()) {
|
||||
loader.addClasspath(classpath);
|
||||
}
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
private URL[] getExistingUrls() {
|
||||
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||
if (tccl instanceof ExtendedGroovyClassLoader groovyClassLoader) {
|
||||
return groovyClassLoader.getURLs();
|
||||
}
|
||||
else {
|
||||
return new URL[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void addCompilationCustomizers(CompilationCustomizer... customizers) {
|
||||
this.loader.getConfiguration().addCompilationCustomizers(customizers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the specified Groovy sources, applying any
|
||||
* {@link CompilerAutoConfiguration}s. All classes defined in the sources will be
|
||||
* returned from this method.
|
||||
* @param sources the sources to compile
|
||||
* @return compiled classes
|
||||
* @throws CompilationFailedException in case of compilation failures
|
||||
* @throws IOException in case of I/O errors
|
||||
* @throws CompilationFailedException in case of compilation errors
|
||||
*/
|
||||
public Class<?>[] compile(String... sources) throws CompilationFailedException, IOException {
|
||||
|
||||
this.loader.clearCache();
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
|
||||
CompilerConfiguration configuration = this.loader.getConfiguration();
|
||||
|
||||
CompilationUnit compilationUnit = new CompilationUnit(configuration, null, this.loader);
|
||||
ClassCollector collector = this.loader.createCollector(compilationUnit, null);
|
||||
compilationUnit.setClassgenCallback(collector);
|
||||
|
||||
for (String source : sources) {
|
||||
List<String> paths = ResourceUtils.getUrls(source, this.loader);
|
||||
for (String path : paths) {
|
||||
compilationUnit.addSource(new URL(path));
|
||||
}
|
||||
}
|
||||
|
||||
addAstTransformations(compilationUnit);
|
||||
|
||||
compilationUnit.compile(Phases.CLASS_GENERATION);
|
||||
for (Object loadedClass : collector.getLoadedClasses()) {
|
||||
classes.add((Class<?>) loadedClass);
|
||||
}
|
||||
ClassNode mainClassNode = MainClass.get(compilationUnit);
|
||||
|
||||
Class<?> mainClass = null;
|
||||
for (Class<?> loadedClass : classes) {
|
||||
if (mainClassNode.getName().equals(loadedClass.getName())) {
|
||||
mainClass = loadedClass;
|
||||
}
|
||||
}
|
||||
if (mainClass != null) {
|
||||
classes.remove(mainClass);
|
||||
classes.add(0, mainClass);
|
||||
}
|
||||
|
||||
return ClassUtils.toClassArray(classes);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void addAstTransformations(CompilationUnit compilationUnit) {
|
||||
Deque[] phaseOperations = getPhaseOperations(compilationUnit);
|
||||
processConversionOperations((LinkedList) phaseOperations[Phases.CONVERSION]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Deque[] getPhaseOperations(CompilationUnit compilationUnit) {
|
||||
try {
|
||||
Field field = CompilationUnit.class.getDeclaredField("phaseOperations");
|
||||
field.setAccessible(true);
|
||||
return (Deque[]) field.get(compilationUnit);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Phase operations not available from compilation unit");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void processConversionOperations(LinkedList conversionOperations) {
|
||||
int index = getIndexOfASTTransformationVisitor(conversionOperations);
|
||||
conversionOperations.add(index, new CompilationUnit.ISourceUnitOperation() {
|
||||
@Override
|
||||
public void call(SourceUnit source) throws CompilationFailedException {
|
||||
ASTNode[] nodes = new ASTNode[] { source.getAST() };
|
||||
for (ASTTransformation transformation : GroovyCompiler.this.transformations) {
|
||||
transformation.visit(nodes, source);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int getIndexOfASTTransformationVisitor(List<?> conversionOperations) {
|
||||
for (int index = 0; index < conversionOperations.size(); index++) {
|
||||
if (conversionOperations.get(index).getClass().getName()
|
||||
.startsWith(ASTTransformationVisitor.class.getName())) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return conversionOperations.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link CompilationCustomizer} to call {@link CompilerAutoConfiguration}s.
|
||||
*/
|
||||
private class CompilerAutoConfigureCustomizer extends CompilationCustomizer {
|
||||
|
||||
CompilerAutoConfigureCustomizer() {
|
||||
super(CompilePhase.CONVERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
|
||||
throws CompilationFailedException {
|
||||
|
||||
ImportCustomizer importCustomizer = new SmartImportCustomizer(source);
|
||||
List<ClassNode> classNodes = source.getAST().getClasses();
|
||||
ClassNode mainClassNode = MainClass.get(classNodes);
|
||||
|
||||
// Additional auto configuration
|
||||
for (CompilerAutoConfiguration autoConfiguration : GroovyCompiler.this.compilerAutoConfigurations) {
|
||||
if (classNodes.stream().anyMatch(autoConfiguration::matches)) {
|
||||
if (GroovyCompiler.this.configuration.isGuessImports()) {
|
||||
autoConfiguration.applyImports(importCustomizer);
|
||||
importCustomizer.call(source, context, classNode);
|
||||
}
|
||||
if (classNode.equals(mainClassNode)) {
|
||||
autoConfiguration.applyToMainClass(GroovyCompiler.this.loader,
|
||||
GroovyCompiler.this.configuration, context, source, classNode);
|
||||
}
|
||||
autoConfiguration.apply(GroovyCompiler.this.loader, GroovyCompiler.this.configuration, context,
|
||||
source, classNode);
|
||||
}
|
||||
}
|
||||
importCustomizer.call(source, context, classNode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MainClass {
|
||||
|
||||
static ClassNode get(CompilationUnit source) {
|
||||
return get(source.getAST().getClasses());
|
||||
}
|
||||
|
||||
static ClassNode get(List<ClassNode> classes) {
|
||||
for (ClassNode node : classes) {
|
||||
if (AstUtils.hasAtLeastOneAnnotation(node, "Enable*AutoConfiguration")) {
|
||||
return null; // No need to enhance this
|
||||
}
|
||||
if (AstUtils.hasAtLeastOneAnnotation(node, "*Controller", "Configuration", "Component", "*Service",
|
||||
"Repository", "Enable*")) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return classes.isEmpty() ? null : classes.get(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
||||
|
||||
/**
|
||||
* Configuration for the {@link GroovyCompiler}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface GroovyCompilerConfiguration {
|
||||
|
||||
/**
|
||||
* Constant to be used when there is no {@link #getClasspath() classpath}.
|
||||
*/
|
||||
String[] DEFAULT_CLASSPATH = { "." };
|
||||
|
||||
/**
|
||||
* Returns the scope in which the compiler operates.
|
||||
* @return the scope of the compiler
|
||||
*/
|
||||
GroovyCompilerScope getScope();
|
||||
|
||||
/**
|
||||
* Returns if import declarations should be guessed.
|
||||
* @return {@code true} if imports should be guessed, otherwise {@code false}
|
||||
*/
|
||||
boolean isGuessImports();
|
||||
|
||||
/**
|
||||
* Returns if jar dependencies should be guessed.
|
||||
* @return {@code true} if dependencies should be guessed, otherwise {@code false}
|
||||
*/
|
||||
boolean isGuessDependencies();
|
||||
|
||||
/**
|
||||
* Returns true if auto-configuration transformations should be applied.
|
||||
* @return {@code true} if auto-configuration transformations should be applied,
|
||||
* otherwise {@code false}
|
||||
*/
|
||||
boolean isAutoconfigure();
|
||||
|
||||
/**
|
||||
* Returns the classpath for local resources.
|
||||
* @return a path for local resources
|
||||
*/
|
||||
String[] getClasspath();
|
||||
|
||||
/**
|
||||
* Returns the configuration for the repositories that will be used by the compiler to
|
||||
* resolve dependencies.
|
||||
* @return the repository configurations
|
||||
*/
|
||||
List<RepositoryConfiguration> getRepositoryConfiguration();
|
||||
|
||||
/**
|
||||
* Returns if running in quiet mode.
|
||||
* @return {@code true} if running in quiet mode
|
||||
*/
|
||||
boolean isQuiet();
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
/**
|
||||
* The scope in which a groovy compiler operates.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public enum GroovyCompilerScope {
|
||||
|
||||
/**
|
||||
* Default scope, exposes groovy.jar (loaded from the parent) and the shared cli
|
||||
* package (loaded via groovy classloader).
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* Extension scope, allows full access to internal CLI classes.
|
||||
*/
|
||||
EXTENSION
|
||||
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.maven.settings.Profile;
|
||||
import org.apache.maven.settings.Repository;
|
||||
import org.codehaus.plexus.interpolation.InterpolationException;
|
||||
import org.codehaus.plexus.interpolation.Interpolator;
|
||||
import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
|
||||
import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
|
||||
|
||||
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
||||
import org.springframework.boot.cli.compiler.maven.MavenSettings;
|
||||
import org.springframework.boot.cli.compiler.maven.MavenSettingsReader;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Factory used to create {@link RepositoryConfiguration}s.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class RepositoryConfigurationFactory {
|
||||
|
||||
private static final RepositoryConfiguration MAVEN_CENTRAL = new RepositoryConfiguration("central",
|
||||
URI.create("https://repo.maven.apache.org/maven2/"), false);
|
||||
|
||||
private static final RepositoryConfiguration SPRING_MILESTONE = new RepositoryConfiguration("spring-milestone",
|
||||
URI.create("https://repo.spring.io/milestone"), false);
|
||||
|
||||
private static final RepositoryConfiguration SPRING_SNAPSHOT = new RepositoryConfiguration("spring-snapshot",
|
||||
URI.create("https://repo.spring.io/snapshot"), true);
|
||||
|
||||
private RepositoryConfigurationFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new default repository configuration.
|
||||
* @return the newly-created default repository configuration
|
||||
*/
|
||||
public static List<RepositoryConfiguration> createDefaultRepositoryConfiguration() {
|
||||
MavenSettings mavenSettings = new MavenSettingsReader().readSettings();
|
||||
List<RepositoryConfiguration> repositoryConfiguration = new ArrayList<>();
|
||||
repositoryConfiguration.add(MAVEN_CENTRAL);
|
||||
if (!Boolean.getBoolean("disableSpringSnapshotRepos")) {
|
||||
repositoryConfiguration.add(SPRING_MILESTONE);
|
||||
repositoryConfiguration.add(SPRING_SNAPSHOT);
|
||||
}
|
||||
addDefaultCacheAsRepository(mavenSettings.getLocalRepository(), repositoryConfiguration);
|
||||
addActiveProfileRepositories(mavenSettings.getActiveProfiles(), repositoryConfiguration);
|
||||
return repositoryConfiguration;
|
||||
}
|
||||
|
||||
private static void addDefaultCacheAsRepository(String localRepository,
|
||||
List<RepositoryConfiguration> repositoryConfiguration) {
|
||||
RepositoryConfiguration repository = new RepositoryConfiguration("local",
|
||||
getLocalRepositoryDirectory(localRepository).toURI(), true);
|
||||
if (!repositoryConfiguration.contains(repository)) {
|
||||
repositoryConfiguration.add(0, repository);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addActiveProfileRepositories(List<Profile> activeProfiles,
|
||||
List<RepositoryConfiguration> configurations) {
|
||||
for (Profile activeProfile : activeProfiles) {
|
||||
Interpolator interpolator = new RegexBasedInterpolator();
|
||||
interpolator.addValueSource(new PropertiesBasedValueSource(activeProfile.getProperties()));
|
||||
for (Repository repository : activeProfile.getRepositories()) {
|
||||
configurations.add(getRepositoryConfiguration(interpolator, repository));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static RepositoryConfiguration getRepositoryConfiguration(Interpolator interpolator,
|
||||
Repository repository) {
|
||||
String name = interpolate(interpolator, repository.getId());
|
||||
String url = interpolate(interpolator, repository.getUrl());
|
||||
boolean snapshotsEnabled = false;
|
||||
if (repository.getSnapshots() != null) {
|
||||
snapshotsEnabled = repository.getSnapshots().isEnabled();
|
||||
}
|
||||
return new RepositoryConfiguration(name, URI.create(url), snapshotsEnabled);
|
||||
}
|
||||
|
||||
private static String interpolate(Interpolator interpolator, String value) {
|
||||
try {
|
||||
return interpolator.interpolate(value);
|
||||
}
|
||||
catch (InterpolationException ex) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private static File getLocalRepositoryDirectory(String localRepository) {
|
||||
if (StringUtils.hasText(localRepository)) {
|
||||
return new File(localRepository);
|
||||
}
|
||||
return new File(getM2HomeDirectory(), "repository");
|
||||
}
|
||||
|
||||
private static File getM2HomeDirectory() {
|
||||
String mavenRoot = System.getProperty("maven.home");
|
||||
if (StringUtils.hasLength(mavenRoot)) {
|
||||
return new File(mavenRoot);
|
||||
}
|
||||
return new File(System.getProperty("user.home"), ".m2");
|
||||
}
|
||||
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import groovy.lang.Grab;
|
||||
import org.codehaus.groovy.ast.AnnotationNode;
|
||||
import org.codehaus.groovy.ast.expr.ConstantExpression;
|
||||
import org.codehaus.groovy.ast.expr.Expression;
|
||||
import org.codehaus.groovy.transform.ASTTransformation;
|
||||
|
||||
import org.springframework.boot.cli.compiler.grape.DependencyResolutionContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* {@link ASTTransformation} to resolve {@link Grab @Grab} artifact coordinates.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Order(ResolveDependencyCoordinatesTransformation.ORDER)
|
||||
public class ResolveDependencyCoordinatesTransformation extends AnnotatedNodeASTTransformation {
|
||||
|
||||
/**
|
||||
* The order of the transformation.
|
||||
*/
|
||||
public static final int ORDER = DependencyManagementBomTransformation.ORDER + 300;
|
||||
|
||||
private static final Set<String> GRAB_ANNOTATION_NAMES = Collections
|
||||
.unmodifiableSet(new HashSet<>(Arrays.asList(Grab.class.getName(), Grab.class.getSimpleName())));
|
||||
|
||||
private final DependencyResolutionContext resolutionContext;
|
||||
|
||||
public ResolveDependencyCoordinatesTransformation(DependencyResolutionContext resolutionContext) {
|
||||
super(GRAB_ANNOTATION_NAMES, false);
|
||||
this.resolutionContext = resolutionContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processAnnotationNodes(List<AnnotationNode> annotationNodes) {
|
||||
for (AnnotationNode annotationNode : annotationNodes) {
|
||||
transformGrabAnnotation(annotationNode);
|
||||
}
|
||||
}
|
||||
|
||||
private void transformGrabAnnotation(AnnotationNode grabAnnotation) {
|
||||
grabAnnotation.setMember("initClass", new ConstantExpression(false));
|
||||
String value = getValue(grabAnnotation);
|
||||
if (value != null && !isConvenienceForm(value)) {
|
||||
applyGroupAndVersion(grabAnnotation, value);
|
||||
}
|
||||
}
|
||||
|
||||
private String getValue(AnnotationNode annotation) {
|
||||
Expression expression = annotation.getMember("value");
|
||||
if (expression instanceof ConstantExpression constantExpression) {
|
||||
Object value = constantExpression.getValue();
|
||||
return (value instanceof String string) ? string : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isConvenienceForm(String value) {
|
||||
return value.contains(":") || value.contains("#");
|
||||
}
|
||||
|
||||
private void applyGroupAndVersion(AnnotationNode annotation, String module) {
|
||||
if (module != null) {
|
||||
setMember(annotation, "module", module);
|
||||
}
|
||||
else {
|
||||
Expression expression = annotation.getMembers().get("module");
|
||||
module = (String) ((ConstantExpression) expression).getValue();
|
||||
}
|
||||
if (annotation.getMember("group") == null) {
|
||||
setMember(annotation, "group", this.resolutionContext.getArtifactCoordinatesResolver().getGroupId(module));
|
||||
}
|
||||
if (annotation.getMember("version") == null) {
|
||||
setMember(annotation, "version",
|
||||
this.resolutionContext.getArtifactCoordinatesResolver().getVersion(module));
|
||||
}
|
||||
}
|
||||
|
||||
private void setMember(AnnotationNode annotation, String name, String value) {
|
||||
ConstantExpression expression = new ConstantExpression(value);
|
||||
annotation.setMember(name, expression);
|
||||
}
|
||||
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
|
||||
/**
|
||||
* Smart extension of {@link ImportCustomizer} that will only add a specific import if a
|
||||
* class with the same name is not already explicitly imported.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
class SmartImportCustomizer extends ImportCustomizer {
|
||||
|
||||
private SourceUnit source;
|
||||
|
||||
SmartImportCustomizer(SourceUnit source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportCustomizer addImport(String alias, String className) {
|
||||
if (this.source.getAST().getImport(ClassHelper.make(className).getNameWithoutPackage()) == null) {
|
||||
super.addImport(alias, className);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportCustomizer addImports(String... imports) {
|
||||
for (String alias : imports) {
|
||||
if (this.source.getAST().getImport(ClassHelper.make(alias).getNameWithoutPackage()) == null) {
|
||||
super.addImports(alias);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
import org.codehaus.groovy.transform.ASTTransformation;
|
||||
|
||||
/**
|
||||
* Marker interface for AST transformations that should be installed automatically from
|
||||
* {@code META-INF/services}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SpringBootAstTransformation extends ASTTransformation {
|
||||
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.CompilationFailedException;
|
||||
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 the caching infrastructure.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class CachingCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableCaching");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) throws CompilationFailedException {
|
||||
dependencies.add("spring-context-support");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
|
||||
imports.addStarImports("org.springframework.cache", "org.springframework.cache.annotation",
|
||||
"org.springframework.cache.concurrent");
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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;
|
||||
import org.springframework.boot.groovy.EnableGroovyTemplates;
|
||||
import org.springframework.boot.groovy.GroovyTemplate;
|
||||
|
||||
/**
|
||||
* {@link CompilerAutoConfiguration} for Groovy Templates (outside MVC).
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class GroovyTemplatesCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableGroovyTemplates");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("groovy.text.TemplateEngine").add("groovy-templates");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) {
|
||||
imports.addStarImports("groovy.text");
|
||||
imports.addImports(EnableGroovyTemplates.class.getCanonicalName());
|
||||
imports.addStaticImport(GroovyTemplate.class.getName(), "template");
|
||||
}
|
||||
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class JdbcCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneFieldOrMethod(classNode, "JdbcTemplate", "NamedParameterJdbcTemplate",
|
||||
"DataSource");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("org.springframework.jdbc.core.JdbcTemplate").add("spring-boot-starter-jdbc");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) {
|
||||
imports.addStarImports("org.springframework.jdbc.core", "org.springframework.jdbc.core.namedparam");
|
||||
imports.addImports("javax.sql.DataSource");
|
||||
}
|
||||
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.CompilationFailedException;
|
||||
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 JMS.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class JmsCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableJms")
|
||||
|| AstUtils.hasAtLeastOneAnnotation(classNode, "EnableJmsMessaging");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) throws CompilationFailedException {
|
||||
dependencies.add("spring-jms", "jakarta.jms-api");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
|
||||
imports.addStarImports("jakarta.jms", "org.springframework.jms.annotation", "org.springframework.jms.config",
|
||||
"org.springframework.jms.core", "org.springframework.jms.listener",
|
||||
"org.springframework.jms.listener.adapter");
|
||||
}
|
||||
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.CompilationFailedException;
|
||||
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 Rabbit.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class RabbitCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableRabbit")
|
||||
|| AstUtils.hasAtLeastOneAnnotation(classNode, "EnableRabbitMessaging");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) throws CompilationFailedException {
|
||||
dependencies.add("spring-rabbit");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
|
||||
imports.addStarImports("org.springframework.amqp.rabbit.annotation", "org.springframework.amqp.rabbit.core",
|
||||
"org.springframework.amqp.rabbit.config", "org.springframework.amqp.rabbit.connection",
|
||||
"org.springframework.amqp.rabbit.listener", "org.springframework.amqp.rabbit.listener.adapter",
|
||||
"org.springframework.amqp.core");
|
||||
}
|
||||
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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 Batch.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SpringBatchCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableBatchProcessing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("org.springframework.batch.core.Job").add("spring-boot-starter-batch");
|
||||
dependencies.ifAnyMissingClasses("org.springframework.jdbc.core.JdbcTemplate").add("spring-jdbc");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) {
|
||||
imports.addImports("org.springframework.batch.repeat.RepeatStatus",
|
||||
"org.springframework.batch.core.scope.context.ChunkContext",
|
||||
"org.springframework.batch.core.step.tasklet.Tasklet",
|
||||
"org.springframework.batch.core.configuration.annotation.StepScope",
|
||||
"org.springframework.batch.core.configuration.annotation.JobBuilderFactory",
|
||||
"org.springframework.batch.core.configuration.annotation.StepBuilderFactory",
|
||||
"org.springframework.batch.core.configuration.annotation.EnableBatchProcessing",
|
||||
"org.springframework.batch.core.Step", "org.springframework.batch.core.StepExecution",
|
||||
"org.springframework.batch.core.StepContribution", "org.springframework.batch.core.Job",
|
||||
"org.springframework.batch.core.JobExecution", "org.springframework.batch.core.JobParameter",
|
||||
"org.springframework.batch.core.JobParameters", "org.springframework.batch.core.launch.JobLauncher",
|
||||
"org.springframework.batch.core.converter.JobParametersConverter",
|
||||
"org.springframework.batch.core.converter.DefaultJobParametersConverter");
|
||||
}
|
||||
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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 groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.ast.AnnotationNode;
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.classgen.GeneratorContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
|
||||
import org.springframework.boot.cli.compiler.CompilerAutoConfiguration;
|
||||
import org.springframework.boot.cli.compiler.DependencyCustomizer;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
||||
|
||||
/**
|
||||
* {@link CompilerAutoConfiguration} for Spring.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SpringBootCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("org.springframework.boot.SpringApplication").add("spring-boot-starter");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) {
|
||||
imports.addImports("jakarta.annotation.PostConstruct", "jakarta.annotation.PreDestroy",
|
||||
"groovy.util.logging.Log", "org.springframework.stereotype.Controller",
|
||||
"org.springframework.stereotype.Service", "org.springframework.stereotype.Component",
|
||||
"org.springframework.beans.factory.annotation.Autowired",
|
||||
"org.springframework.beans.factory.annotation.Value", "org.springframework.context.annotation.Import",
|
||||
"org.springframework.context.annotation.ImportResource",
|
||||
"org.springframework.context.annotation.Profile", "org.springframework.context.annotation.Scope",
|
||||
"org.springframework.context.annotation.Configuration",
|
||||
"org.springframework.context.annotation.ComponentScan", "org.springframework.context.annotation.Bean",
|
||||
"org.springframework.context.ApplicationContext", "org.springframework.context.MessageSource",
|
||||
"org.springframework.core.annotation.Order", "org.springframework.core.io.ResourceLoader",
|
||||
"org.springframework.boot.ApplicationRunner", "org.springframework.boot.ApplicationArguments",
|
||||
"org.springframework.boot.CommandLineRunner",
|
||||
"org.springframework.boot.context.properties.ConfigurationProperties",
|
||||
"org.springframework.boot.context.properties.EnableConfigurationProperties",
|
||||
"org.springframework.boot.autoconfigure.EnableAutoConfiguration",
|
||||
"org.springframework.boot.autoconfigure.SpringBootApplication",
|
||||
"org.springframework.boot.context.properties.ConfigurationProperties",
|
||||
"org.springframework.boot.context.properties.EnableConfigurationProperties");
|
||||
imports.addStarImports("org.springframework.stereotype", "org.springframework.scheduling.annotation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyToMainClass(GroovyClassLoader loader, GroovyCompilerConfiguration configuration,
|
||||
GeneratorContext generatorContext, SourceUnit source, ClassNode classNode)
|
||||
throws CompilationFailedException {
|
||||
addEnableAutoConfigurationAnnotation(classNode);
|
||||
}
|
||||
|
||||
private void addEnableAutoConfigurationAnnotation(ClassNode classNode) {
|
||||
if (!hasEnableAutoConfigureAnnotation(classNode)) {
|
||||
AnnotationNode annotationNode = new AnnotationNode(ClassHelper.make("EnableAutoConfiguration"));
|
||||
classNode.addAnnotation(annotationNode);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasEnableAutoConfigureAnnotation(ClassNode classNode) {
|
||||
for (AnnotationNode node : classNode.getAnnotations()) {
|
||||
String name = node.getClassNode().getNameWithoutPackage();
|
||||
if ("EnableAutoConfiguration".equals(name) || "SpringBootApplication".equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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 Integration.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Artem Bilan
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SpringIntegrationCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableIntegration")
|
||||
|| AstUtils.hasAtLeastOneAnnotation(classNode, "MessageEndpoint");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("org.springframework.integration.config.EnableIntegration")
|
||||
.add("spring-boot-starter-integration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) {
|
||||
imports.addImports("org.springframework.messaging.Message", "org.springframework.messaging.MessageChannel",
|
||||
"org.springframework.messaging.PollableChannel", "org.springframework.messaging.SubscribableChannel",
|
||||
"org.springframework.messaging.MessageHeaders",
|
||||
"org.springframework.integration.support.MessageBuilder",
|
||||
"org.springframework.integration.channel.DirectChannel",
|
||||
"org.springframework.integration.channel.QueueChannel",
|
||||
"org.springframework.integration.channel.ExecutorChannel",
|
||||
"org.springframework.integration.core.MessagingTemplate",
|
||||
"org.springframework.integration.config.EnableIntegration");
|
||||
imports.addStarImports("org.springframework.integration.annotation");
|
||||
}
|
||||
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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;
|
||||
import org.springframework.boot.groovy.GroovyTemplate;
|
||||
|
||||
/**
|
||||
* {@link CompilerAutoConfiguration} for Spring MVC.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SpringMvcCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "Controller", "RestController", "EnableWebMvc");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("org.springframework.web.servlet.mvc.Controller")
|
||||
.add("spring-boot-starter-web");
|
||||
dependencies.ifAnyMissingClasses("groovy.text.TemplateEngine").add("groovy-templates");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) {
|
||||
imports.addStarImports("org.springframework.web.bind.annotation",
|
||||
"org.springframework.web.servlet.config.annotation", "org.springframework.web.servlet",
|
||||
"org.springframework.http", "org.springframework.web.servlet.handler", "org.springframework.http",
|
||||
"org.springframework.ui", "groovy.text");
|
||||
imports.addStaticImport(GroovyTemplate.class.getName(), "template");
|
||||
}
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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 Retry.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class SpringRetryCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableRetry", "Retryable", "Recover");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("org.springframework.retry.annotation.EnableRetry").add("spring-retry",
|
||||
"spring-boot-starter-aop");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) {
|
||||
imports.addStarImports("org.springframework.retry.annotation");
|
||||
}
|
||||
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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 Security.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SpringSecurityCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableWebSecurity", "EnableGlobalMethodSecurity");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses(
|
||||
"org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity")
|
||||
.add("spring-boot-starter-security");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) {
|
||||
imports.addImports("org.springframework.security.core.Authentication",
|
||||
"org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity",
|
||||
"org.springframework.security.core.authority.AuthorityUtils")
|
||||
.addStarImports("org.springframework.security.config.annotation.web.configuration",
|
||||
"org.springframework.security.authentication",
|
||||
"org.springframework.security.config.annotation.web",
|
||||
"org.springframework.security.config.annotation.web.builders");
|
||||
}
|
||||
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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 groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.ast.AnnotationNode;
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.expr.ClassExpression;
|
||||
import org.codehaus.groovy.classgen.GeneratorContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
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;
|
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
||||
|
||||
/**
|
||||
* {@link CompilerAutoConfiguration} for Spring Test.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class SpringTestCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "SpringBootTest");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("org.springframework.http.HttpHeaders").add("spring-boot-starter-web");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(GroovyClassLoader loader, GroovyCompilerConfiguration configuration,
|
||||
GeneratorContext generatorContext, SourceUnit source, ClassNode classNode)
|
||||
throws CompilationFailedException {
|
||||
if (!AstUtils.hasAtLeastOneAnnotation(classNode, "RunWith")) {
|
||||
AnnotationNode runWith = new AnnotationNode(ClassHelper.make("RunWith"));
|
||||
runWith.addMember("value", new ClassExpression(ClassHelper.make("SpringRunner")));
|
||||
classNode.addAnnotation(runWith);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
|
||||
imports.addStarImports("org.junit.runner", "org.springframework.boot.test",
|
||||
"org.springframework.boot.test.context", "org.springframework.boot.test.web.client",
|
||||
"org.springframework.http", "org.springframework.test.context.junit4",
|
||||
"org.springframework.test.annotation")
|
||||
.addImports("org.springframework.boot.test.context.SpringBootTest.WebEnvironment",
|
||||
"org.springframework.boot.test.web.client.TestRestTemplate");
|
||||
}
|
||||
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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 Websocket.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SpringWebsocketCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableWebSocket", "EnableWebSocketMessageBroker");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("org.springframework.web.socket.config.annotation.EnableWebSocket")
|
||||
.add("spring-boot-starter-websocket").add("spring-messaging");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) {
|
||||
imports.addStarImports("org.springframework.messaging.handler.annotation",
|
||||
"org.springframework.messaging.simp.config", "org.springframework.web.socket.handler",
|
||||
"org.springframework.web.socket.sockjs.transport.handler",
|
||||
"org.springframework.web.socket.config.annotation")
|
||||
.addImports("org.springframework.web.socket.WebSocketHandler");
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class TransactionManagementCompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableTransactionManagement");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) {
|
||||
dependencies.ifAnyMissingClasses("org.springframework.transaction.annotation.Transactional").add("spring-tx",
|
||||
"spring-boot-starter-aop");
|
||||
}
|
||||
|
||||
@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");
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes for auto-configuring the Groovy compiler.
|
||||
*/
|
||||
package org.springframework.boot.cli.compiler.autoconfigure;
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.dependencies;
|
||||
|
||||
/**
|
||||
* A resolver for artifacts' Maven coordinates, allowing group id, artifact id, or version
|
||||
* to be obtained from a module identifier. A module identifier may be in the form
|
||||
* {@code groupId:artifactId:version}, in which case coordinate resolution simply extracts
|
||||
* the relevant piece from the identifier. Alternatively the identifier may be in the form
|
||||
* {@code artifactId}, in which case coordinate resolution uses implementation-specific
|
||||
* metadata to resolve the groupId and version.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface ArtifactCoordinatesResolver {
|
||||
|
||||
/**
|
||||
* Gets the group id of the artifact identified by the given {@code module}. Returns
|
||||
* {@code null} if the artifact is unknown to the resolver.
|
||||
* @param module the id of the module
|
||||
* @return the group id of the module
|
||||
*/
|
||||
String getGroupId(String module);
|
||||
|
||||
/**
|
||||
* Gets the artifact id of the artifact identified by the given {@code module}.
|
||||
* Returns {@code null} if the artifact is unknown to the resolver.
|
||||
* @param module the id of the module
|
||||
* @return the artifact id of the module
|
||||
*/
|
||||
String getArtifactId(String module);
|
||||
|
||||
/**
|
||||
* Gets the version of the artifact identified by the given {@code module}. Returns
|
||||
* {@code null} if the artifact is unknown to the resolver.
|
||||
* @param module the id of the module
|
||||
* @return the version of the module
|
||||
*/
|
||||
String getVersion(String module);
|
||||
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.dependencies;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link DependencyManagement} that delegates to one or more {@link DependencyManagement}
|
||||
* instances.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class CompositeDependencyManagement implements DependencyManagement {
|
||||
|
||||
private final List<DependencyManagement> delegates;
|
||||
|
||||
private final List<Dependency> dependencies = new ArrayList<>();
|
||||
|
||||
public CompositeDependencyManagement(DependencyManagement... delegates) {
|
||||
this.delegates = Arrays.asList(delegates);
|
||||
for (DependencyManagement delegate : delegates) {
|
||||
this.dependencies.addAll(delegate.getDependencies());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Dependency> getDependencies() {
|
||||
return this.dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSpringBootVersion() {
|
||||
for (DependencyManagement delegate : this.delegates) {
|
||||
String version = delegate.getSpringBootVersion();
|
||||
if (version != null) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dependency find(String artifactId) {
|
||||
for (DependencyManagement delegate : this.delegates) {
|
||||
Dependency found = delegate.find(artifactId);
|
||||
if (found != null) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.dependencies;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A single dependency.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public final class Dependency {
|
||||
|
||||
private final String groupId;
|
||||
|
||||
private final String artifactId;
|
||||
|
||||
private final String version;
|
||||
|
||||
private final List<Exclusion> exclusions;
|
||||
|
||||
/**
|
||||
* Create a new {@link Dependency} instance.
|
||||
* @param groupId the group ID
|
||||
* @param artifactId the artifact ID
|
||||
* @param version the version
|
||||
*/
|
||||
public Dependency(String groupId, String artifactId, String version) {
|
||||
this(groupId, artifactId, version, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Dependency} instance.
|
||||
* @param groupId the group ID
|
||||
* @param artifactId the artifact ID
|
||||
* @param version the version
|
||||
* @param exclusions the exclusions
|
||||
*/
|
||||
public Dependency(String groupId, String artifactId, String version, List<Exclusion> exclusions) {
|
||||
Assert.notNull(groupId, "GroupId must not be null");
|
||||
Assert.notNull(artifactId, "ArtifactId must not be null");
|
||||
Assert.notNull(version, "Version must not be null");
|
||||
Assert.notNull(exclusions, "Exclusions must not be null");
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
this.version = version;
|
||||
this.exclusions = Collections.unmodifiableList(exclusions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the dependency group id.
|
||||
* @return the group ID
|
||||
*/
|
||||
public String getGroupId() {
|
||||
return this.groupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the dependency artifact id.
|
||||
* @return the artifact ID
|
||||
*/
|
||||
public String getArtifactId() {
|
||||
return this.artifactId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the dependency version.
|
||||
* @return the version
|
||||
*/
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the dependency exclusions.
|
||||
* @return the exclusions
|
||||
*/
|
||||
public List<Exclusion> getExclusions() {
|
||||
return this.exclusions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() == obj.getClass()) {
|
||||
Dependency other = (Dependency) obj;
|
||||
boolean result = true;
|
||||
result = result && this.groupId.equals(other.groupId);
|
||||
result = result && this.artifactId.equals(other.artifactId);
|
||||
result = result && this.version.equals(other.version);
|
||||
result = result && this.exclusions.equals(other.exclusions);
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + this.groupId.hashCode();
|
||||
result = prime * result + this.artifactId.hashCode();
|
||||
result = prime * result + this.version.hashCode();
|
||||
result = prime * result + this.exclusions.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.groupId + ":" + this.artifactId + ":" + this.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* A dependency exclusion.
|
||||
*/
|
||||
public static final class Exclusion {
|
||||
|
||||
private final String groupId;
|
||||
|
||||
private final String artifactId;
|
||||
|
||||
Exclusion(String groupId, String artifactId) {
|
||||
Assert.notNull(groupId, "GroupId must not be null");
|
||||
Assert.notNull(artifactId, "ArtifactId must not be null");
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the exclusion artifact ID.
|
||||
* @return the exclusion artifact ID
|
||||
*/
|
||||
public String getArtifactId() {
|
||||
return this.artifactId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the exclusion group ID.
|
||||
* @return the exclusion group ID
|
||||
*/
|
||||
public String getGroupId() {
|
||||
return this.groupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() == obj.getClass()) {
|
||||
Exclusion other = (Exclusion) obj;
|
||||
boolean result = true;
|
||||
result = result && this.groupId.equals(other.groupId);
|
||||
result = result && this.artifactId.equals(other.artifactId);
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.groupId.hashCode() * 31 + this.artifactId.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.groupId + ":" + this.artifactId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.dependencies;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An encapsulation of dependency management information.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public interface DependencyManagement {
|
||||
|
||||
/**
|
||||
* Returns the managed dependencies.
|
||||
* @return the managed dependencies
|
||||
*/
|
||||
List<Dependency> getDependencies();
|
||||
|
||||
/**
|
||||
* Returns the managed version of Spring Boot. May be {@code null}.
|
||||
* @return the Spring Boot version, or {@code null}
|
||||
*/
|
||||
String getSpringBootVersion();
|
||||
|
||||
/**
|
||||
* Finds the managed dependency with the given {@code artifactId}.
|
||||
* @param artifactId the artifact ID of the dependency to find
|
||||
* @return the dependency, or {@code null}
|
||||
*/
|
||||
Dependency find(String artifactId);
|
||||
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.dependencies;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ArtifactCoordinatesResolver} backed by
|
||||
* {@link SpringBootDependenciesDependencyManagement}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class DependencyManagementArtifactCoordinatesResolver implements ArtifactCoordinatesResolver {
|
||||
|
||||
private final DependencyManagement dependencyManagement;
|
||||
|
||||
public DependencyManagementArtifactCoordinatesResolver() {
|
||||
this(new SpringBootDependenciesDependencyManagement());
|
||||
}
|
||||
|
||||
public DependencyManagementArtifactCoordinatesResolver(DependencyManagement dependencyManagement) {
|
||||
this.dependencyManagement = dependencyManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupId(String artifactId) {
|
||||
Dependency dependency = find(artifactId);
|
||||
return (dependency != null) ? dependency.getGroupId() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArtifactId(String id) {
|
||||
Dependency dependency = find(id);
|
||||
return (dependency != null) ? dependency.getArtifactId() : null;
|
||||
}
|
||||
|
||||
private Dependency find(String id) {
|
||||
if (StringUtils.countOccurrencesOf(id, ":") == 2) {
|
||||
String[] tokens = id.split(":");
|
||||
return new Dependency(tokens[0], tokens[1], tokens[2]);
|
||||
}
|
||||
if (id != null) {
|
||||
if (id.startsWith("spring-boot")) {
|
||||
return new Dependency("org.springframework.boot", id, this.dependencyManagement.getSpringBootVersion());
|
||||
}
|
||||
return this.dependencyManagement.find(id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion(String module) {
|
||||
Dependency dependency = find(module);
|
||||
return (dependency != null) ? dependency.getVersion() : null;
|
||||
}
|
||||
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.dependencies;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.model.Model;
|
||||
|
||||
import org.springframework.boot.cli.compiler.dependencies.Dependency.Exclusion;
|
||||
|
||||
/**
|
||||
* {@link DependencyManagement} derived from a Maven {@link Model}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class MavenModelDependencyManagement implements DependencyManagement {
|
||||
|
||||
private final List<Dependency> dependencies;
|
||||
|
||||
private final Map<String, Dependency> byArtifactId = new LinkedHashMap<>();
|
||||
|
||||
public MavenModelDependencyManagement(Model model) {
|
||||
this.dependencies = extractDependenciesFromModel(model);
|
||||
for (Dependency dependency : this.dependencies) {
|
||||
this.byArtifactId.put(dependency.getArtifactId(), dependency);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Dependency> extractDependenciesFromModel(Model model) {
|
||||
List<Dependency> dependencies = new ArrayList<>();
|
||||
for (org.apache.maven.model.Dependency mavenDependency : model.getDependencyManagement().getDependencies()) {
|
||||
List<Exclusion> exclusions = new ArrayList<>();
|
||||
for (org.apache.maven.model.Exclusion mavenExclusion : mavenDependency.getExclusions()) {
|
||||
exclusions.add(new Exclusion(mavenExclusion.getGroupId(), mavenExclusion.getArtifactId()));
|
||||
}
|
||||
Dependency dependency = new Dependency(mavenDependency.getGroupId(), mavenDependency.getArtifactId(),
|
||||
mavenDependency.getVersion(), exclusions);
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Dependency> getDependencies() {
|
||||
return this.dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSpringBootVersion() {
|
||||
return find("spring-boot").getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dependency find(String artifactId) {
|
||||
return this.byArtifactId.get(artifactId);
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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.dependencies;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.building.DefaultModelProcessor;
|
||||
import org.apache.maven.model.io.DefaultModelReader;
|
||||
import org.apache.maven.model.locator.DefaultModelLocator;
|
||||
|
||||
/**
|
||||
* {@link DependencyManagement} derived from the effective pom of
|
||||
* {@code spring-boot-dependencies}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class SpringBootDependenciesDependencyManagement extends MavenModelDependencyManagement {
|
||||
|
||||
public SpringBootDependenciesDependencyManagement() {
|
||||
super(readModel());
|
||||
}
|
||||
|
||||
private static Model readModel() {
|
||||
DefaultModelProcessor modelProcessor = new DefaultModelProcessor();
|
||||
modelProcessor.setModelLocator(new DefaultModelLocator());
|
||||
modelProcessor.setModelReader(new DefaultModelReader());
|
||||
|
||||
try {
|
||||
return modelProcessor.read(SpringBootDependenciesDependencyManagement.class
|
||||
.getResourceAsStream("spring-boot-dependencies-effective-bom.xml"), null);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to build model from effective pom", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes for dependencies used during compilation.
|
||||
*/
|
||||
package org.springframework.boot.cli.compiler.dependencies;
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.grape;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.aether.repository.Proxy;
|
||||
import org.eclipse.aether.repository.ProxySelector;
|
||||
import org.eclipse.aether.repository.RemoteRepository;
|
||||
|
||||
/**
|
||||
* Composite {@link ProxySelector}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class CompositeProxySelector implements ProxySelector {
|
||||
|
||||
private final List<ProxySelector> selectors;
|
||||
|
||||
public CompositeProxySelector(List<ProxySelector> selectors) {
|
||||
this.selectors = selectors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Proxy getProxy(RemoteRepository repository) {
|
||||
for (ProxySelector selector : this.selectors) {
|
||||
Proxy proxy = selector.getProxy(repository);
|
||||
if (proxy != null) {
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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.grape;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.aether.DefaultRepositorySystemSession;
|
||||
import org.eclipse.aether.RepositorySystem;
|
||||
import org.eclipse.aether.repository.LocalRepository;
|
||||
import org.eclipse.aether.repository.LocalRepositoryManager;
|
||||
import org.eclipse.aether.repository.ProxySelector;
|
||||
import org.eclipse.aether.util.repository.JreProxySelector;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link RepositorySystemSessionAutoConfiguration} that, in the absence of any
|
||||
* configuration, applies sensible defaults.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class DefaultRepositorySystemSessionAutoConfiguration implements RepositorySystemSessionAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public void apply(DefaultRepositorySystemSession session, RepositorySystem repositorySystem) {
|
||||
|
||||
if (session.getLocalRepositoryManager() == null) {
|
||||
LocalRepository localRepository = new LocalRepository(getM2RepoDirectory());
|
||||
LocalRepositoryManager localRepositoryManager = repositorySystem.newLocalRepositoryManager(session,
|
||||
localRepository);
|
||||
session.setLocalRepositoryManager(localRepositoryManager);
|
||||
}
|
||||
|
||||
ProxySelector existing = session.getProxySelector();
|
||||
if (!(existing instanceof CompositeProxySelector)) {
|
||||
JreProxySelector fallback = new JreProxySelector();
|
||||
ProxySelector selector = (existing != null) ? new CompositeProxySelector(Arrays.asList(existing, fallback))
|
||||
: fallback;
|
||||
session.setProxySelector(selector);
|
||||
}
|
||||
}
|
||||
|
||||
private File getM2RepoDirectory() {
|
||||
return new File(getDefaultM2HomeDirectory(), "repository");
|
||||
}
|
||||
|
||||
private File getDefaultM2HomeDirectory() {
|
||||
String mavenRoot = System.getProperty("maven.home");
|
||||
if (StringUtils.hasLength(mavenRoot)) {
|
||||
return new File(mavenRoot);
|
||||
}
|
||||
return new File(System.getProperty("user.home"), ".m2");
|
||||
}
|
||||
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.grape;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.eclipse.aether.graph.Dependency;
|
||||
import org.eclipse.aether.graph.Exclusion;
|
||||
import org.eclipse.aether.util.artifact.JavaScopes;
|
||||
|
||||
import org.springframework.boot.cli.compiler.dependencies.ArtifactCoordinatesResolver;
|
||||
import org.springframework.boot.cli.compiler.dependencies.CompositeDependencyManagement;
|
||||
import org.springframework.boot.cli.compiler.dependencies.DependencyManagement;
|
||||
import org.springframework.boot.cli.compiler.dependencies.DependencyManagementArtifactCoordinatesResolver;
|
||||
|
||||
/**
|
||||
* Context used when resolving dependencies.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class DependencyResolutionContext {
|
||||
|
||||
private final Map<String, Dependency> managedDependencyByGroupAndArtifact = new HashMap<>();
|
||||
|
||||
private final List<Dependency> managedDependencies = new ArrayList<>();
|
||||
|
||||
private DependencyManagement dependencyManagement = null;
|
||||
|
||||
private ArtifactCoordinatesResolver artifactCoordinatesResolver;
|
||||
|
||||
private String getIdentifier(Dependency dependency) {
|
||||
return getIdentifier(dependency.getArtifact().getGroupId(), dependency.getArtifact().getArtifactId());
|
||||
}
|
||||
|
||||
private String getIdentifier(String groupId, String artifactId) {
|
||||
return groupId + ":" + artifactId;
|
||||
}
|
||||
|
||||
public ArtifactCoordinatesResolver getArtifactCoordinatesResolver() {
|
||||
return this.artifactCoordinatesResolver;
|
||||
}
|
||||
|
||||
public String getManagedVersion(String groupId, String artifactId) {
|
||||
Dependency dependency = getManagedDependency(groupId, artifactId);
|
||||
if (dependency == null) {
|
||||
dependency = this.managedDependencyByGroupAndArtifact.get(getIdentifier(groupId, artifactId));
|
||||
}
|
||||
return (dependency != null) ? dependency.getArtifact().getVersion() : null;
|
||||
}
|
||||
|
||||
public List<Dependency> getManagedDependencies() {
|
||||
return Collections.unmodifiableList(this.managedDependencies);
|
||||
}
|
||||
|
||||
private Dependency getManagedDependency(String group, String artifact) {
|
||||
return this.managedDependencyByGroupAndArtifact.get(getIdentifier(group, artifact));
|
||||
}
|
||||
|
||||
public void addManagedDependencies(List<Dependency> dependencies) {
|
||||
this.managedDependencies.addAll(dependencies);
|
||||
for (Dependency dependency : dependencies) {
|
||||
this.managedDependencyByGroupAndArtifact.put(getIdentifier(dependency), dependency);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDependencyManagement(DependencyManagement dependencyManagement) {
|
||||
for (org.springframework.boot.cli.compiler.dependencies.Dependency dependency : dependencyManagement
|
||||
.getDependencies()) {
|
||||
List<Exclusion> aetherExclusions = new ArrayList<>();
|
||||
for (org.springframework.boot.cli.compiler.dependencies.Dependency.Exclusion exclusion : dependency
|
||||
.getExclusions()) {
|
||||
aetherExclusions.add(new Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*"));
|
||||
}
|
||||
Dependency aetherDependency = new Dependency(new DefaultArtifact(dependency.getGroupId(),
|
||||
dependency.getArtifactId(), "jar", dependency.getVersion()), JavaScopes.COMPILE, false,
|
||||
aetherExclusions);
|
||||
this.managedDependencies.add(0, aetherDependency);
|
||||
this.managedDependencyByGroupAndArtifact.put(getIdentifier(aetherDependency), aetherDependency);
|
||||
}
|
||||
this.dependencyManagement = (this.dependencyManagement != null)
|
||||
? new CompositeDependencyManagement(dependencyManagement, this.dependencyManagement)
|
||||
: dependencyManagement;
|
||||
this.artifactCoordinatesResolver = new DependencyManagementArtifactCoordinatesResolver(
|
||||
this.dependencyManagement);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue