forked from lucko/helper
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use sun.misc.Unsafe to inject URLs into ClassLoaders on Java 9+ (luck…
- Loading branch information
Showing
7 changed files
with
84 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
helper/src/main/java/me/lucko/helper/maven/URLInjector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package me.lucko.helper.maven; | ||
|
||
import javax.annotation.Nonnull; | ||
import java.net.URL; | ||
import java.net.URLClassLoader; | ||
|
||
/** | ||
* Handles injecting URLs into a {@link URLClassLoader} | ||
*/ | ||
interface URLInjector { | ||
|
||
/** | ||
* Adds the given URL to the class loader | ||
* | ||
* @param classLoader ClassLoader to add to | ||
* @param url URL to add | ||
* @throws Exception Any exception whilst adding | ||
*/ | ||
void addURL(@Nonnull ClassLoader classLoader, @Nonnull URL url) throws Exception; | ||
|
||
} |
56 changes: 56 additions & 0 deletions
56
helper/src/main/java/me/lucko/helper/maven/UnsafeURLInjector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package me.lucko.helper.maven; | ||
|
||
import sun.misc.Unsafe; | ||
|
||
import javax.annotation.Nonnull; | ||
import java.lang.reflect.Field; | ||
import java.net.URL; | ||
import java.net.URLClassLoader; | ||
import java.util.ArrayDeque; | ||
import java.util.ArrayList; | ||
|
||
/** | ||
* An implementation of {@link URLInjector} that uses sun.misc.Unsafe to | ||
* inject URLs directly into a {@link URLClassLoader}'s paths. | ||
* <p> | ||
* This implementation works on Java 9+ only. | ||
*/ | ||
final class UnsafeURLInjector implements URLInjector { | ||
|
||
private final ArrayDeque<URL> unopenedURLs; | ||
private final ArrayList<URL> pathURLs; | ||
|
||
public UnsafeURLInjector(final ArrayDeque<URL> unopenedURLs, final ArrayList<URL> pathURLs) { | ||
this.unopenedURLs = unopenedURLs; | ||
this.pathURLs = pathURLs; | ||
} | ||
|
||
public static URLInjector create(final URLClassLoader classLoader) { | ||
try { | ||
final Field field = Unsafe.class.getDeclaredField("theUnsafe"); | ||
field.setAccessible(true); | ||
final Unsafe unsafe = (Unsafe) field.get(null); | ||
final Object ucp = fetchField(unsafe, URLClassLoader.class, classLoader, "ucp"); | ||
final ArrayDeque<URL> unopenedURLs = (ArrayDeque<URL>) fetchField(unsafe, ucp, "unopenedUrls"); | ||
final ArrayList<URL> pathURLs = (ArrayList<URL>) fetchField(unsafe, ucp, "path"); | ||
return new UnsafeURLInjector(unopenedURLs, pathURLs); | ||
} catch (Throwable t) { | ||
return (loader, url) -> { throw new UnsupportedOperationException(); }; | ||
} | ||
} | ||
|
||
private static Object fetchField(final Unsafe unsafe, final Object object, final String name) throws NoSuchFieldException { | ||
return fetchField(unsafe, object.getClass(), object, name); | ||
} | ||
|
||
private static Object fetchField(final Unsafe unsafe, final Class<?> clazz, final Object object, final String name) throws NoSuchFieldException { | ||
final Field field = clazz.getDeclaredField(name); | ||
final long offset = unsafe.objectFieldOffset(field); | ||
return unsafe.getObject(object, offset); | ||
} | ||
|
||
@Override public void addURL(@Nonnull ClassLoader classLoader, @Nonnull URL url) { | ||
unopenedURLs.addLast(url); | ||
pathURLs.add(url); | ||
} | ||
} |