-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e4fa190
Showing
22 changed files
with
806 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
**/build | ||
**/**/build | ||
.idea | ||
.gradle | ||
gradle.properties |
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,26 @@ | ||
subprojects { | ||
apply plugin: 'java' | ||
|
||
group 'ru.kdev' | ||
version '1.0-SNAPSHOT' | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
compileOnly files('../extensions-core/build/libs/extensions-core-1.0-SNAPSHOT.jar') | ||
implementation 'org.ow2.asm:asm:9.1' | ||
implementation group: 'org.ow2.asm', name: 'asm-tree', version: '9.1' | ||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' | ||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' | ||
} | ||
|
||
jar { | ||
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }} | ||
} | ||
|
||
test { | ||
useJUnitPlatform() | ||
} | ||
} |
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,7 @@ | ||
jar { | ||
manifest { | ||
attributes 'Premain-Class': 'ru.kdev.extensions.ExtensionsBootstrap', | ||
'Can-Redefine-Classes': 'true', | ||
'Can-Retransform-Classes': 'true' | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
extensions-core/src/main/java/ru/kdev/extensions/ExtensionList.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,49 @@ | ||
package ru.kdev.extensions; | ||
|
||
import ru.kdev.extensions.annotation.Extension; | ||
|
||
import java.io.InputStream; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.Scanner; | ||
|
||
public class ExtensionList { | ||
|
||
private final List<Class<?>> extensions = new ArrayList<>(); | ||
|
||
public static ExtensionList parse(InputStream stream) throws ClassNotFoundException { | ||
Scanner scanner = new Scanner(stream); | ||
ExtensionList list = new ExtensionList(); | ||
|
||
while (scanner.hasNext()) { | ||
String line = scanner.nextLine(); | ||
list.extensions.add(Class.forName(line)); | ||
} | ||
|
||
return list; | ||
} | ||
|
||
public Class<?> getExtensionByTarget(Class<?> target) { | ||
for(Class<?> extension : extensions) { | ||
if(Arrays.asList(extension.getAnnotation(Extension.class).classes()).contains(target)) { | ||
return extension; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
public Class<?>[] getAllTargets() { | ||
List<Class<?>> targets = new ArrayList<>(); | ||
|
||
for(Class<?> ext : extensions) { | ||
targets.addAll(Arrays.asList(ext.getAnnotation(Extension.class).classes())); | ||
} | ||
|
||
return targets.toArray(new Class<?>[0]); | ||
} | ||
|
||
public List<Class<?>> getExtensions() { | ||
return extensions; | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
extensions-core/src/main/java/ru/kdev/extensions/ExtensionsBootstrap.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 ru.kdev.extensions; | ||
|
||
import ru.kdev.extensions.processor.ExtensionsClassFileTransformer; | ||
|
||
import java.lang.instrument.Instrumentation; | ||
|
||
public class ExtensionsBootstrap { | ||
|
||
public static void premain(String arg, Instrumentation instrumentation) { | ||
try { | ||
ExtensionList list = ExtensionList.parse(ExtensionsBootstrap.class.getResourceAsStream("/extensions")); | ||
|
||
instrumentation.addTransformer(new ExtensionsClassFileTransformer(list), true); | ||
instrumentation.retransformClasses(list.getAllTargets()); | ||
} catch (ClassNotFoundException ex) { | ||
throw new IllegalArgumentException("Main class not found or main method not found."); | ||
} catch (Throwable throwable) { | ||
throwable.printStackTrace(); | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
extensions-core/src/main/java/ru/kdev/extensions/annotation/Extension.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,16 @@ | ||
package ru.kdev.extensions.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.TYPE) | ||
public @interface Extension { | ||
|
||
/** | ||
* Target classes | ||
* */ | ||
Class<?>[] classes(); | ||
} |
32 changes: 32 additions & 0 deletions
32
extensions-core/src/main/java/ru/kdev/extensions/annotation/Inject.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,32 @@ | ||
package ru.kdev.extensions.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.METHOD) | ||
public @interface Inject { | ||
|
||
/** | ||
* Target method(s) | ||
* */ | ||
String[] method(); | ||
|
||
/** | ||
* Target place | ||
* */ | ||
At at(); | ||
|
||
/** | ||
* Allows to change return node | ||
* Only on bottom inject | ||
* */ | ||
boolean changeReturn() default false; | ||
|
||
enum At { | ||
TOP, | ||
BOTTOM | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
extensions-core/src/main/java/ru/kdev/extensions/annotation/TargetField.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,11 @@ | ||
package ru.kdev.extensions.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.FIELD) | ||
public @interface TargetField { | ||
} |
11 changes: 11 additions & 0 deletions
11
extensions-core/src/main/java/ru/kdev/extensions/annotation/TargetMethod.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,11 @@ | ||
package ru.kdev.extensions.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.METHOD) | ||
public @interface TargetMethod { | ||
} |
30 changes: 30 additions & 0 deletions
30
extensions-core/src/main/java/ru/kdev/extensions/internal/Util.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,30 @@ | ||
package ru.kdev.extensions.internal; | ||
|
||
import org.objectweb.asm.Type; | ||
import sun.misc.Unsafe; | ||
|
||
import java.lang.invoke.MethodHandles; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
|
||
public final class Util { | ||
|
||
public static MethodHandles.Lookup TRUSTED_LOOKUP; | ||
public static Unsafe UNSAFE; | ||
|
||
public static String getMethodDescriptor(Method m) { | ||
return Type.getMethodDescriptor(m); | ||
} | ||
|
||
static { | ||
try { | ||
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); | ||
theUnsafe.setAccessible(true); | ||
UNSAFE = (Unsafe) theUnsafe.get(null); | ||
Field implLookup = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP"); | ||
TRUSTED_LOOKUP = (MethodHandles.Lookup) UNSAFE.getObjectVolatile(UNSAFE.staticFieldBase(implLookup), UNSAFE.staticFieldOffset(implLookup)); | ||
} catch (NoSuchFieldException | IllegalAccessException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
...sions-core/src/main/java/ru/kdev/extensions/processor/ExtensionsClassFileTransformer.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,31 @@ | ||
package ru.kdev.extensions.processor; | ||
|
||
import ru.kdev.extensions.ExtensionList; | ||
|
||
import java.io.IOException; | ||
import java.lang.instrument.ClassFileTransformer; | ||
import java.security.ProtectionDomain; | ||
|
||
public class ExtensionsClassFileTransformer implements ClassFileTransformer { | ||
|
||
private final ExtensionList extensionList; | ||
|
||
public ExtensionsClassFileTransformer(ExtensionList list) { | ||
this.extensionList = list; | ||
} | ||
|
||
@Override | ||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { | ||
Class<?> extension = extensionList.getExtensionByTarget(classBeingRedefined); | ||
|
||
if(extension != null) { | ||
try { | ||
return ExtensionsProcessor.process(extension, classBeingRedefined); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
return classfileBuffer; | ||
} | ||
} |
Oops, something went wrong.