Recaf
Recaf copied to clipboard
Reduce Recaf artifact size
Current size as of 2b3017f0866dc8e6c17fc325ac6ba6e620ade841 - 76 MB - (Nov 18 2024)
Current size as of 17371d720e71d06665f472a09cff80437a4733eb - 56 MB - (Jan 3 2025)
Current size as of bcf59f76e1d08afbb842f4e926dfb5a6430d09ec - 60 MB - (Sept 7 2025)
Current size as of f101c6e92af76914c6be3ef9b71b11081d9a3623- 62 MB - (Nov 13 2025)
Action items
- [ ]
-30 MBRemove unusedfastutilcollection implementations- ~~Can create a
shadowJaroutput filter for this~~ Actually no we can't - packaging only a select few classes from transitive dependencies is broken inshadowJar
- ~~Can create a
- [x] OpenRewrite options:
- [x]
-10 MBRemove it + transitive dependencies- Need an alternative for parsing Java source
- We could possibly make our own with the
javacAST similiar to how OpenRewrite does things, but more lean (DONE: SourceSolver) - ~~Go back to using JavaParser~~ (~2 MB)
- ~~Not ideal since we would lose the partial AST read support we get with OpenRewrite~~
- We could possibly make our own with the
- Need an alternative for parsing Java source
- [x]
-7 MBRemove unused transitive dependencies
- [x]
- [ ]
-9 MBRemove R8 in favor of dex - [ ]
-1 MBRemove JPhantom in favor of Reconstruct - [x]
-4 MBRemove Jackson dependency and storeAndroidResdata in JSON instead of XML- Will want to keep a tool in the Recaf repo to produce the JSON from the XML since the XML comes from the Android SDK releases. We can keep Jackson on the runtime path for this case, but not as a implementation/api dependency.
- [ ] ~~
-4 MBStrip debug info from dependencies (after the above steps)~~- Not worth it because it makes bugs harder to diagnose if there is a crash/exception in the dependency code
Summary
Assuming all action items are taken (and best alternatives for multiple choice cases)
-53 MBin potential removed data leading to a23 MBfat-jar
For fastutil, these are the classes we and transitive dependencies import.
it.unimi.dsi.fastutil.Hash.Strategy;
it.unimi.dsi.fastutil.bytes.ByteIterator;
it.unimi.dsi.fastutil.chars.Char2IntArrayMap;
it.unimi.dsi.fastutil.chars.Char2IntMap;
it.unimi.dsi.fastutil.chars.Char2ObjectArrayMap;
it.unimi.dsi.fastutil.chars.Char2ObjectMap;
it.unimi.dsi.fastutil.chars.CharArraySet;
it.unimi.dsi.fastutil.chars.CharSet;
it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2IntMap;
it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2IntSortedMap;
it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
it.unimi.dsi.fastutil.ints.Int2ObjectMap;
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceRBTreeMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMaps;
it.unimi.dsi.fastutil.ints.IntArrayList;
it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
it.unimi.dsi.fastutil.ints.IntList;
it.unimi.dsi.fastutil.ints.IntOpenHashSet;
it.unimi.dsi.fastutil.ints.IntSet;
it.unimi.dsi.fastutil.ints.IntSortedSet;
it.unimi.dsi.fastutil.longs.Long2ReferenceMap;
it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap;
it.unimi.dsi.fastutil.objects.Object2BooleanMap.Entry;
it.unimi.dsi.fastutil.objects.Object2BooleanMap;
it.unimi.dsi.fastutil.objects.Object2CharArrayMap;
it.unimi.dsi.fastutil.objects.Object2CharMap;
it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
it.unimi.dsi.fastutil.objects.Object2IntMap;
it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
it.unimi.dsi.fastutil.objects.Object2LongMap;
it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap;
it.unimi.dsi.fastutil.objects.Object2ObjectMap;
it.unimi.dsi.fastutil.objects.Object2ObjectRBTreeMap;
it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap.FastSortedEntrySet;
it.unimi.dsi.fastutil.objects.Object2ReferenceLinkedOpenHashMap;
it.unimi.dsi.fastutil.objects.ObjectIterator;
it.unimi.dsi.fastutil.objects.Reference2BooleanMap.Entry;
it.unimi.dsi.fastutil.objects.Reference2BooleanMap;
it.unimi.dsi.fastutil.objects.Reference2BooleanMaps;
it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap;
it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
it.unimi.dsi.fastutil.objects.Reference2IntMap.Entry;
it.unimi.dsi.fastutil.objects.Reference2IntMap;
it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
Can probably do some basic analysis and see all the classes we need to support these uses and then toss everything else.