Repository navigation
Conversation
The Signature attribute of a record component was not renamed, so RecordComponent.getGenericType() threw TypeNotPresentException when a component's type was obfuscated. Record components were renamed like their fields while their accessors were renamed like methods, so RecordComponent.getAccessor() returned null for most components. Record component signatures are now renamed like the signatures of fields and methods, and each record component is now renamed like its accessor method. RecordsTest compiles a set of records, obfuscates them, runs code that reflects over them, and checks the Record attribute against the accessors. It also covers a retained record whose component types are obfuscated. The tests need Java 16 or newer and print a notice on older versions, like the existing Java 21 tests.
This branch has not been deployed
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #179.
Obfuscated records could not be used through
java.lang.reflect.RecordComponent, which reflective libraries and record serialization rely on:ClassFile.remapassumed a record component'sSignature"is always a simple name", but it is the component's full generic type, e.g.Ljava/util/List<Lcom/acme/Item;>;. Field and method signatures were renamed; component signatures kept the original class names, soRecordComponent.getGenericType()threwTypeNotPresentException. The component'sSignaturenow goes throughremapSignaturelike the others.RecordComponent.getAccessor()finds the accessor by the component's name, and javac guarantees that name equals the accessor's. With the two renamed independently,getAccessor()returnednull, and in some records the names crossed over between components. Each component is now renamed withnm.mapMethod(className, name, "()" + descriptor), so it always gets its accessor's new name. That includes accessors with bodies and accessors that implement interface methods. Field names still change independently; the JVM and reflection don't require a component's name to match its field's.Tests
RecordsTestcompilesRecordComponents.txt, obfuscates it withGuardDB, and checks:testObfuscatedRecordsSupportReflectionruns code inside the obfuscated JAR that prints, for every component, its resolved generic type and the value its accessor returns. The output must equal the unobfuscated output. The records cover a generic component whose type is renamed, same-typed components (so swapped accessors show up), a type variable, nested generics, explicit accessors with bodies, an accessor that implements an interface method, an alias getter, primitives and arrays, an empty record, and record-typed components.testObfuscatedRecordComponentAttributesreads theRecordattribute with ASM. Every component must name an instance methodname()descriptorand carry exactly that method's generic signature, and no signature may contain an original class name.testRetainedRecordReferringToObfuscatedClasseskeeps a record's class and member names while the class its component refers to is renamed. Component names stay the same, and the signature must be renamed.testUnobfuscatedRecordschecks the expected output against the unobfuscated records, so a failure points at obfuscation rather than at the fixture.Without the fix the three obfuscation tests fail. Each half of the fix is caught on its own: without the signature change the attribute test reports the original class name, and without the naming change it reports a missing accessor.
Like the existing Java 21
SwitchBootstrapstests, these need a Java 16+ test JVM to compile records and printRun test with Java 16 or newer.otherwise. Results:./gradlew build teston JDK 11: passes, includingeditorconfigCheck. The record tests print the notice.