title: Error while redefining a method with ByteBuddy: "class redefinition failed: attempted to add a method"
body: <p>I'm learning Byte Buddy and I'm trying to do the following:</p>
  
  <ul>
  <li>create a subclass from a given class or interface</li>
  <li>then replace a method in the subclass</li>
  </ul>
  
  <p>Note that the subclass is 'loaded' in a <code>ClassLoader</code> <em>before</em> one of its method (<code>sayHello</code>) is redefined. It fails with the following error message:</p>
  
  <pre><code>java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method
  at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)
  at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170)
  at net.bytebuddy.dynamic.loading.ClassReloadingStrategy$Strategy$1.apply(ClassReloadingStrategy.java:293)
  at net.bytebuddy.dynamic.loading.ClassReloadingStrategy.load(ClassReloadingStrategy.java:173)
  ...
  </code></pre>
  
  <p>Below is the code for a set of JUnit tests. The first test, <code>shouldReplaceMethodFromClass</code>, passes as the <code>Bar</code> class is not subclassed before redefining its method. The two other tests fail when the given <code>Bar</code> class or <code>Foo</code> interface is subclassed.</p>
  
  <p>I read that I should delegate the new method in a separate class, which is what I do using the <code>CustomInterceptor</code> class, and I also installed the ByteBuddy agent at the test startup and used to load the subclass, but even with that, I'm still missing something, and I can't see what :(</p>
  
  <p>Anyone has an idea ?</p>
  
  <pre><code>public class ByteBuddyReplaceMethodInClassTest {
  
    private File classDir;
  
    private ByteBuddy bytebuddy;
  
    @BeforeClass
    public static void setupByteBuddyAgent() {
      ByteBuddyAgent.install();
    }
  
    @Before
    public void setupTest() throws IOException {
      this.classDir = Files.createTempDirectory("test").toFile();
      this.bytebuddy = new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE);
    }
  
    @Test
    public void shouldReplaceMethodFromClass()
        throws InstantiationException, IllegalAccessException, Exception {
      // given
      final Class&lt;? extends Bar&gt; modifiedClass = replaceMethodInClass(Bar.class,
          ClassFileLocator.ForClassLoader.of(Bar.class.getClassLoader()));
      // when
      final String hello = modifiedClass.newInstance().sayHello();
      // then
      assertThat(hello).isEqualTo("Hello!");
    }
  
    @Test
    public void shouldReplaceMethodFromSubclass()
        throws InstantiationException, IllegalAccessException, Exception {
      // given
      final Class&lt;? extends Bar&gt; modifiedClass = replaceMethodInClass(createSubclass(Bar.class),
          new ClassFileLocator.ForFolder(this.classDir));
      // when
      final String hello = modifiedClass.newInstance().sayHello();
      // then
      assertThat(hello).isEqualTo("Hello!");
    }
  
    @Test
    public void shouldReplaceMethodFromInterface()
        throws InstantiationException, IllegalAccessException, Exception {
      // given
      final Class&lt;? extends Foo&gt; modifiedClass = replaceMethodInClass(createSubclass(Foo.class),
          new ClassFileLocator.ForFolder(this.classDir));
      // when
      final String hello = modifiedClass.newInstance().sayHello();
      // then
      assertThat(hello).isEqualTo("Hello!");
    }
  
  
    @SuppressWarnings("unchecked")
    private &lt;T&gt; Class&lt;T&gt; createSubclass(final Class&lt;T&gt; baseClass) {
      final Builder&lt;T&gt; subclass =
          this.bytebuddy.subclass(baseClass);
      final Loaded&lt;T&gt; loaded =
          subclass.make().load(ByteBuddyReplaceMethodInClassTest.class.getClassLoader(),
              ClassReloadingStrategy.fromInstalledAgent());
      try {
        loaded.saveIn(this.classDir);
        return (Class&lt;T&gt;) loaded.getLoaded();
      } catch (IOException e) {
        throw new RuntimeException("Failed to save subclass in a temporary directory", e);
      }
    }
  
    private &lt;T&gt; Class&lt;? extends T&gt; replaceMethodInClass(final Class&lt;T&gt; subclass,
        final ClassFileLocator classFileLocator) throws IOException {
      final Builder&lt;? extends T&gt; rebasedClassBuilder =
          this.bytebuddy.redefine(subclass, classFileLocator);
      return rebasedClassBuilder.method(ElementMatchers.named("sayHello"))
          .intercept(MethodDelegation.to(CustomInterceptor.class)).make()
          .load(ByteBuddyReplaceMethodInClassTest.class.getClassLoader(),
              ClassReloadingStrategy.fromInstalledAgent())
          .getLoaded();
    }
  
    static class CustomInterceptor {
      public static String intercept() {
        return "Hello!";
      }
    }
  
  
  }
  </code></pre>
  
  <p>The <code>Foo</code> interface and <code>Bar</code> class are:</p>
  
  <pre><code>public interface Foo {
  
      public String sayHello();
  
  }
  </code></pre>
  
  <p>and </p>
  
  <pre><code>public class Bar {
  
      public String sayHello() throws Exception {
        return null;
      }
  
  }
  </code></pre>