Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jpenilla/reflection-remapper

Java reflection library with support for obfuscation mappings
https://github.com/jpenilla/reflection-remapper

java mappings papermc reflection remapping

Last synced: 1 day ago
JSON representation

Java reflection library with support for obfuscation mappings

Awesome Lists containing this project

README

        

# reflection-remapper
reflection-remapper is a library to simplify making reflective calls, with specific support for remapped environments.

## Getting reflection-remapper
Releases are published to [Maven Central](https://central.sonatype.com/artifact/xyz.jpenilla/reflection-remapper).

>
> Using snapshot builds
>
> Snapshot builds are available on the Sonatype snapshots Maven repository: `https://s01.oss.sonatype.org/content/repositories/snapshots/`
>
> Consult your build tool's documentation for details on adding Maven repositories to your project.
>

### Gradle Kotlin DSL
>
> Click to show build.gradle.kts
>
> ```kotlin
> repositories {
> mavenCentral()
> }
>
> dependencies {
> implementation("xyz.jpenilla:reflection-remapper:0.1.1")
> }
> ```
>

### Gradle Groovy DSL
>
> Click to show build.gradle
>
> ```groovy
> repositories {
> mavenCentral()
> }
>
> dependencies {
> implementation 'xyz.jpenilla:reflection-remapper:0.1.1'
> }
> ```
>

## Using reflection-remapper

*Note: The following is a basic introduction; For further details, consult the reflection-remapper Javadocs.*

### `ReflectionRemapper`
`ReflectionRemapper` is the interface provided by reflection-remapper for remapping class, method, and field names for reflection lookups.

>
> Click to see Java code snippet
>
> ```java
> final Path mappingsFile = /* get path to mappings ... */;
> // ReflectionRemapper provides various static factory methods, in this example we use the one from a Path
> // Note that the standard ReflectionRemapper implementations store their mappings in memory, which can be multiple megabytes large in some cases.
> // This means it's best to use the remapper when your program starts and then dispose of any reference to it, so it can be garbage collected.
> final ReflectionRemapper reflectionRemapper = ReflectionRemapper.forMappings(mappingsFile, "fromNamespace", "toNamespace");
>
> final String runtimeName = reflectionRemapper.remapClassName("net.minecraft.server.level.ServerPlayer");
> final Class> serverPlayerClass = Class.forName(runtimeName); // Exception handling omitted for brevity
> final String runtimeFieldName = reflectionRemapper.remapFieldName(serverPlayerClass, "seenCredits");
> // ...
> ```
>

### Reflection Proxies

A reflection proxy is a runtime generated implementation of a "reflection proxy interface", which uses cached `MethodHandle`s to invoke the targets specified by
the interface definition. Reflection proxies can also make use of a `ReflectionRemapper` on creation in order to allow them to work in a remapped (or not) environment.
The `ReflectionRemapper` on its own, while powerful, tends to make already verbose reflection code even more verbose. When combined with reflection proxies, we
can have relatively clean reflection code while still properly remapping.

>
> Click to see Java code snippet
>
> #### Example target class
> ```java
> public final class ServerLevel {
> private SleepStatus sleepStatus;
>
> private BlockPos findLightningTargetAround(BlockPos pos) {
> // implementation
> }
> }
> ```
>
> #### Example reflection proxy interface
> ```java
> @Proxies(ServerLevel.class) // Can use Class or fully qualified class name (for inaccessible classes)
> private interface ServerLevelProxy {
> BlockPos findLightningTargetAround(ServerLevel instance, BlockPos pos);
>
> @FieldSetter("sleepStatus")
> void setSleepStatus(ServerLevel instance, SleepStatus value);
> }
> ```
>
> #### Creating and using reflection proxy instance
> ```java
> final ReflectionRemapper reflectionRemapper = /* get ReflectionRemapper ... */;
> final ClassLoader classLoader = /* get ClassLoader for loading proxy implementations, generally it needs to be able to see any reflection proxy interfaces you want to implement */;
> final ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper, classLoader); // ReflectionProxyFactory holds a ref to it's ReflectionRemapper
>
> // Generated proxy instances do not hold a ref to the ReflectionRemapper, and are fine to keep around.
> final ServerLevelProxy proxyInstance = reflectionProxyFactory.reflectionProxy(ServerLevelProxy.class);
>
> // ...
>
> final ServerLevel level = /* ... */;
> final BlockPos blockPos = /* ... */;
> final BlockPos target = proxyInstance.findLightningTargetAround(level, blockPos);
> proxyInstance.setSleepStatus(level, new SleepStatus());
> ```
>