Add getters to ResConfig, compute qualifiers lazily and swap out equals and hashCode implementations#4132
Add getters to ResConfig, compute qualifiers lazily and swap out equals and hashCode implementations#4132X1nto wants to merge 3 commits into
Conversation
…h field-based implementations
|
This isn't necessary for the official Apktool. No one else has complained about it, and it just adds unnecessary complexity. |
|
Yes, the library is pushed to be used as-is. Otherwise, the source code is available to fork.
I have no problem with the getters, but the code duplication is ridiculous for no tangible benefit, just complexity. Pre-generating a qualifiers string once per config is really not a big deal. In any case, this isn't my decision, I'm just giving my two cents. |
|
I think its valid that we ship apktool-lib, it could act more library friendly. Looking at how its operated in past we basically generated qualifiers on the fly because thats all we needed them for. My concern is the large duplication of the qualifier checks as we previously relied on the writing of the qualifier to know if it was invalid or not. That computation split out now has to do some heavy lifting in semi-duplication of each qualifier check. The getters don't bother me as much, but maybe if the Java 14 records compile down to regular ole getters that might clean up our logic to be less verbose. I recently had to move to Java11 for Maven publishing, but still can produce a Java8 valid binary. I don't think its out of the realm to say we could move to Java14 for building if it still produces a Java8 compatible binary. |
|
Yes, I have no problem with adding the getters even if apktool itself doesn't use them. |
I understand your concern, but I genuinely couldn't think of a way to make isValid and qualifiers work with this lazy-compute approach. If you have a better suggestion, or if you simply prefer to keep old behavior and precompute this qualifier string, that's fine by me.
I made these changes to reduce the memory footprint taken by each ResConfig, as every string is an extra allocation. Again, if you're not comfortable with this, I can revert this change, I just want to understand the reason behind doing this the way you did it, since you guys have way more experience than me in this codebase.
While records could help with this, I don't think you can produce a Java 8 compatible library since records rely on java.lang.Record, which isn't available on older runtimes. More realistic alternatives to this are either Lombok or Kotlin, but both of them are huge dependencies that are out of the scope of this PR. |
|
Looks like you already committed getters to the main branch. I would've preferred if you waited for my reply so we could've sort this out together, instead of cherry-picking my changes. No offense to anyone, as I have no say in what and how goes to your repo, but I think it doesn't take much effort to at least give me a heads up. |
Do you have more details around your usecase? Trying to visualize what you are trying to do in your userland.
I'll await Igor's comments on this one. I don't have much comfort in speaking confidently in the allocation/perf area.
Yeah I guess both of those deps look bad. We ended up merging basic getters manually generated.
Yep looking back we should have added your "co-authored by" - sorry about that. |
One of our tools use
It's alright! My comment wasn't really about being included as a commit author :D |
|
The PR wasn't a replacement to your PR, nor a "cherry-picking". I simply exposed the fields, standard POJO style. Your PR is still being discussed. |
I'm aware of how string decoding works in APKTool, I didn't have enough time to properly benchmark and fix that. I also didn't get "fixated" on anything, I simply wanted to suggest a more-efficient approach for handling ResConfigs. The fact that I made this PR right now doesn't mean that I'm not looking forward to suggest other improvements. |
|
I see. Alright then, looking forward to it. |
Parsing out possible configurations outside of ResConfig's class currently requires calling
toQualifiers()and then manually filtering out configurations based on their string values. This approach becomes problematic when dealing with languages, because simply getting the language of a ResConfig isn't possible without reflection unless we iterate over all possible languages. So, this adds getters.The second thing this PR addresses is how qualifiers are used. Previously, qualifiers were computed whether or not they were needed by APKTool. As far as I'm aware, the only need of built qualifiers outside of
hashCode()andequals()(more on this later) is writing resources to files. Since some programs usingapktool-lib(including our internal tools at APKMirror) may not need to extract these resources to files, we might as well avoid extra string allocations unless explicitly needed by the library. As forequals()andhashCode(), I think using qualifiers were a wrong choice for this because qualifiers don't include all fields, such asmMinorVersion. While I doubt that 2 same resource configs with only minor versions differing will ever exist in the same APK, I still think it's better to cover all fields of the class. Plus, with qualifiers being lazily-calculated in this new approach, it doesn't make much sense to use them in these methods.I initially wanted to make this PR with the sole purpose of adding getters, however, seeing the opportunity, I took care of the other stuff. I may be wrong with my additions, so please, let me know if there's a reason why qualifiers should be used, or if you just prefer to make these commits into their own separate PRs.