Carsten Tolkmit
Carsten Tolkmit

Reputation: 148

ByteBuddy: How to do method delegation / forwarding to a volatile field

I have (pseudo code) something like this:

final Class<OUT> newClass = (Class<OUT>) new ByteBuddy()
.subclass(Object.class)
.name(newName)
.implement(SomeInterface.class, SomeOtherInterface.class)
.method(ElementMatchers.isMethod())                            
.intercept(
    ExceptionMethod.throwing(UnsupportedOperationException.class,
                            "calling this method is not supported"))
// in fact I am matching for more than a single method here
.method(ElementMatchers.named("getUuid"))
.intercept(
    MethodDelegation.toInstanceField(SomeOtherInterface.class, "delegate"))
.make()
.load(aBusinessEntityClass.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();

My current problem is: I need my delegate field to be volatile. How can I achieve that?

Upvotes: 2

Views: 2095

Answers (2)

Rafael Winterhalter
Rafael Winterhalter

Reputation: 44067

The toInstanceField API was retired with Byte Buddy 1.5.0 in favor of a new instrumentation API where you rather define the field explicitly:

new ByteBuddy()
  .defineField("delegate", SomeOtherInterface.class, VOLATILE)
  .method(ElementMatchers.named("getUuid"))
  .intercept(MethodDelegation.toField("delegate"));

This allows to do other things such as adding annotations etc.

This approach is now implemented for all Implementations. The new version was released today.

Upvotes: 4

Carsten Tolkmit
Carsten Tolkmit

Reputation: 148

Okay, found a solution that works for me, in case anyone is interested:

final Class<OUT> newClass = (Class<OUT>) new ByteBuddy()
.subclass(Object.class)
.name(newName)
.implement(SomeInterface.class, SomeOtherInterface.class)
.method(ElementMatchers.isMethod())                            
.intercept(
    ExceptionMethod.throwing(UnsupportedOperationException.class,
                        "calling this method is not supported"))
// in fact I am matching for more than a single method here
.method(ElementMatchers.named("getUuid"))
.intercept(
    MethodDelegation.toInstanceField(SomeOtherInterface.class, "delegate"))
// -- HERE THE FIELD IS MODIFIED AGAIN, IN THIS CASE AS  --
// -- PRIVATE & VOLATILE                                 --
.field(ElementMatchers.named("delegate"))                       
.transform(Transformer.ForField.withModifiers(FieldManifestation.VOLATILE, Visibility.PRIVATE))
.make()
.load(aBusinessEntityClass.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();

The solution was to modify the field afterwards with a call to field() with transform() and appropriate Transformer.ForField.withModifiers().

Hope to help everyone facing this issue.

Upvotes: 1

Related Questions