class Concrete1Sub(val underlying Concrete1) extends Concrete1 {
export underlying.{concrete1Method1, ...}
override def doStuff: Result = // some new code
}
For the rest I don’t really get what you are trying to do, so I’m afraid I cannot help
If you really need to override that specific method there’s not much else that you can do. Besides maybe hope that someone wrote some kind of “automatic proxy” library, but that will involve macros. Or use dynamic proxy classes, but that involves Java reflection, and only seems to work for interfaces… You even got lucky that those classes are not defined as final, since you have no control over those classes or objects.
Do concrete1Method1, concrete1Method2, etc, depend on doStuff? If so, I don’t see any great solutions, I’m afraid.
(My usual response to this sort of “I need to add new behavior but don’t control the class” is to use a type class, but if you don’t control the call sites that use the underlying method that probably won’t work.)
Some of the subclasses do depend on it. What is the suggestion in case there is no dependency?
type class is not an option I don’t control who builds the classes and I don’t control the end consumers, I just have a small scope where the instance is passed down along with other dependencies.
case class Instances(...,c1: Concrete1, ...)
def someWiring: Instances = ???
def modify(f: Instances): Instances = // I can intercept and change here
def logic(i: Instances) = ???
logic(
modify(someWiring)
)
The job there is to define proxies to incrementally deserialised Scala objects; additional methods and state are added into the proxy, with delegation of inherited traits to the deserialised object.
ByteBuddy will let you override specific methods and do a custom implementation, with or without forwarding to what plays the role of super. You can also use it to just reimplement your own subclass at runtime and instantiate that - so no proxies at all; that might work if you can supply the instances, even though the traits and classes are third party.
EDIT: for the sake of completeness, it is possible to use ByteBuddy to patch existing compiled classes, but to do that requires tapping into the Java agent mechanism. I’ve done this myself in extremis, but don’t recommend it.
Ok but personally I think I’d still prefer macros over runtime class instrumentation
But it does seem like it could solve the problem here. IIUC you can use it as a more powerful version of the Java dynamic proxy mechanism.
Yeah, I was thinking type classes. But I agree that, from the sound of things, that’s not an option. So yeah, I’m not seeing any good options, just the stuff that’s been explored above.