Commit aede0165 authored by Phillip Webb's avatar Phillip Webb

Favor groovy.jar instead of groovy-all.jar

Update CLI application to use groovy.jar rather than groovy-all.jar.
This prevents classloading issues when a user project @Grabs groovy-ant.
parent 557f69a4
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.codehaus.groovy</groupId> <groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId> <artifactId>groovy</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
...@@ -94,6 +94,11 @@ ...@@ -94,6 +94,11 @@
<artifactId>aether-util</artifactId> <artifactId>aether-util</artifactId>
</dependency> </dependency>
<!-- Provided --> <!-- Provided -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-templates</artifactId>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
......
...@@ -26,8 +26,11 @@ import java.net.URL; ...@@ -26,8 +26,11 @@ import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.control.CompilationUnit; import org.codehaus.groovy.control.CompilationUnit;
...@@ -159,39 +162,39 @@ class ExtendedGroovyClassLoader extends GroovyClassLoader { ...@@ -159,39 +162,39 @@ class ExtendedGroovyClassLoader extends GroovyClassLoader {
*/ */
private static class DefaultScopeParentClassLoader extends ClassLoader { private static class DefaultScopeParentClassLoader extends ClassLoader {
private static final String[] GROOVY_JARS_PREFIXES = { "groovy", "antlr", "asm" };
private final URLClassLoader groovyOnlyClassLoader; private final URLClassLoader groovyOnlyClassLoader;
public DefaultScopeParentClassLoader(ClassLoader parent) { public DefaultScopeParentClassLoader(ClassLoader parent) {
super(parent); super(parent);
this.groovyOnlyClassLoader = new URLClassLoader( this.groovyOnlyClassLoader = new URLClassLoader(getGroovyJars(parent), null);
new URL[] { getGroovyJar(parent) }, null);
} }
private URL getGroovyJar(final ClassLoader parent) { private URL[] getGroovyJars(final ClassLoader parent) {
URL result = findGroovyJarDirectly(parent); Set<URL> urls = new HashSet<URL>();
if (result == null) { findGroovyJarsDirectly(parent, urls);
result = findGroovyJarFromClassPath(parent); if (urls.isEmpty()) {
findGroovyJarsFromClassPath(parent, urls);
} }
Assert.state(result != null, "Unable to find groovy JAR"); Assert.state(urls.size() > 0, "Unable to find groovy JAR");
return result; return new ArrayList<URL>(urls).toArray(new URL[urls.size()]);
} }
private URL findGroovyJarDirectly(ClassLoader classLoader) { private void findGroovyJarsDirectly(ClassLoader classLoader, Set<URL> urls) {
while (classLoader != null) { while (classLoader != null) {
if (classLoader instanceof URLClassLoader) { if (classLoader instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) classLoader).getURLs(); for (URL url : ((URLClassLoader) classLoader).getURLs()) {
for (URL url : urls) {
if (isGroovyJar(url.toString())) { if (isGroovyJar(url.toString())) {
return url; urls.add(url);
} }
} }
} }
classLoader = classLoader.getParent(); classLoader = classLoader.getParent();
} }
return null;
} }
private URL findGroovyJarFromClassPath(ClassLoader parent) { private void findGroovyJarsFromClassPath(ClassLoader parent, Set<URL> urls) {
String classpath = System.getProperty("java.class.path"); String classpath = System.getProperty("java.class.path");
String[] entries = classpath.split(System.getProperty("path.separator")); String[] entries = classpath.split(System.getProperty("path.separator"));
for (String entry : entries) { for (String entry : entries) {
...@@ -199,7 +202,7 @@ class ExtendedGroovyClassLoader extends GroovyClassLoader { ...@@ -199,7 +202,7 @@ class ExtendedGroovyClassLoader extends GroovyClassLoader {
File file = new File(entry); File file = new File(entry);
if (file.canRead()) { if (file.canRead()) {
try { try {
return file.toURI().toURL(); urls.add(file.toURI().toURL());
} }
catch (MalformedURLException ex) { catch (MalformedURLException ex) {
// Swallow and continue // Swallow and continue
...@@ -207,11 +210,15 @@ class ExtendedGroovyClassLoader extends GroovyClassLoader { ...@@ -207,11 +210,15 @@ class ExtendedGroovyClassLoader extends GroovyClassLoader {
} }
} }
} }
return null;
} }
private boolean isGroovyJar(String entry) { private boolean isGroovyJar(String entry) {
return entry.contains("/groovy-all"); for (String jarPrefix : GROOVY_JARS_PREFIXES) {
if (entry.contains("/" + jarPrefix + "-")) {
return true;
}
}
return false;
} }
@Override @Override
......
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
package org.springframework.boot.cli; package org.springframework.boot.cli;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
...@@ -86,6 +90,26 @@ public class CliTester implements TestRule { ...@@ -86,6 +90,26 @@ public class CliTester implements TestRule {
return this.outputCapture.apply(new RunLauncherStatement(base), description); return this.outputCapture.apply(new RunLauncherStatement(base), description);
} }
public String getHttpOutput() {
return getHttpOutput("http://localhost:8080");
}
public String getHttpOutput(String uri) {
try {
InputStream stream = URI.create(uri).toURL().openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line;
StringBuilder result = new StringBuilder();
while ((line = reader.readLine()) != null) {
result.append(line);
}
return result.toString();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
private final class RunLauncherStatement extends Statement { private final class RunLauncherStatement extends Statement {
private final Statement base; private final Statement base;
......
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.cli;
import org.junit.Rule;
import org.junit.Test;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
/**
* Integration tests to exercise reproduce raised issues.
*
* @author Phillip Webb
*/
public class ReproIntegrationTests {
private static final String SRC = "src/test/resources/repro-samples";
@Rule
public CliTester cli = new CliTester();
@Test
public void grabAntBuilder() throws Exception {
this.cli.run(SRC + "/grab-ant-builder.groovy");
assertThat(this.cli.getHttpOutput(),
containsString("{\"message\":\"Hello World\"}"));
}
}
...@@ -16,11 +16,7 @@ ...@@ -16,11 +16,7 @@
package org.springframework.boot.cli; package org.springframework.boot.cli;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.FileUtils;
import org.junit.BeforeClass; import org.junit.BeforeClass;
...@@ -85,31 +81,29 @@ public class SampleIntegrationTests { ...@@ -85,31 +81,29 @@ public class SampleIntegrationTests {
"foo=bar"); "foo=bar");
assertTrue("Wrong output: " + output, assertTrue("Wrong output: " + output,
output.contains("completed with the following parameters")); output.contains("completed with the following parameters"));
String result = readEntirely("http://localhost:8080"); String result = this.cli.getHttpOutput();
assertEquals("World!", result); assertEquals("World!", result);
} }
@Test @Test
public void webSample() throws Exception { public void webSample() throws Exception {
this.cli.run("samples/web.groovy"); this.cli.run("samples/web.groovy");
String result = readEntirely("http://localhost:8080"); assertEquals("World!", this.cli.getHttpOutput());
assertEquals("World!", result);
} }
@Test @Test
public void uiSample() throws Exception { public void uiSample() throws Exception {
this.cli.run("samples/ui.groovy", "--classpath=.:src/test/resources"); this.cli.run("samples/ui.groovy", "--classpath=.:src/test/resources");
String result = readEntirely("http://localhost:8080"); String result = this.cli.getHttpOutput();
assertTrue("Wrong output: " + result, result.contains("Hello World")); assertTrue("Wrong output: " + result, result.contains("Hello World"));
result = readEntirely("http://localhost:8080/css/bootstrap.min.css"); result = this.cli.getHttpOutput("http://localhost:8080/css/bootstrap.min.css");
assertTrue("Wrong output: " + result, result.contains("container")); assertTrue("Wrong output: " + result, result.contains("container"));
} }
@Test @Test
public void actuatorSample() throws Exception { public void actuatorSample() throws Exception {
this.cli.run("samples/actuator.groovy"); this.cli.run("samples/actuator.groovy");
String result = readEntirely("http://localhost:8080"); assertEquals("{\"message\":\"Hello World!\"}", this.cli.getHttpOutput());
assertEquals("{\"message\":\"Hello World!\"}", result);
} }
@Test @Test
...@@ -156,24 +150,7 @@ public class SampleIntegrationTests { ...@@ -156,24 +150,7 @@ public class SampleIntegrationTests {
@Test @Test
public void deviceSample() throws Exception { public void deviceSample() throws Exception {
this.cli.run("samples/device.groovy"); this.cli.run("samples/device.groovy");
String result = readEntirely("http://localhost:8080"); assertEquals("Hello Normal Device!", this.cli.getHttpOutput());
assertEquals("Hello Normal Device!", result);
}
private static String readEntirely(String uri) {
try {
InputStream stream = URI.create(uri).toURL().openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line;
StringBuilder result = new StringBuilder();
while ((line = reader.readLine()) != null) {
result.append(line);
}
return result.toString();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
} }
} }
@Grab("org.codehaus.groovy:groovy-ant:2.1.6")
@RestController
class MainController {
@RequestMapping("/")
def home() {
new AntBuilder().echo(message:"Hello world")
[message: "Hello World"]
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment