byte-buddy
Runtime code generation for the Java virtual machine.
Byte Buddy - runtime code generation for the Java virtual machine
Suppose I have a method m
:
public void m() {
String foo = "foo";
int bar = 0;
doSomething(foo, bar);
}
I want to use ByteBuddy to instrument the code so that when calling doSomething
in m
, it will automatically put the value of foo
and bar
into a HashMap
, pretty much something looks like:
public void m() {
String foo = "foo";
int bar = 0;
context.put("foo", foo); // new code injected
context.put("bar", bar); // new code injected
doSomething(foo, bar);
}
Is there anyway to do this instrumentation via ByteBuddy?
Source: (StackOverflow)
I am using ByteBuddy to create a class at runtime with dynamically generated byte code. The generated class does what it is intended to do, but I want to manually inspect the generated byte code, to ensure it is correct.
For example
Class<?> dynamicType = new ByteBuddy()
.subclass(MyAbstractClass.class)
.method(named("mymethod"))
.intercept(new MyImplementation(args))
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
where MyImplementation chains multiple StackManipulation commands together to create the dynamically generated code.
Can I write the generated class out to a file, (so I can manually inspect with a IDE), or otherwise print out the bytecode for the generated class?
Source: (StackOverflow)
We have a large class (100s of methods) which has an interface annotated with lazy loading guidelines. When initially loading this object and sending it to the client we do a limited load of the most frequently used and recent data. We are currently using java Proxying to sniff on every invocation. On every invocation we are checking "Do we have the data? If there is a date param, have we loaded data for that date?" If the answer is no to either of those questions we go back to the server and load the full object.
This works, however, the java reflection, proxying, and the extra overhead on calls like basic getters (getId()
for example) plays havoc on the performance of some of our code.
I want to start using byte buddy to hopefully decrease the invocation costs, especially on the simple fields that are always loaded.
What is the best way to approach this?
Also, because this object is being serialized (Java serialization, The server makes these objects and hands them off to the client), what is the right way to make sure these dynamically created classes can be passed from server to client across the wire?
Source: (StackOverflow)
I begin with byte-buddy the very impressive byte-code manipulation library. It works fine but I have a problem with subclassing an abstract, parameterized class:
public interface Task<DTO extends IDatabaseObject> {
void execute(DTO input);
Class<DTO> getDataObjectClass();
}
With this being the abstract class :
public abstract class AbstractTask<T extends IDatabaseObject> implements Task<T> {
protected Class<T> dataObjectClass = /* Call to an external method which retrieves the class from T */;
@Override
public Class<T> getDataObjectClass() {
return dataObjectClass;
}
}
I want to create a concrete class extending
public abstract class AbstractTask<T extends IDatabaseObject> implements Task<T> {
protected String SUCCESS_MESSAGE_PREFIX = "task.mess.";
protected Class<T> dataObjectClass;// = Introspector.getParameterizedTypeClass(this, AbstractTask.class, 0);
@Override
public Class<T> getDataObjectClass() {
return dataObjectClass;
}
@Override
public String getSuccessMessage(IDatabaseObject t) {
final String messageKey = SUCCESS_MESSAGE_PREFIX + this.getClass().getSimpleName();
final MessagesFactory messagesFactory = MessagesFactory.getInstance();
return messagesFactory.isPresent(messageKey) ? messagesFactory.get(messageKey) : "";
}
}
I want to create a concrete class of AbstractTask
, to fullfil the following assertion:
createConcreteImplementation(Person.class).getDataObjectClass() == Person.class
where the createConcreteImplementation
method creates an subclass via Byte Buddy. Even if this is not possible, I welcom suggestions for alternative ways or approximative this behavior.
Source: (StackOverflow)
I use Byte Buddy (v0.5.2) to dynamically create a "subclass" of an interface (actually, I want to create a class that implements that interface). All methods invoked on an instance of this class should be redirected to another (interceptor) class.
I used the following code (with "TestInterface" being an interface that declares exactly one method "sayHello"):
final Interceptor interceptor = new Interceptor();
Class<?> clazz = new ByteBuddy()
.subclass(TestInterface.class)
.method(any()).intercept(MethodDelegation.to(interceptor))
.make()
.load(TestInterface.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
TestInterface instance = (TestInterface) clazz.newInstance();
instance.sayHello();
The interceptor class looks like this:
public class Interceptor {
public Object intercept(@Origin MethodHandle method, @AllArguments Object[] args) throws Throwable {
...
}
}
However, when I try to call the "sayHello" method (last line of my code example), I get an "IncompatibleClassChangeError". The stack trace is as follows:
Exception in thread "main" java.lang.IllegalAccessError: no such method: byteuddytest.TestInterface.sayHello()void/invokeVirtual
at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:448)
at bytebuddytest.TestInterface$ByteBuddy$0E9xusGs.sayHello(Unknown Source)
at bytebuddytest.Main.main(Main.java:32)
Caused by: java.lang.IncompatibleClassChangeError: Found interface bytebuddytest.TestInterface, but class was expected
at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:965)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990)
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1387)
at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1732)
at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:442)
... 2 more
The problem seems to be related to the use of the "MethodHandle" parameter in my interceptor method. When I change the type to "Method", everything works fine. But according to the docs, "MethodHandle" should be preferred to "Method" because of performance reasons.
Is the error caused by a bug in Byte Buddy, or should I actually use a "Method" parameter in this case?
Source: (StackOverflow)
I am trying to convert Cglib proxy to ByteBuddy. Cglib has net.sf.cglib.proxy.Proxy interface to intercept all method calls. I check the documentation of ByteBuddy but couldnt find such an example. Without such interface for every object that i instantiate with ByteBuddy i am repeating same thing again and agin. Is there a better way to do this with ByteBuddy?
Here is my example code snippet:
Service:
public class MyService {
public void sayFoo() {
System.out.println("foo");
}
public void sayBar() {
System.out.println("bar");
}
}
Interceptor:
public class MyServiceInterceptor {
public void sayFoo(@SuperCall Callable<Void> zuper) {
try {
zuper.call();
} catch (Exception e) {
e.printStackTrace();
}
}
public void sayBar(@SuperCall Callable<Void> zuper) {
try {
zuper.call();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Test:
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.dynamic.ClassLoadingStrategy;
import net.bytebuddy.instrumentation.MethodDelegation;
import net.bytebuddy.instrumentation.method.matcher.MethodMatchers;
public class Main {
public static void main(String[] args) throws Exception {
ByteBuddy buddy = new ByteBuddy(ClassFileVersion.forCurrentJavaVersion());
Class<? extends MyService> serviceClass =
buddy.subclass(MyService.class)
.method(MethodMatchers.named("sayFoo").or(MethodMatchers.named("sayBar")))
.intercept(MethodDelegation.to(new MyServiceInterceptor()))
.make()
.load(Main.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
MyService service = serviceClass.newInstance();
service.sayFoo();
service.sayBar();
}
}
Source: (StackOverflow)
I am trying to create a "custom" setter method for a field with byte buddy.
Buddy's own mechanism allows for standard setter/getter methods to be implemented very easily, however, I am looking for an elegant way to extend the setter with some additional logic.
To simplify the example, let's assume we have a class A, which has a method setChanged(String).
Goal is to make a sub-class of A, add a field with corresponding access methods.
The catch is, that I want to call setChanged("fieldName") from each added setter method.
public void setName(String name)
{
setChanged("name");
this.name = name;
}
For a "normal" setter method, byte byddy implementation would be:
new ByteBuddy()
.subclass(A.class)
.name("B")
.defineField("name", Integer.TYPE, Visibility.PUBLIC)
// args is a ArrayList<Class<?>>
.defineMethod(getSetterName(name), Void.TYPE, args, Visibility.PUBLIC)
.intercept( FieldAccessor.ofField(name) )
Bytecode I am after looks like this:
L0
ALOAD 0 // Loads the this reference onto the operand stack
ILOAD 1 // Loads the integer value of the local variable 1 (first method arg)
PUTFIELD package/B.name : I // stores the value to the field
L1
ALOAD 0
LDC "name"
INVOKEVIRTUAL package/A.setChanged (Ljava/lang/String;)V
RETURN
My question is: is there a way to re-use FieldAccessor in this context?
Source: (StackOverflow)
Is it possible to use Byte Buddy to redefine a private method of a class? It seems that the entry point into using Byte Buddy is always sub-classing an existing class. When doing this, it is obviously not possible to redefine a private method of the parent class (at least not in a way that the redefined method is used in the parent class).
Consider the following example:
public class Foo {
public void sayHello() {
System.out.println(getHello());
}
private String getHello() {
return "Hello World!";
}
}
Foo foo = new ByteBuddy()
.subclass(Foo.class)
.method(named("getHello")).intercept(FixedValue.value("Byte Buddy!"))
.make()
.load(Main.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded()
.newInstance();
foo.sayHello();
The output will be "Hello World!". Is there any chance to get "Byte Buddy!" as output?
Source: (StackOverflow)
I have a public abstract class java.nio.ByteBuffer
instance which is actually an instance of private class java.nio.HeapByteBuffer
and I need to make a proxy object which would call some invocation method handler to check access permissions and then call the invoked method on the actual instance.
The problem is that the java.nio.ByteBuffer
class has only private constructors and also has some final methods, thus I can not create proxy instances with javassist.util.proxy.ProxyFactory
class.
So, how can I make a proxy object to control the invocation of a java.nio.ByteBuffer
instance including those final methods invocation?
Source: (StackOverflow)
I have a bunch of WebServices running on plain JDK and I need to intercept all public methods in order to do something. Some methods are using @WebParam annotation. Subclassing the WebService with ByteBuddy drops the @WebParam annotation from the overriding method and the service doesn't work anymore as expected.
Here's a sample signature
public Something fetch( @WebParam( name="Query" ) QueryCriteria query )
And here's how I'm using ByteBuddy
new ByteBuddy( )
.subclass( implementationClass )
.method( isPublic( ).and( isDeclaredBy( implementationClass ) ) )
.intercept(
MethodDelegation.to( new WebServiceInterceptor( ) )
.andThen( SuperMethodCall.INSTANCE ) )
.annotateType( implementationClass.getAnnotations( ) )
.make( )
I know there's a way to annotate parameters, but it requires special knowledge about the method parameters (because only some params are annotated). What I'd would like to do is just to ask ByteBuddy to annotate my class exactly the same way as superclass including all parameters of all overridden methods.
subclass( implementationClass )
.annotateType( LIKE_SUPERCLASS )
.method( )
.intercept( ... )
.annotateMethod( LIKE_SUPER_INCLUDING_PARAMS )
Any ideas?
BR, Paci
Source: (StackOverflow)
In the following code snippet I'm calling the method doStuff
once on an instance of Subclass
. However it is intercepted twice.
Note that doStuff
was defined in the parent class SuperClass
. If doStuff
was defined in SubClass
the interception logic would work as expected: only one interception.
Am I using Byte Buddy incorrectly?
package com.test;
import static net.bytebuddy.matcher.ElementMatchers.any;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import java.util.concurrent.Callable;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType.Builder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import org.junit.Test;
public class ReproBugTest {
@Test
public void reproBug() {
new AgentBuilder.Default().type(nameStartsWith("com.test"))
.transform(new AgentBuilder.Transformer() {
@Override
public Builder<?> transform(
Builder<?> builder,
TypeDescription td) {
return builder.method(any())
.intercept(
MethodDelegation.to(MethodInterceptor.class));
}
})
.installOn(
ByteBuddyAgent.installOnOpenJDK());
SubClass subClass = new SubClass();
subClass.doStuff();
}
}
class SuperClass {
public void doStuff() {
System.out.println("Doing stuff...");
}
}
class SubClass extends SuperClass {
}
class MethodInterceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper)
throws Exception {
// Intercepted twice, bug?
System.out.println("Intercepted");
Object returnValue = zuper.call();
return returnValue;
}
}
Source: (StackOverflow)
I am trying to redefine 2 methods using ByteBuddy, like so:
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
ClassLoadingStrategy.Default classLoadingStrategy = ClassLoadingStrategy.Default.INJECTION;
new ByteBuddy().redefine(CommandBase.class).method(returns(Item.class)).intercept(MethodDelegation.to(CppItemInterceptor.class)).make().load(classLoader, classLoadingStrategy);
new ByteBuddy().redefine(CommandBase.class).method(returns(Block.class)).intercept(MethodDelegation.to(CppBlockInterceptor.class)).make().load(classLoader, classLoadingStrategy);
try {
System.out.println(CppBlockInterceptor.getBlockByText(null, "1").getLocalizedName());
System.out.println(CommandBase.getBlockByText(null, "1").getLocalizedName());
} catch (Exception e) {
e.printStackTrace();
}
The direct call to CppBlockInterceptor produces the intended output, but the call to the method that was supposed to be replaced still uses the old behavior. Is there any reason for this?
Source: (StackOverflow)
I am working on an existing application which has extensive use of old-style jdbc SQL operations, i.e., SELECT, UPDATE, INSERT etc.
The application has a class managing data-fields, with a dirty flag to indicate that something has changed and needs to be committed to the database.
When the INSERT or UPDATE statement has completed without exception, and the commit has succeeded, the 'dirty flag' needs to be turned off.
For reasons of the current design and program flow, that is not completely trivial, so, I thought it could be possible to implement a proxy of the Connection used to write the changes to the database, override the commit method and ensure that when the commit is successful, the flag is set to off.
In other words, I want to implement, in effect, a java-based database commit "callback", so that I can subscribe to the commits of a particular connection, and act upon these events.
I was looking into byte-buddy as a possible means of achieving this, but in all the examples I've seen so far, one has control over the instantiation of the class being modified.
That is not the case in my situation. An instance of a type implementing java.sql.Connection is being created by the jdbc driver, often wrapped by another class used in a database connection pool (such as TomCat connection pool).
How can I intercept the instantiation of these objects, and override, dynamically, the commit and rollback methods?
Can I do it with byte-buddy?
Is there a better option?
Source: (StackOverflow)
This question is related to my previous quesiton here: How to create a default constructor with Byte Buddy
I am creating a subclass which first sets up some context before delegatig method invocation to some instance. This already works quite well with one issue remaining.
I get the following error when loading my dynamically created subclass.
java.lang.VerifyError: Bad access to protected data in invokevirtual
Exception Details:
Location:
com/frequentis/ps/service/test/saga/ProxyTestSaga$ByteBuddy$Rm8DV3Lj.setTimeoutManager(Lcom/codebullets/sagalib/timeout/TimeoutManager;)V @3: invokevirtual
Reason:
Type 'com/frequentis/ps/service/test/saga/ProxyTestSaga' (current frame, stack[0]) is not assignable to 'com/frequentis/ps/service/test/saga/ProxyTestSaga$ByteBuddy$Rm8DV3Lj'
Current Frame:
bci: @3
flags: { }
locals: { 'com/frequentis/ps/service/test/saga/ProxyTestSaga$ByteBuddy$Rm8DV3Lj', 'com/codebullets/sagalib/timeout/TimeoutManager' }
stack: { 'com/frequentis/ps/service/test/saga/ProxyTestSaga' }
Bytecode:
0x0000000: b200 0cb6 0010 57b1
at java.lang.Class.getDeclaredFields0(Native Method)
at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
at java.lang.Class.getDeclaredField(Class.java:2068)
at net.bytebuddy.implementation.LoadedTypeInitializer$ForStaticField.onLoad(LoadedTypeInitializer.java:124)
at net.bytebuddy.implementation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:200)
at net.bytebuddy.implementation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:200)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.initialize(DynamicType.java:3497)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:3485)
at com.frequentis.ps.service.test.saga.DynamicSagaTypeBuilder.buildAndLoad(DynamicSagaTypeBuilder.java:65)
at com.frequentis.ps.service.test.saga.MoreAbstractSpaceSagaUnitTest.generateProxyClassForSagaUnderTest(MoreAbstractSpaceSagaUnitTest.java:274)
at com.frequentis.ps.service.test.saga.AbstractSpaceSagaUnitTest.enhance(AbstractSpaceSagaUnitTest.java:105)
at com.frequentis.ps.service.test.saga.ProxyTestSagaTest.before(ProxyTestSagaTest.java:27)
This is currently my byte buddy setup, which works for almost all cases except for the "setTimeoutManager
" and "setState
" methods which result in the shown error.
// called within the unit test base class (as shown in the call stack above)
builder = new ByteBuddy()
.subclass(sagaUnderTestClass, ConstructorStrategy.Default.IMITATE_SUPER_TYPE_PUBLIC);
// define default ctor if necessary that passes "null" values to the super ctor
builder.method(isAnnotatedWith(StartsSaga.class).or(isAnnotatedWith(EventHandler.class)))
.intercept(MethodDelegation.to(new ForwardingContextSetupInterceptor<(sagaUnderTest, contextSetter))
.appendParameterBinder(Pipe.Binder.install(Forwarder.class)))
.method(isPublic()
.and(isDeclaredBy(sagaUnderTest.getClass()).or(isDeclaredBy(AbstractSaga.class)
.and(not(isAnnotatedWith(StartsSaga.class))).and(not(isAnnotatedWith(EventHandler.class))))
.intercept(MethodDelegation.to(sagaUnderTest))))
Do I need a different setup for setters?
or is it caused by the abstract class?
I dont really understand why it says bad access to protected data, does it mean the private field?
My type hierachy looks like this. The top most base class which declares the setters:
public abstract class AbstractSaga<SAGA_STATE extends SagaState> implements Saga<SAGA_STATE>, NeedTimeouts, NeedContext {
private SAGA_STATE state;
private boolean completed;
private TimeoutManager timeoutManager;
private ExecutionContext context;
protected AbstractSaga() {
completed = false;
}
// i have omitted some method for clarity
protected ExecutionContext context() {
return context;
}
@Override
public SAGA_STATE state() {
return state;
}
@Override
public void setState(final SAGA_STATE state) {
this.state = state;
}
@Override
public boolean isFinished() {
return completed;
}
protected void setFinished() {
completed = true;
}
@Override
public void setTimeoutManager(final TimeoutManager timeoutManager) {
this.timeoutManager = timeoutManager;
}
}
Extended by:
public abstract class AbstractSpaceSaga<SAGA_STATE extends SpaceSagaState, MESSAGE extends Message>
extends AbstractSaga<SAGA_STATE> {
}
And finally again extended by:
public class ProxyTestSaga
extends AbstractSpaceSaga<SpaceSagaState, TestRequest> {
@StartsSaga
public void handle(final TestRequest request) {
}
@EventHandler
public void handle(final TestEvent event) {
}
}
I hope the code is somehow understandable, I can add more info if required any time.
Source: (StackOverflow)
I have a simple entity User.
public class User {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And his corresponding DTO
public class UsuarioDTO {
String name;
String getName(){
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
I want to achieve something like I show below to avoid multiple classes of transformers.
@Dto(entity = "Usuario")
public class UsuarioDTO {
@BasicElement(name = "name")
String name;
String getName(){
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BasicElement {
String name();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Dto {
String entity() default "";
}
With this example classes I can do:
public class Transformer {
public static void main(String[] args) {
UserDTO usuarioDTO = new UserDTO("Gabriel");
Class<UserDTO> obj = UserDTO.class;
if (obj.isAnnotationPresent(Dto.class)) {
Dto annotation = obj.getAnnotation(Dto.class);
Class<?> clazz;
try {
clazz = Class.forName(annotation.entity());
Constructor<?> constructor = clazz.getConstructor();
Object instance = constructor.newInstance();
for (Field originField : UserDTO.class.getDeclaredFields()) {
originField.setAccessible(true);
if (originField.isAnnotationPresent(BasicElement.class)) {
BasicElement basicElement = originField.getAnnotation(BasicElement.class);
Field destinationField = instance.getClass().getDeclaredField(basicElement.name());
destinationField.setAccessible(true);
destinationField.set(instance, originField.get(usuarioDTO));
}
}
System.out.println(((User) instance).getName());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
But this would be to expensive because consumes the annotations in each transformation.
It's possible with Byte-buddy to read the annotations and create a class transformer whose decompiled code look like this:
public class TransformerImpl implements ITransformer{
public Object toEntity(Object dto){
User user = new User();
user.setName(dto.getName());
}
}
UPDATE:
@Rafael Winterhalter, something like this?
public class Transformer<D,E> {
List<Field> dtoFields = new ArrayList<Field>();
Constructor<D> dtoConstructor;
List<Field> entityFields = new ArrayList<Field>();
Constructor<E> entityConstructor;
public Transformer(Class<D> dtoClass){
try {
Dto annotation = dtoClass.getAnnotation(Dto.class);
Class<E> entityClass = (Class<E>) annotation.entity();
//entityConstructor = entityClass.getConstructor();
entityConstructor = entityClass.getDeclaredConstructor();
entityConstructor.setAccessible(true);
dtoConstructor = dtoClass.getConstructor();
dtoConstructor.setAccessible(true);
lookupFields(entityClass, dtoClass);
} catch (Exception e) {
e.printStackTrace();
}
}
private void lookupFields(Class<E> entityClass, Class<D> dtoClass) throws NoSuchFieldException {
for (Field dtoField : dtoClass.getDeclaredFields()) {
if (dtoField.isAnnotationPresent(BasicElement.class)) {
BasicElement basicElement = dtoField.getAnnotation(BasicElement.class);
String entityFieldName = (basicElement.name().equals("")) ? dtoField.getName() : basicElement.name();
Field entityField = entityClass.getDeclaredField(entityFieldName);
dtoField.setAccessible(true);
entityField.setAccessible(true);
dtoFields.add(dtoField);
entityFields.add(entityField);
}
}
}
public E toEntity(D dto) throws ReflectiveOperationException {
E entity = entityConstructor.newInstance();
for (int i = 0; i < entityFields.size(); i++){
Field destination = entityFields.get(i);
Field origin = dtoFields.get(i);
destination.set(entity, origin.get(dto));
}
return entity;
}
public D toDto(E entity) throws ReflectiveOperationException {
D dto = dtoConstructor.newInstance();
for (int i = 0; i < entityFields.size(); i++){
Field origin = entityFields.get(i);
Field destination = dtoFields.get(i);
destination.set(dto, origin.get(entity));
}
return dto;
}
}
Source: (StackOverflow)