0

Based on the idea of Can I redefine private methods using Byte Buddy?, I would like to redefine a private method from a parent class. Is that possible? Or it's like the chicken and egg problem ?

Thanks!

Community
  • 1
  • 1
Jordi Llach
  • 93
  • 1
  • 5
  • It’s not clear what you are asking. A `private` method is only relevant to its declaring class, which is the class you have to redefine. Whether this class is a superclass of another class, is irrelevant. – Holger Feb 17 '17 at 16:59
  • Because A's private method in its turn call other package protected and private methods which I do not want to replace or copy I need to redefine A's private method in B(a subclass) – Jordi Llach Feb 17 '17 at 17:16
  • There is no such method in `B`. A `private` method of `A` exists only in `A`. The only possibility to solve your task would be to replace `A`’s `private` method with a method that does a `this instanceof B` check and delegates to the old code, if the check evaluate to `false`. I don’t know whether ByteBuddy supports this kind of Instrumentation, but it looks like a questionable design anyway. – Holger Feb 17 '17 at 17:31
  • Whether this question makes sense or not ByteBuddy fails with a java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields) – Jordi Llach Feb 17 '17 at 18:02
  • Perhaps it helps to show what you have tried… – Holger Feb 17 '17 at 18:20

1 Answers1

1

Private methods are not dispatched virtually, therefore, you cannot change the dispatch of the private method within the subclass. The only way to do this, would be to hardcode a conditional dispatch into the private method directly.

You can do so, by using Byte Buddy's Advice class in combination with a Java agent. The Java agent would look like the following:

new AgentBuilder.Default()
  .disableClassFormatChanges()
  .with(RedefinitionStrategy.REDEFINITION)
  .type(is(ClassWithPrivateMethod.class))
  .transform((builder, type, cl, module) -> {
     return builder.visitor(Advice.to(MyAdvice.class)
                                  .on(named("privateMethod")));
   }).install(inst);

where the code of MyAdvice is inlined in the befinning of the method named privateMethod. The conditional dispatch would look like the following:

class Adv {
  @OnMethodEnter(skipOn = OnNonDefaultValue.class)
  static boolean intercept(@This ClassWithPrivateMethod self) {
    if (self instanceof ParentClass) {
      // Your code
      return true;
    } else {
      return false;
    }
  }
}

By returning true and by using the skip coniditon, you only execute the actual code if false is returned.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192