77import org .parchmentmc .feather .mapping .MappingDataContainer ;
88import org .parchmentmc .feather .metadata .ClassMetadata ;
99import org .parchmentmc .feather .metadata .MethodMetadata ;
10+ import org .parchmentmc .feather .metadata .RecordMetadata ;
1011import org .parchmentmc .feather .metadata .SourceMetadata ;
12+ import org .parchmentmc .feather .metadata .WithType ;
1113
1214import java .io .IOException ;
15+ import java .util .HashMap ;
1316import java .util .Map ;
17+ import java .util .Objects ;
18+ import java .util .stream .Collectors ;
1419
1520public abstract class GenerateSanitizedExport extends GenerateExport {
1621 public GenerateSanitizedExport () {
@@ -31,6 +36,7 @@ protected MappingDataContainer modifyData(MappingDataContainer container) throws
3136 final boolean skipAnonClasses = getSkipAnonymousClassParameters ().get ();
3237
3338 final Map <String , ClassMetadata > classMetadataMap = MappingUtil .buildClassMetadataMap (metadata );
39+ final Map <String , String > recordClassesToCanonicalDescriptors = new HashMap <>();
3440
3541 // Cascade parent methods first separately so that prefixes don't get applied multiple times
3642 builder .getClasses ().forEach (clsData -> cascadeParentMethods (builder , classMetadataMap , clsData , classMetadataMap .get (clsData .getName ())));
@@ -48,12 +54,19 @@ protected MappingDataContainer modifyData(MappingDataContainer container) throws
4854 // Simple heuristic; if it starts with `lambda$`, it's a lambda.
4955 boolean lambda = (methodMeta != null && methodMeta .isLambda ())
5056 || (methodMeta == null && methodData .getName ().startsWith ("lambda$" ));
57+
58+ // Whether the current method is a canonical constructor for a record
59+ boolean recordCanonical = clsMeta != null
60+ && clsMeta .isRecord ()
61+ && methodData .getName ().equals ("<init>" )
62+ && recordClassesToCanonicalDescriptors .computeIfAbsent (clsData .getName (),
63+ s -> createCanonicalConstructor (clsMeta )).equals (methodData .getDescriptor ());
5164
5265 methodData .getParameters ().forEach (paramData -> {
5366 if (paramData .getName () != null ) {
5467 if ((skipAnonClasses && anonClass ) || (skipLambdas && lambda )) {
5568 paramData .setName (null );
56- } else {
69+ } else if (! recordCanonical ) {
5770 paramData .setName (paramPrefix + capitalize (paramData .getName ()));
5871 }
5972 }
@@ -93,4 +106,15 @@ private static boolean withinAnonymousClass(String className) {
93106 }
94107 return false ;
95108 }
109+
110+ private static String createCanonicalConstructor (ClassMetadata classMeta ) {
111+ final String params = classMeta .getRecords ().stream ()
112+ .map (RecordMetadata ::getField )
113+ .map (WithType ::getDescriptor )
114+ .map (named -> named .getMojangName ().orElse (null ))
115+ .filter (Objects ::nonNull )
116+ .collect (Collectors .joining ("" ));
117+
118+ return "(" + params + ")V" ;
119+ }
96120}
0 commit comments