Package org.stianloader.remapper

# Class Remapper

java.lang.Object
org.stianloader.remapper.Remapper

public final class Remapper extends Object
Simple in-memory remapping engine. Unlike many other remappers it is able to take in already parsed `Objectweb ASM Classnodes` as input and output them without having to go through an intermediary store-to-file mode.

Additionally, this is a remapper that is only a remapper. More specifically, it will only remap - but not change your access flags, LVT entries or anything else that might not be intuitive. That being said, existing LVT entries might get edited in order to support parameter remapping, though it is not guaranteed to do so at this time (2025-12-20) and it will depend on the structure of the method. Further, it will not generate LVT entries for parameters without LVT entries.

The names of the destination namespace (or the remapped names in laymen's terms) are provided by the `MappingLookup` instance supplied through the `constructor` of this class. After construction, the remapper itself cannot be mutated and all changes need to be performed through the `MappingLookup` instance.

ClassNodes can be remapped via `remapNode(ClassNode, StringBuilder)`. A similar method also exists to remap MethodNodes and FieldNodes.

## Thread safety and concurrency

While a single instance of this class can be used in a concurrent environment and be shared across multiple threads, the same may not apply to a `MappingLookup` instance. On a similar note a single call to the remapNode methods do not cause any parallelisation to happen. As such if it is known that the remapper is called on larger classes, it might be useful to be aware that methods can be individually remapped via `remapNode(String, MethodNode, StringBuilder)`. However, `remapNode(ClassNode, StringBuilder)` implies `remapNode(String, MethodNode, StringBuilder)` so this strategy has serious flaws. If a serious performance updraft is expected when employing parallelisation on a ClassNode level, then please open up an issue on the project's repository.

## Method overloading, inheritance and other remapping restrictions

The burden of handling restrictions on method overloading and inheritance falls upon the used `MappingLookup` instance. If the `MappingLookup` instance is erroneously implemented or used (i.e. in the case of `SimpleMappingLookup` the instance being fed invalid data), it is possible to modify the way inheritance and overloading behaves - potentially causing a method to no longer override another or creating an override where no one existed beforehand. More acutely, it is also possible that inheritance applies to fields, too - this is notably the case when making use of anonymous classes at enum members. Unlike sl-deobf, the burden of handling inheritance for fields also falls upon the `MappingLookup` instance.

The `Remapper` instance is unable to verify mapping collisions and it is the job of the `MappingLookup` implementation to ensure that such events do not happen - note that some implementations such as `SimpleMappingLookup` do not check for such inconsistencies; for more information on this topic, see the manual of your lookup implementation.

While the `Remapper` instance allows nonsensical remapping requests (such as remapping methods from/to <clinit> or <init>), it is imperative that this behaviour is not relied on and that `MappingLookup` instances take the necessary precautions to prohibit such requests.

Layered mappings, that is mappings that are built ontop of other mappings, are not directly supported by this remapper. However, it is possible to easily obtain this behaviour by calling the remapNode methods multiple times - more specifically once per layer of mappings. That being said, some `MappingLookup` instances might not necessarily support such behaviour, especially when it comes to computing the hierarchy of classes as the class name might not necessarily be known to the `MappingLookup` instance. As such the alternative is directly "squashing" the mapping layers into a single `MappingLookup`. In case of doubt, consult the manual of the used lookup implementation for further guidance on how layered mappings may be implemented.

## Reflection

Remapping reflective calls are not supported due to the complexity required for such a niche feature. If absolutely needed (we generally recommend wrapping the reflective operations in a way that they are redirected as needed at runtime), 3rd party tools should be used. The same applies to method handles or other string constants. That being said, `java.lang.Class` constants will get remapped so very simple reflective operations might still behave as intended.

## Constructor Summary

Constructors
Constructor
Description
`Remapper(@NotNull MappingLookup lookup)`
Constructor.

## Method Summary

Modifier and Type
Method
Description
`final @NotNull MappingLookup`
`getLookup()`
Obtain the `MappingLookup` instance from which this `Remapper` sources all source to destination namespace name mappings.
`static @NotNull String`
`getRemappedFieldDescriptor(@NotNull MappingLookup lookup, @NotNull String fieldDesc, @NotNull StringBuilder sharedBuilder)`
Remaps a field descriptor.
`static @NotNull String`
`getRemappedMethodDescriptor(@NotNull MappingLookup lookup, @NotNull String methodDesc, @NotNull StringBuilder sharedBuilder)`
Remaps a method descriptor.
`static @NotNull String`
`remapInternalName(@NotNull MappingLookup lookup, @NotNull String internalName, @NotNull StringBuilder sharedStringBuilder)`
Remap an internal name or array `String`, meaning that this method accepts the same kind of strings as `Type.getObjectType(String)`.
`@NotNull Remapper`
`remapNode(@NotNull String owner, @NotNull org.objectweb.asm.tree.FieldNode field, @NotNull StringBuilder sharedStringBuilder)`
Remap a `FieldNode`, modifying it and it's contents.
`@NotNull Remapper`
`remapNode(@NotNull String owner, @NotNull org.objectweb.asm.tree.MethodNode method, @NotNull StringBuilder sharedStringBuilder)`
Remap a `MethodNode`, modifying it and it's contents.
`@NotNull Remapper`
`remapNode(@NotNull org.objectweb.asm.tree.ClassNode node, @NotNull StringBuilder sharedBuilder)`
Remap a `ClassNode`, modifying it and it's contents.
`static boolean`
`remapSignature(@NotNull MappingLookup lookup, @NotNull String signature, int start, int end, @NotNull StringBuilder signatureOut)`
Remap a generic signature string, as used for example in `MethodNode.signature`, `FieldNode.signature` or `ClassNode.signature`.
`static boolean`
`remapSignature(@NotNull MappingLookup lookup, @NotNull String signature, @NotNull StringBuilder out)`
Remap a generic signature string, as used for example in `MethodNode.signature`, `FieldNode.signature` or `ClassNode.signature`.

### Methods inherited from class java.lang.Object

`clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

## Constructor Details

### Remapper

public Remapper(@NotNull @NotNull MappingLookup lookup)
Constructor. Create a `Remapper` instance which uses a given `MappingLookup` instance to remap nodes.

Parameters:
  `lookup` - The lookup to use for all remapping requests, may not be null

## Method Details

### getRemappedFieldDescriptor

@NotNull public static @NotNull String getRemappedFieldDescriptor(@NotNull @NotNull MappingLookup lookup, @NotNull @NotNull String fieldDesc, @NotNull @NotNull StringBuilder sharedBuilder)
Remaps a field descriptor.

Parameters:
  `lookup` - The `MappingLookup` to use in order to remap the descriptor.
  `fieldDesc` - The old (unmapped) field descriptor
  `sharedBuilder` - A shared cached string builder. The contents of the string builder are wiped and after the invocation the contents are undefined
Returns:
  The new (remapped) field descriptor. It can be identity identical to the "fieldDesc" if it didn't need to be altered

### getRemappedMethodDescriptor

@NotNull public static @NotNull String getRemappedMethodDescriptor(@NotNull @NotNull MappingLookup lookup, @NotNull @NotNull String methodDesc, @NotNull @NotNull StringBuilder sharedBuilder)
Remaps a method descriptor.

Note: This method completely disregards bridges or other context-specific circumstances. Overall, it aims to be the most generically applicable method.

Although this method was initially written to remap `method descriptors`, this method also can work with `method signatures`.

Parameters:
  `lookup` - The `MappingLookup` to use in order to remap the descriptor.
  `methodDesc` - The old (unmapped) method descriptor
  `sharedBuilder` - A shared cached string builder. The contents of the string builder are wiped and after the invocation the contents are undefined
Returns:
  The new (remapped) method descriptor. It can be identity identical to the "methodDesc" if it didn't need to be altered

### remapInternalName

@NotNull public static @NotNull String remapInternalName(@NotNull @NotNull MappingLookup lookup, @NotNull @NotNull String internalName, @NotNull @NotNull StringBuilder sharedStringBuilder)
Remap an internal name or array `String`, meaning that this method accepts the same kind of strings as `Type.getObjectType(String)`.

The contents of the `StringBuilder` instance passed to this method might be overwritten and the contents afterwards should be considered unknown. It is especially not guaranteed (in fact, it usually won't be) that the content of the `StringBuilder` is equal to the returned `String`.

Parameters:
  `lookup` - The `MappingLookup` to use in order to remap the descriptor.
  `internalName` - The internal name in the source namespace.
  `sharedStringBuilder` - A shared `StringBuilder` instance of object pooling purposes (note: The instance should not be used across multiple threads!)
Returns:
  The remapped internal name in the destination namespace.
See Also:
  - `Type.getInternalName()`

### remapSignature

public static boolean remapSignature(@NotNull @NotNull MappingLookup lookup, @NotNull @NotNull String signature, int start, int end, @NotNull @NotNull StringBuilder signatureOut)
Remap a generic signature string, as used for example in `MethodNode.signature`, `FieldNode.signature` or `ClassNode.signature`. As this method is fairly generic it is even capable of remapping method, field or type descriptors. However, this method is not capable of remapping internal names. If internal names should be remapped, use `remapInternalName(MappingLookup, String, StringBuilder)` instead.

Internally, this method is recursive (in order to be able to correctly remap nested generics), which is why this method accepts a start and end pointer, which are the `codepoints` which should be remapped and pushed to the `StringBuilder` buffer. This algorithm evaluates the input signature from left to right.

In the case that end is greater than `start`, a crash is likely, although the type of crash is not defined. It may also deadlock or cause an `OOM situation`. Furthermore, if `end` does not correctly align with a type boundary (usually a semicolon or a character that represents a primitive), then unexpected behaviour is likely - more likely than not it will cause a crash, deadlock or `OutOfMemoryError`. As similar behaviour also applies to `start`, both `start` and `end` should be chosen carefully. More often than not, this method can be considered overkill and instead `remapSignature(MappingLookup, String, StringBuilder)` can be used safely as an alternative - however that method will remap the entire signature while this method can (if `start` and `end` are chosen accordingly) remap parts of it.

Parameters:
  `lookup` - The `MappingLookup` to use in order to remap the descriptor.
  `signature` - The signature to remap in the source namespace.
  `start` - The start of signature.
  `end` - The last codepoint of the signature that should be handled by this method. Everything beyond it is plainly ignored.
  `signatureOut` - The `StringBuilder` instance to which the remapped signature should be stored into.
Returns:
  True if a modification happened while remapping the signature, false otherwise.

### remapSignature

public static boolean remapSignature(@NotNull @NotNull MappingLookup lookup, @NotNull @NotNull String signature, @NotNull @NotNull StringBuilder out)
Remap a generic signature string, as used for example in `MethodNode.signature`, `FieldNode.signature` or `ClassNode.signature`. As this method is fairly generic it is even capable of remapping method, field or type descriptors. However, this method is not capable of remapping internal names. If internal names should be remapped, use `remapInternalName(MappingLookup, String, StringBuilder)` instead.

Internally, this method is recursive (in order to be able to correctly remap nested generics). This algorithm evaluates the input signature from left to right.

Parameters:
  `lookup` - The `MappingLookup` to use in order to remap the descriptor.
  `signature` - The signature to remap in the source namespace.
  `out` - The `StringBuilder` instance to which the remapped signature should be stored into.
Returns:
  True if a modification happened while remapping the signature, false otherwise - that is if false, `StringBuilder.toString()` of `out` will be equal to `signature`.

### getLookup

@NotNull @Contract(pure=true) public final @NotNull MappingLookup getLookup()
Obtain the `MappingLookup` instance from which this `Remapper` sources all source to destination namespace name mappings. This instance is set through the constructor.

Returns:
  The `MappingLookup` instance used by this `Remapper`.

### remapNode

@Contract(pure=false, mutates="param1,param2", value="_, _ -> this") @NotNull public @NotNull Remapper remapNode(@NotNull @NotNull org.objectweb.asm.tree.ClassNode node, @NotNull @NotNull StringBuilder sharedBuilder)
Remap a `ClassNode`, modifying it and it's contents.

Warning: The given `StringBuilder` instance may be overwritten. The contents of the `StringBuilder` before the method call are completely irrelevant, and the contents after the call may be garbage. The reason `Remapper` allows supplying `StringBuilder` instances is mostly for performance reasons in order to cut down the amount of times a `StringBuilder` instance is allocated only to be instantly discarded again.

Parameters:
  `node` - The node to remap
  `sharedBuilder` - The `StringBuilder` instance to use for string manipulation.
Returns:
  The current `Remapper` instance, for chaining

### remapNode

@NotNull @Contract(pure=false, mutates="param2, param3", value="_, _, _ -> this") public @NotNull Remapper remapNode(@NotNull @NotNull String owner, @NotNull @NotNull org.objectweb.asm.tree.FieldNode field, @NotNull @NotNull StringBuilder sharedStringBuilder)
Remap a `FieldNode`, modifying it and it's contents.

Warning: The given `StringBuilder` instance may be overwritten. The contents of the `StringBuilder` before the method call are completely irrelevant, and the contents after the call may be garbage. The reason `Remapper` allows supplying `StringBuilder` instances is mostly for performance reasons in order to cut down the amount of times a `StringBuilder` instance is allocated only to be instantly discarded again.

Parameters:
  `owner` - The owner of the member (i.e. the class where it is defined), represented as an `internal name`
  `field` - The node to remap
  `sharedStringBuilder` - The `StringBuilder` instance to use for string manipulation.
Returns:
  The current `Remapper` instance, for chaining

### remapNode

@NotNull @Contract(pure=false, mutates="param2, param3", value="_, _, _ -> this") public @NotNull Remapper remapNode(@NotNull @NotNull String owner, @NotNull @NotNull org.objectweb.asm.tree.MethodNode method, @NotNull @NotNull StringBuilder sharedStringBuilder)
Remap a `MethodNode`, modifying it and it's contents.

Warning: The given `StringBuilder` instance may be overwritten. The contents of the `StringBuilder` before the method call are completely irrelevant, and the contents after the call may be garbage. The reason `Remapper` allows supplying `StringBuilder` instances is mostly for performance reasons in order to cut down the amount of times a `StringBuilder` instance is allocated only to be instantly discarded again.

Parameters:
  `owner` - The owner of the member (i.e. the class where it is defined), represented as an `internal name`
  `method` - The node to remap
  `sharedStringBuilder` - The `StringBuilder` instance to use for string manipulation.
Returns:
  The current `Remapper` instance, for chaining