Merge branch '1.3.x'
This commit is contained in:
commit
140e86bb97
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2015 the original author or authors.
|
* Copyright 2012-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package org.springframework.boot.devtools.restart;
|
package org.springframework.boot.devtools.restart;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -23,13 +26,18 @@ import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
import org.springframework.boot.devtools.settings.DevToolsSettings;
|
import org.springframework.boot.devtools.settings.DevToolsSettings;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A filtered collections of URLs which can be change after the application has started.
|
* A filtered collection of URLs which can change after the application has started.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
final class ChangeableUrls implements Iterable<URL> {
|
final class ChangeableUrls implements Iterable<URL> {
|
||||||
|
|
||||||
|
|
@ -74,7 +82,59 @@ final class ChangeableUrls implements Iterable<URL> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ChangeableUrls fromUrlClassLoader(URLClassLoader classLoader) {
|
public static ChangeableUrls fromUrlClassLoader(URLClassLoader classLoader) {
|
||||||
return fromUrls(classLoader.getURLs());
|
List<URL> urls = new ArrayList<URL>();
|
||||||
|
for (URL url : classLoader.getURLs()) {
|
||||||
|
urls.add(url);
|
||||||
|
urls.addAll(getUrlsFromClassPathOfJarManifestIfPossible(url));
|
||||||
|
}
|
||||||
|
return fromUrls(urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<URL> getUrlsFromClassPathOfJarManifestIfPossible(URL url) {
|
||||||
|
JarFile jarFile = getJarFileIfPossible(url);
|
||||||
|
if (jarFile != null) {
|
||||||
|
try {
|
||||||
|
return getUrlsFromClassPathAttribute(jarFile.getManifest());
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Failed to read Class-Path attribute from manifest of jar "
|
||||||
|
+ url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.<URL>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JarFile getJarFileIfPossible(URL url) {
|
||||||
|
try {
|
||||||
|
File file = new File(url.toURI());
|
||||||
|
if (file.isFile()) {
|
||||||
|
return new JarFile(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
// Assume it's not a jar and continue
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<URL> getUrlsFromClassPathAttribute(Manifest manifest) {
|
||||||
|
List<URL> urls = new ArrayList<URL>();
|
||||||
|
String classPathAttribute = manifest.getMainAttributes()
|
||||||
|
.getValue(Attributes.Name.CLASS_PATH);
|
||||||
|
if (StringUtils.hasText(classPathAttribute)) {
|
||||||
|
for (String entry : StringUtils.delimitedListToStringArray(classPathAttribute,
|
||||||
|
" ")) {
|
||||||
|
try {
|
||||||
|
urls.add(new URL(entry));
|
||||||
|
}
|
||||||
|
catch (MalformedURLException ex) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Class-Path attribute contains malformed URL", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ChangeableUrls fromUrls(Collection<URL> urls) {
|
public static ChangeableUrls fromUrls(Collection<URL> urls) {
|
||||||
|
|
|
||||||
|
|
@ -17,19 +17,27 @@
|
||||||
package org.springframework.boot.devtools.restart;
|
package org.springframework.boot.devtools.restart;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.JarOutputStream;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ChangeableUrls}.
|
* Tests for {@link ChangeableUrls}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
public class ChangeableUrlsTests {
|
public class ChangeableUrlsTests {
|
||||||
|
|
||||||
|
|
@ -63,6 +71,16 @@ public class ChangeableUrlsTests {
|
||||||
assertThat(urls.size()).isEqualTo(0);
|
assertThat(urls.size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void urlsFromJarClassPathAreConsidered() throws Exception {
|
||||||
|
URL projectCore = makeUrl("project-core");
|
||||||
|
URL projectWeb = makeUrl("project-web");
|
||||||
|
ChangeableUrls urls = ChangeableUrls.fromUrlClassLoader(new URLClassLoader(
|
||||||
|
new URL[] { makeJarFileWithUrlsInManifestClassPath(projectCore,
|
||||||
|
projectWeb) }));
|
||||||
|
assertThat(urls.toList()).containsExactly(projectCore, projectWeb);
|
||||||
|
}
|
||||||
|
|
||||||
private URL makeUrl(String name) throws IOException {
|
private URL makeUrl(String name) throws IOException {
|
||||||
File file = this.temporaryFolder.newFolder();
|
File file = this.temporaryFolder.newFolder();
|
||||||
file = new File(file, name);
|
file = new File(file, name);
|
||||||
|
|
@ -72,4 +90,15 @@ public class ChangeableUrlsTests {
|
||||||
return file.toURI().toURL();
|
return file.toURI().toURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private URL makeJarFileWithUrlsInManifestClassPath(URL... urls) throws Exception {
|
||||||
|
File classpathJar = this.temporaryFolder.newFile("classpath.jar");
|
||||||
|
Manifest manifest = new Manifest();
|
||||||
|
manifest.getMainAttributes().putValue(Attributes.Name.MANIFEST_VERSION.toString(),
|
||||||
|
"1.0");
|
||||||
|
manifest.getMainAttributes().putValue(Attributes.Name.CLASS_PATH.toString(),
|
||||||
|
StringUtils.arrayToDelimitedString(urls, " "));
|
||||||
|
new JarOutputStream(new FileOutputStream(classpathJar), manifest).close();
|
||||||
|
return classpathJar.toURI().toURL();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue