The devs for Java Edition really have mods in mind nowadays.
- They left in the code debug features that they used to strip out.
- They left in the code their testing infrastructure that they used to strip out as well.
- They started making everything namespaced to differentiate contents between mods (like in this week's snapshot they made gamerules namespaced with the "minecraft:" prefix like items and blocks and whatnot)
- They are adding a lot more "building blocks" type features that both allow new /easier things in datapacks, and in mods as well.
Method patching with Mixins is less needed now because the game's internal APIs are more versatile than ever.
That's definitely true, and I think that's a testament to Minecraft / Java's strong OO design—it dovetails very nicely with the Open/Close principle. However my view is that for a mod to be a mod, there's always going to be stuff that you can't/shouldn't implement just with datapacks—whether that's complex rendering features, new entity logic, or whatever. The Mixin processor makes it really easy to build these kinds of features in a very compatible way
These tools sound very powerful, could they find use for other Java codebases?
I don't know where you'd use it besides modding, but it is a general-purpose framework: https://github.com/SpongePowered/Mixin
Other codebases don't tend to need those tools, because they already use frameworks like Spring or Micronaut which have such features built-in. Usually without bytecode rewriting and with more concern given to API definition.
For example, in Micronaut (which is what I'm more familiar with) you can use @Replace or a BeanCreatedListener to swap out objects at injection time with compatible objects you provide. If a use-site injects Collection<SomeInterface> you can just implement that interface yourself, annotate your class with @Singleton or @Prototype and now your object will appear in those collections. You can use @Order to control the ordering of that collection too to ensure your code runs before the other implementations. And so on - there's lots of ways to write code that modifies the execution of other code, whilst still being understandable and debuggable.
You still need quite a lot of mixins / modified code to actually do useful things. Mojang isn't always making things unnecessarily extensible, just extensible enough for them to keep updating the game.
They've also been working with a lot of modders on the rendering engine over the past year or two.