-
Notifications
You must be signed in to change notification settings - Fork 23
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
Showing
14 changed files
with
313 additions
and
13 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
### commons | ||
|
||
This is a module full of good stuff that is useful in every way, so it's a bit of a mixed bag, but I'll always update | ||
this document when there's new content. | ||
|
||
### usage | ||
|
||
```kotlin | ||
// Dependencies | ||
dependencies { | ||
// commons module | ||
compileOnly("me.qwqdev.library:commons:1.0-SNAPSHOT") | ||
} | ||
``` | ||
|
||
### [VarHandleReflectionInjector](src/main/java/me/qwqdev/library/commons/injector/VarHandleReflectionInjector.java) | ||
|
||
This is an `injector`, and its main use is to be used | ||
with [VarHandleAutoInjection](src/main/java/me/qwqdev/library/commons/injector/annotation/VarHandleAutoInjection.java). | ||
|
||
Yes, just like its name, we don't have to write a bunch of ugly code to assign `VarHandle`, let it all disappear, Amen. | ||
|
||
```java | ||
public class Example { | ||
public static void main(String[] args) { | ||
Test test = new Test(); | ||
|
||
// we can use TField_HANDLE | ||
Test.TField_HANDLE.set(test, 2); | ||
|
||
// prints 2 | ||
System.out.println(test.getTField()); | ||
} | ||
} | ||
``` | ||
|
||
```java | ||
|
||
@Getter | ||
@Setter | ||
public class Test { | ||
private volatile int tField = 100; | ||
|
||
@VarHandleAutoInjection(fieldName = "tField") | ||
public static VarHandle TField_HANDLE; | ||
|
||
static { | ||
new VarHandleReflectionInjector().inject(Test.class); | ||
} | ||
} | ||
``` |
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 |
---|---|---|
|
@@ -24,4 +24,6 @@ fairy { | |
|
||
// Dependencies | ||
dependencies { | ||
// Annotation module | ||
compileOnly(project(":annotation")) | ||
} |
16 changes: 16 additions & 0 deletions
16
commons/src/main/java/me/qwqdev/library/commons/CommonsLauncher.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 me.qwqdev.library.commons; | ||
|
||
import io.fairyproject.FairyLaunch; | ||
import io.fairyproject.container.InjectableComponent; | ||
import io.fairyproject.plugin.Plugin; | ||
|
||
/** | ||
* The type Commons launcher. | ||
* | ||
* @author qwq-dev | ||
* @since 2024-12-23 18:32 | ||
*/ | ||
@FairyLaunch | ||
@InjectableComponent | ||
public class CommonsLauncher extends Plugin { | ||
} |
25 changes: 25 additions & 0 deletions
25
commons/src/main/java/me/qwqdev/library/commons/factory/InjectorFactory.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,25 @@ | ||
package me.qwqdev.library.commons.factory; | ||
|
||
import lombok.experimental.UtilityClass; | ||
import me.qwqdev.library.commons.injector.StaticInjectorInterface; | ||
import me.qwqdev.library.commons.injector.VarHandleReflectionInjector; | ||
|
||
/** | ||
* Factory for creating injector instances. | ||
* | ||
* @author qwq-dev | ||
* @since 2024-12-23 18:38 | ||
*/ | ||
@UtilityClass | ||
public final class InjectorFactory { | ||
/** | ||
* Create a {@link VarHandleReflectionInjector} instance. | ||
* | ||
* @return a {@link VarHandleReflectionInjector} instance | ||
* @see StaticInjectorInterface | ||
* @see VarHandleReflectionInjector | ||
*/ | ||
public static StaticInjectorInterface createVarHandleReflectionInjector() { | ||
return new VarHandleReflectionInjector(); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
commons/src/main/java/me/qwqdev/library/commons/injector/ObjectInjectorInterface.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 me.qwqdev.library.commons.injector; | ||
|
||
/** | ||
* Interface for object injectors. | ||
* | ||
* @author qwq-dev | ||
* @since 2024-12-23 16:44 | ||
*/ | ||
public interface ObjectInjectorInterface { | ||
/** | ||
* Process the given object. | ||
* | ||
* @param object given object | ||
*/ | ||
void inject(Object object); | ||
} |
16 changes: 16 additions & 0 deletions
16
commons/src/main/java/me/qwqdev/library/commons/injector/StaticInjectorInterface.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 me.qwqdev.library.commons.injector; | ||
|
||
/** | ||
* Interface for static injectors. | ||
* | ||
* @author qwq-dev | ||
* @since 2024-12-23 17:07 | ||
*/ | ||
public interface StaticInjectorInterface { | ||
/** | ||
* Process the given class. | ||
* | ||
* @param clazz given class | ||
*/ | ||
void inject(Class<?> clazz); | ||
} |
100 changes: 100 additions & 0 deletions
100
commons/src/main/java/me/qwqdev/library/commons/injector/VarHandleReflectionInjector.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,100 @@ | ||
package me.qwqdev.library.commons.injector; | ||
|
||
import me.qwqdev.library.commons.injector.annotation.VarHandleAutoInjection; | ||
|
||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.VarHandle; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
|
||
/** | ||
* Utility class for injecting {@link VarHandle} instances into static fields annotated with {@link VarHandleAutoInjection}. | ||
* This class automatically injects {@link VarHandle} instances into the static fields of a class based on the annotations | ||
* present on those fields. | ||
* | ||
* <p>The injection is done via reflection, which allows this class to work without explicitly hardcoding the | ||
* dependencies. However, this approach introduces some overhead and may not be suitable for high-performance use cases. | ||
* </p> | ||
* | ||
* <p>The injection process works in two ways: | ||
* <ul> | ||
* <li><b>Default:</b> Uses {@link MethodHandles#lookup()} to locate the {@link VarHandle} for the specified static field. | ||
* This is the most common use case when static methods aren't needed.</li> | ||
* <li><b>Static Method:</b> If specified in the {@link VarHandleAutoInjection} annotation, a static method can be used | ||
* to retrieve the {@link VarHandle} for the field. This allows for more customized handling of the {@link VarHandle} | ||
* injection.</li> | ||
* </ul> | ||
* </p> | ||
* | ||
* <p>If using a static method for injection, the class containing the static method must be loadable by the current | ||
* thread's context {@link ClassLoader}. The method should be accessible and match the required signature for retrieving | ||
* the {@link VarHandle}.</p> | ||
* | ||
* <p>Due to the use of reflection, the fields will be made accessible even if they are private, ensuring that injection | ||
* can occur regardless of visibility modifiers.</p> | ||
* | ||
* <p>This class implements the {@link StaticInjectorInterface} interface, which defines the contract for injecting | ||
* dependencies (in this case, {@link VarHandle} instances) into static fields of a class.</p> | ||
* | ||
* @author qwq-dev | ||
* @since 2024-12-23 16:15 | ||
*/ | ||
public class VarHandleReflectionInjector implements StaticInjectorInterface { | ||
/** | ||
* {@inheritDoc} | ||
* <p> | ||
* Injects {@link VarHandle} instances into static fields of the given class that are annotated with | ||
* {@link VarHandleAutoInjection}. This method uses reflection to find the appropriate {@link VarHandle} | ||
* for each annotated field and assigns it to the field. | ||
* | ||
* <p>The method performs the injection by either using the default method of | ||
* {@link MethodHandles#privateLookupIn(Class, MethodHandles.Lookup)} to | ||
* locate the {@link VarHandle} for the specified static field or by using a static method if defined in the | ||
* annotation {@link VarHandleAutoInjection}. | ||
* | ||
* <p>The specified static method must contain two parameters: {@link String} and {@link Class} | ||
* | ||
* <p>If a static method is specified in the annotation, it will be called to retrieve the {@link VarHandle} | ||
* for the field. The class containing the static method must be loadable by the current thread's context | ||
* {@link ClassLoader}.</p> | ||
* | ||
* @param clazz the class into which {@link VarHandle} instances will be injected into its static fields | ||
* @throws IllegalStateException if the injection fails due to reflection issues or invalid annotations | ||
*/ | ||
@Override | ||
public void inject(Class<?> clazz) { | ||
Field[] fields = clazz.getDeclaredFields(); | ||
|
||
for (Field field : fields) { | ||
VarHandleAutoInjection annotation = field.getAnnotation(VarHandleAutoInjection.class); | ||
|
||
if (annotation == null) { | ||
continue; | ||
} | ||
|
||
String targetFieldName = annotation.fieldName(); | ||
String staticMethodName = annotation.staticMethodName(); | ||
String staticMethodPackage = annotation.staticMethodPackage(); | ||
boolean useStaticMethod = !staticMethodName.isEmpty() && !staticMethodPackage.isEmpty(); | ||
|
||
try { | ||
VarHandle varHandle; | ||
|
||
if (useStaticMethod) { | ||
Class<?> staticClass = Class.forName(staticMethodPackage); | ||
Method method = staticClass.getDeclaredMethod(staticMethodName, String.class, Class.class); | ||
method.setAccessible(true); | ||
varHandle = (VarHandle) method.invoke(null, targetFieldName, field.getType()); | ||
} else { | ||
varHandle = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()) | ||
.unreflectVarHandle(clazz.getDeclaredField(targetFieldName)); | ||
} | ||
|
||
field.setAccessible(true); | ||
field.set(null, varHandle); | ||
} catch (Exception exception) { | ||
throw new IllegalStateException("Failed to inject VarHandle for field: " + field.getName(), exception); | ||
} | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
...s/src/main/java/me/qwqdev/library/commons/injector/annotation/VarHandleAutoInjection.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,42 @@ | ||
package me.qwqdev.library.commons.injector.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
import java.lang.invoke.VarHandle; | ||
|
||
/** | ||
* Annotation to mark a field for automatic {@link VarHandle} injection. | ||
* | ||
* @author qwq-dev | ||
* @since 2024-12-23 16:15 | ||
*/ | ||
@Target(ElementType.FIELD) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface VarHandleAutoInjection { | ||
/** | ||
* The name of the target field for which the {@link VarHandle} is being generated. | ||
* | ||
* @return the field name | ||
*/ | ||
String fieldName(); | ||
|
||
/** | ||
* The name of the static method used to generate the {@link VarHandle}. | ||
* | ||
* <p>The specified static method must contain two parameters: {@link String} and {@link Class} | ||
* | ||
* @return the static method name, or an empty string if not specified | ||
*/ | ||
String staticMethodName() default ""; | ||
|
||
/** | ||
* The fully qualified name of the class containing the static method used to generate the {@link VarHandle}. | ||
* | ||
* <p>The class must be loadable by the current thread's context {@link ClassLoader}. | ||
* | ||
* @return the fully qualified class name, or an empty string if not specified | ||
*/ | ||
String staticMethodPackage() default ""; | ||
} |
Oops, something went wrong.