Commit 2b83edeb authored by Phillip Webb's avatar Phillip Webb

Fix jarmode support in unexploded jars

Update `LaunchedURLClassLoader` to ensure that the `JarModeLauncher`
is created in the correct classloader.

Prior to this commit the launcher was created by the application
classloader and did not have access to any of the required
`org.springframework` classes.

See gh-19848
parent 57db621b
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
package org.springframework.boot.loader; package org.springframework.boot.loader;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection; import java.net.JarURLConnection;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
...@@ -38,6 +40,8 @@ import org.springframework.boot.loader.jar.Handler; ...@@ -38,6 +40,8 @@ import org.springframework.boot.loader.jar.Handler;
*/ */
public class LaunchedURLClassLoader extends URLClassLoader { public class LaunchedURLClassLoader extends URLClassLoader {
private static final int BUFFER_SIZE = 4096;
static { static {
ClassLoader.registerAsParallelCapable(); ClassLoader.registerAsParallelCapable();
} }
...@@ -96,7 +100,7 @@ public class LaunchedURLClassLoader extends URLClassLoader { ...@@ -96,7 +100,7 @@ public class LaunchedURLClassLoader extends URLClassLoader {
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith("org.springframework.boot.loader.jarmode.")) { if (name.startsWith("org.springframework.boot.loader.jarmode.")) {
try { try {
Class<?> result = findClass(name); Class<?> result = loadClassInLaunchedClassLoader(name);
if (resolve) { if (resolve) {
resolveClass(result); resolveClass(result);
} }
...@@ -129,6 +133,35 @@ public class LaunchedURLClassLoader extends URLClassLoader { ...@@ -129,6 +133,35 @@ public class LaunchedURLClassLoader extends URLClassLoader {
} }
} }
private Class<?> loadClassInLaunchedClassLoader(String name) throws ClassNotFoundException {
String internalName = name.replace('.', '/') + ".class";
InputStream inputStream = getParent().getResourceAsStream(internalName);
if (inputStream == null) {
throw new ClassNotFoundException(name);
}
try {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
byte[] bytes = outputStream.toByteArray();
Class<?> definedClass = defineClass(name, bytes, 0, bytes.length);
definePackageIfNecessary(name);
return definedClass;
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new ClassNotFoundException("Cannot load resource for class [" + name + "]", ex);
}
}
/** /**
* Define a package before a {@code findClass} call is made. This is necessary to * Define a package before a {@code findClass} call is made. This is necessary to
* ensure that the appropriate manifest for nested JARs is associated with the * ensure that the appropriate manifest for nested JARs is associated with the
......
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