Coder Social home page Coder Social logo

raphw / byte-buddy Goto Github PK

View Code? Open in Web Editor NEW
6.0K 6.0K 775.0 980.78 MB

Runtime code generation for the Java virtual machine.

Home Page: https://bytebuddy.net

License: Apache License 2.0

Java 99.90% C 0.04% Shell 0.03% Batchfile 0.03%
byte-code dynamic-proxy instrumentation java java-agent java-library java-virtual-machine

byte-buddy's Introduction

๐Ÿ‘‹ Hi there, I am a full-stack software consultant from Germany, living and working in Oslo, Norway. I am specialized on the Java platform but I do generally enjoy any kind of programming. I am fairly active in developing open source software and I believe in writing clean, modular code. I am regularly blogging about technology. I also enjoy speaking at conferences and user group meetings and was pronounced a Java One Rockstar. I am the author of Byte Buddy, a runtime code generator for the Java virtual machine and won a Duke's Choice award and a Groundbreaker award for my efforts. I also created documents4j, a document format converter for Java. For my contributions to the ecosystem, I was elected a Java Champion. Get in touch, if you want to talk with me about something that you think that I could help you with.

byte-buddy's People

Contributors

agoallikmaa avatar cemelo avatar codingfabian avatar dependabot[bot] avatar diabolusexmachina avatar don-vip avatar felixbarny avatar felixmarxibm avatar funky-eyes avatar godin avatar hunterwb avatar kalgon avatar likethesalad avatar ljnelson avatar marcono1234 avatar mches avatar mibac138 avatar orange-buffalo avatar pascalschumacher avatar perlun avatar raphw avatar richardstartin avatar ryszard-trojnacki avatar sanne avatar sbabcoc avatar skapral avatar sormuras avatar testn avatar xenoamess avatar yrodiere avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

byte-buddy's Issues

Enhance ConstructorStrategy.Default to support package private and private constructors

In playing with ByteBuddy on some things that currently use Cglib, I noticed that there's no way out of the box to have constructors created for a package private superclass/constructor. For even a basic package private type like class Foo{}, with ConstructorStrategy.Default.IMITATE_SUPER_TYPE a ByteBuddy generated subclass contains no constructors, which prevents me from using it via reflection. With ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR I get an IllegalArgumentException on the subclass call.

Can ConstructorStrategy.Default be enhanced to support package private and private classes/constructors? Is there a current workaround to get constructors imitating the super type generated for package private and private classes?

Auto-ignore methods that are not instrumented in rebasement

When rebasing a class, instrumenting methods might require knowledge og the name of another method's super method. As these methods might or might not be instrumented themselfs, it is required to rebase methods that are themselfs not explicitly implemented. These methods should however be implicitly ignored in a first pass through in order to avoid writing these unneccessary methods.

Potentially replace argument List with Collection, Iterable, or Set: ByteBuddy#makeInterface, possibly other methods

Why is there ByteBuddy#makeInterface(List) instead of either:

  1. ByteBuddy#makeInterface(Collection) if you want to allow more argument types
  2. ByteBuddy#makeInterface(Iterable) if you want to allow even more argument types, but not necessarily have a size() method to improve ByteBuddyCommons#join(...) performance
  3. ByteBuddy#makeInterface(Set) if you want to indicate that each super-interface Class should only be specified once

Is there a need to preserve the ordering of the input Class elements?

I have a Set<Class> that I'd like to pass in as an argument, but, with the existing makeInterface methods, I need to convert it to either an array, or a List, which seems unnecessary.

It's possible that List arguments of other methods could also be converted, but I haven't looked over the whole Byte Buddy API.

Better error messages

I have just started playing around with Buddy a couple of days ago.
My idea can roughly be described as dynamic beans generation: add field, getter, setter.

new ByteBuddy()
    .subclass(Object.class)
        .defineField("a", String.class, Visibility.PRIVATE)
            .defineMethod("getA", Integer.TYPE, new ArrayList<Class<?>>(), Visibility.PUBLIC)
                .intercept(FieldAccessor.ofField("a"))
            .defineMethod("setA", Void.TYPE, args, Visibility.PUBLIC)
                .intercept(FieldAccessor.ofField("a"))
    .make()
    .load(SilConfig.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
    .getLoaded();

Note that the field is defined as String, getter method as Integer.
This leads to:

Exception in thread "main" java.lang.IllegalStateException
    at net.bytebuddy.instrumentation.method.bytecode.stack.StackManipulation$Illegal.apply(StackManipulation.java:46)
    at net.bytebuddy.instrumentation.method.bytecode.stack.StackManipulation$Compound.apply(StackManipulation.java:194)
    at net.bytebuddy.instrumentation.method.bytecode.stack.StackManipulation$Compound.apply(StackManipulation.java:194)
    at net.bytebuddy.instrumentation.method.bytecode.stack.StackManipulation$Compound.apply(StackManipulation.java:194)
    at net.bytebuddy.instrumentation.FieldAccessor.apply(FieldAccessor.java:179)
    at net.bytebuddy.instrumentation.FieldAccessor.applyGetter(FieldAccessor.java:110)
    at net.bytebuddy.instrumentation.FieldAccessor$Appender.apply(FieldAccessor.java:790)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Entry$Simple.apply(TypeWriter.java:1062)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Engine$ForCreation.create(TypeWriter.java:695)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1150)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:219)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$AbstractDelegatingBuilder.make(DynamicType.java:1607)

Java version: 1.7.0_45
It took me a while to see what was wrong, due to the ambiguity of the exception thrown.

Interface Setter Methods Not Being Intercepted

While trying to workaround issue #10 I discovered that the following test cases results in only getter methods being intercepted.

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.NamingStrategy;
import net.bytebuddy.dynamic.ClassLoadingStrategy;
import net.bytebuddy.instrumentation.MethodDelegation;
import net.bytebuddy.instrumentation.method.bytecode.bind.annotation.AllArguments;
import net.bytebuddy.instrumentation.method.bytecode.bind.annotation.Origin;
import net.bytebuddy.instrumentation.method.bytecode.bind.annotation.RuntimeType;
import static net.bytebuddy.instrumentation.method.matcher.MethodMatchers.*;
import net.bytebuddy.utility.RandomString;
import org.testng.annotations.Test;

public class ServiceLocatorProxyNGTest {

    @Test
    public void testSomeMethod() throws InstantiationException, IllegalAccessException {
        Class<ProxyedInterface> type = ProxyedInterface.class;
        ClassLoader classLoader = getClass().getClassLoader();

        Class<? extends ProxyedInterface> proxyType = new ByteBuddy(ClassFileVersion.JAVA_V8)
                .withNamingStrategy(new ProxyNamingStrategy(type))
                .subclass(type)
                .method(isDeclaredBy(type))
                .intercept(MethodDelegation.to(new GeneralInterceptor(new ProxyedInterfaceDelegate(10L))))
                .make()
                .load(classLoader, ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();

        ProxyedInterface result = proxyType.newInstance();
        result.setObject(11l);
        Long f = result.getObject();

        System.out.println("");

    }

    public static interface ProxyedInterface {

        void setObject(Long value);

        Long getObject();

    }

    public static class ProxyedInterfaceDelegate implements ProxyedInterface {

        private Long value;

        public ProxyedInterfaceDelegate(Long value) {
            this.value = value;
        }


        @Override
        public void setObject(Long value) {
            this.value = value;
        }

        @Override
        public Long getObject() {
            return value;
        }

    }

    public class GeneralInterceptor {

        private final ProxyedInterface delegate;

        public GeneralInterceptor(ProxyedInterface delegate) {
            this.delegate = delegate;
        }

        @RuntimeType
        public Object intercept(@AllArguments Object[] allArguments, @Origin Method method) {
            try {
                System.out.println("Intercepted method: " + method.getName());
                return method.invoke(delegate, allArguments);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    public static class ProxyNamingStrategy implements NamingStrategy {

        private final Class<?> type;

        public ProxyNamingStrategy(Class<?> type) {
            this.type = type;
        }

        @Override
        public String name(UnnamedType unnamedType) {
            String packageName = type.getPackage().getName();
            String simpleName = type.getSimpleName();
            return String.format("test.%s_Proxy_%s", simpleName, RandomString.make());
        }

    }

}

Can't instantiate type when a parent method uses a non public type in signature

This is a followup of mockito issues mockito/mockito#233 and PR mockito/mockito#234

The fix 6f223d9 here don't handle compilation, so bytecode is can be generated, but cannot be instantiated (IllegalAccessError).

The issue is probably there MethodRegistry.Default.Compiled#getInstrumentedMethods does not check if methods are visible, like other components of 6f223d9.

I'm guessing that the implementation should be something like :

@Override
public MethodList getInstrumentedMethods() {
    return new MethodList.Explicit(new ArrayList<MethodDescription>(implementations.keySet())).filter(not(isTypeInitializer()).and(isVisibleTo(instrumentedType)));
}

Hotswapping classes throws an IllegalStateException

Using the code in the example:

ClassLoader classLoader = ClassLoader.getSystemClassLoader();
ClassLoadingStrategy classLoadingStrategy = ClassReloadingStrategy.fromInstalledAgent();
class Foo {
    String m() {
        return "foo";
    }
}
class Bar {
    String m() {
        return "bar";
    }
}
Foo foo = new Foo();
new ByteBuddy().redefine(Bar.class).name(Foo.class.getName()).make().load(Foo.class.getClassLoader(), classLoadingStrategy);
System.out.println(foo.m());

Prints out "bar" as expected but throws an IllegalStateException right after.

java.lang.IllegalStateException: ClassReader.accept() should be called with EXPAND_FRAMES flag
    at net.bytebuddy.jar.asm.commons.LocalVariablesSorter.visitFrame(Unknown Source) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.jar.asm.commons.RemappingMethodAdapter.visitFrame(Unknown Source) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.jar.asm.ClassReader.a(Unknown Source) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.jar.asm.ClassReader.b(Unknown Source) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.doCreate(TypeWriter.java:1351) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:1335) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:917) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.make(RedefinitionDynamicTypeBuilder.java:209) ~[byte-buddy-0.6.12.jar:?]

Create Interface (not class)

I have looked at a lot of ASM type libraries and was just starting on cglib when I ran into an issue with it and found your post about byte-buddy. Trying this out, I really like it, although its a bit of a learning curve to figure out model so I can do what I think is obvious - but has a different representation in bb.

One thing I am stuck on. I dont need this 100% but it would be very useful. Most ASM tools assume (many with comments saying so) that there is no use for creating interfaces, only classes.
I would like to be able to create interfaces, ideally root (not derived) interfaces.
With cglib that was in fact the first thing I tried and got to work (although I dont like that it derives from an internal interface, its not a top level one - but it is an interface)

I have tried about 20 ways to do to this with BB and scanned most of the source and and the web and cant find it. Two strategies that got close were

interface I {} ;
...
new ByteBuddy().subclass(I.class, no-constrors ).name(...)...

I got that to produce something that 'worked' but its a not an interface, its
class name extends Object implements I

I see in the code where its switching the subclass to Object ...

The other attempt is to use variations on this
new ByteBuddy()
.withModifiers(TypeManifestation.INTERFACE)
.subclass(Object.class,ConstructorStrategy.Default.NO_CONSTRUCTORS)
.name(name);

but that ends up crashing with null pointer exceptions in various places ...
the superclass isnt null but its contents are uninitialized.

Is this possible ? I cant find anywhere that constructs a Builder for either an iterface,
or (related probably) without a superclass.

The Annotation support looks like its close ...

I am curious if this is a fundamental difficulty with the JVM or ASM or if its simply something that noones ever asked for or thought of ..

I can live without it by making an abstract class but it seems a huge hole where the rest of the product has incredible depth.

-David

Obscure documentation

Hi Rafael,
i just noticed that you use quite an obscure example in the 3-1 = 2 comparison example in the main readme.
It is correct, but it evokes a wtf moment when you see that it substracts hash codes. Is that intended, or shall I send a PR to make that less magical?

Implement validator for class creation process

Currently, Byte Buddy does not validate if a user defines a class with illegal properties, e.g defines an abstract method on a non-abstract type, a default method on a Java 7 class etc.

Piping methods with void return type

I'm currently porting one of our libraries from CGLib to ByteBuddy and I've encounter a problem with @pipe. I've got a simple proxy that delegates all calls to the wrapped target object. Everything is OK until there is a method returning void on the target object.

My setup is like:

public class X {
    public static class WrappedObject {
        Object method1() {...}
        void method2() {...}
    }

    public static interface Forwarder<T, S> {
        T to(S target);
    }

    public static class Handler {
        protected final WrappedObject wrappedObject;

        public Handler(WrappedObject wrappedObject) {
            this.wrappedObject = wrappedObject;
        }

        @RuntimeType
        public Object delegate(@Pipe Forwarder<Object, WrappedObject> pipe) {
            return pipe.to(wrappedObject);
        }
    }

    public static void main(String... args) throws Exception {
        WrappedObject proxiedObject = new ByteBuddy()
          .subclass(WrappedObject.class)
          .method(any())
          .intercept(MethodDelegation.to(new Handler(new WrappedObject())).appendParameterBinder(Pipe.Binder.install(Forwarder.class)))
          .make()
          .load(X.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
          .getLoaded()
          .newInstance();
    }
}

The proxy cannot be created:

Exception in thread "main" java.lang.IllegalStateException: An illegal stack manipulation must not be applied
    at net.bytebuddy.instrumentation.method.bytecode.stack.StackManipulation$Illegal.apply(StackManipulation.java:46)
    at net.bytebuddy.instrumentation.method.bytecode.stack.StackManipulation$Compound.apply(StackManipulation.java:194)
    at net.bytebuddy.instrumentation.method.bytecode.bind.annotation.Pipe$Binder$Redirection$MethodCall$Appender.apply(Pipe.java:589)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Entry$Simple.apply(TypeWriter.java:1055)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Engine$ForCreation.create(TypeWriter.java:688)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1143)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:219)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$AbstractDelegatingBuilder.make(DynamicType.java:1611)
    at net.bytebuddy.instrumentation.method.bytecode.bind.annotation.Pipe$Binder$Redirection.make(Pipe.java:332)
    at net.bytebuddy.instrumentation.Instrumentation$Context$Default.register(Instrumentation.java:808)
    at net.bytebuddy.instrumentation.method.bytecode.bind.annotation.Pipe$Binder$Redirection.apply(Pipe.java:342)
    at net.bytebuddy.instrumentation.method.bytecode.bind.MethodDelegationBinder$ParameterBinding$Anonymous.apply(MethodDelegationBinder.java:192)
    at net.bytebuddy.instrumentation.method.bytecode.bind.MethodDelegationBinder$MethodBinding$Builder$Build.apply(MethodDelegationBinder.java:507)
    at net.bytebuddy.instrumentation.method.bytecode.stack.StackManipulation$Compound.apply(StackManipulation.java:194)
    at net.bytebuddy.instrumentation.MethodDelegation$Appender.apply(MethodDelegation.java:998)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Entry$Simple.apply(TypeWriter.java:1055)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Engine$ForCreation.create(TypeWriter.java:688)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1143)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:219)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$AbstractDelegatingBuilder.make(DynamicType.java:1611)
    at X.main(X.java:40)

When I change WrappedObject class to:

    public static class WrappedObject {
        Object method1() {...}
        Object method2() {...}
    }

it runs fine.

So, is @pipe capable of delegation to void returning methods? Or am I doing something wrong?

Add Ability to Generate Java Bean from an Interface

Given the following interface I would like to be able to generate a bean with minimal effort using ByeBuddy. Ideally, I would like to simply give ByteBuddy an interface with getter and setter pairs and have it take care of doing the analysis on the interface and create a dynamic java bean.

public interface UserConfig {

    String getName();

    void setName(String name);

    int getAge();

    void setAge(int age);

}

VerifyError - Bad type on operand stack

The first sample works well with version 0.5.6 but the second sample throws exception for the version 0.6.5

package com.ui4j.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.ClassLoadingStrategy;
import net.bytebuddy.instrumentation.MethodDelegation;
import net.bytebuddy.instrumentation.method.bytecode.bind.annotation.AllArguments;
import net.bytebuddy.instrumentation.method.bytecode.bind.annotation.Origin;
import net.bytebuddy.instrumentation.method.bytecode.bind.annotation.RuntimeType;
import net.bytebuddy.instrumentation.method.bytecode.bind.annotation.SuperCall;
import net.bytebuddy.instrumentation.method.bytecode.bind.annotation.This;
import net.bytebuddy.matcher.ElementMatchers;

import com.ui4j.webkit.proxy.WebKitProxy;

public class Main {

    public static interface Element {

        Element addClass(String... names);

        Element removeClass(String... name);
    }

    public static class WebKitElement implements Element {

        public WebKitElement() {
        }

        @Override
        public Element addClass(String... names) {
            return this;
        }

        @Override
        public Element removeClass(String... name) {
            return this;
        }
    }

    public static class WebKitInterceptor {

        @RuntimeType
        public static Object execute(@SuperCall Callable<Object> callable,
                                                @This Object that,
                                                @Origin Method method,
                                                @AllArguments Object[] arguments) {
            try {
                return callable.call();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Class<? extends WebKitElement> loaded = new ByteBuddy()
                                .subclass(WebKitElement.class)
                                .method(ElementMatchers.any()
                                                .and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class))
                                                .and(ElementMatchers.not(ElementMatchers.nameStartsWith("getEngine")))))
                                .intercept(MethodDelegation.to(WebKitInterceptor.class))
                                .make()
                                .load(WebKitProxy.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                                .getLoaded();
        Constructor<? extends WebKitElement> constructor = loaded.getConstructor();
        WebKitElement instance = constructor.newInstance();
        instance.addClass("foo", "bar");
    }
}
package com.ui4j.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.implementation.bind.annotation.This;
import net.bytebuddy.matcher.ElementMatchers;

import com.ui4j.webkit.proxy.WebKitProxy;

public class Main {

    public static interface Element {

        Element addClass(String... names);

        Element removeClass(String... name);
    }

    public static class WebKitElement implements Element {

        public WebKitElement() {
        }

        @Override
        public Element addClass(String... names) {
            return this;
        }

        @Override
        public Element removeClass(String... name) {
            return this;
        }
    }

    public static class WebKitInterceptor {

        @RuntimeType
        public static Object execute(@SuperCall Callable<Object> callable,
                                                @This Object that,
                                                @Origin Method method,
                                                @AllArguments Object[] arguments) {
            try {
                return callable.call();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Class<? extends WebKitElement> loaded = new ByteBuddy()
                                .subclass(WebKitElement.class)
                                .method(ElementMatchers.any()
                                                .and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class))
                                                .and(ElementMatchers.not(ElementMatchers.nameStartsWith("getEngine")))))
                                .intercept(MethodDelegation.to(WebKitInterceptor.class))
                                .make()
                                .load(WebKitProxy.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                                .getLoaded();
        Constructor<? extends WebKitElement> constructor = loaded.getConstructor();
        WebKitElement instance = constructor.newInstance();
        instance.addClass("foo", "bar");
    }
}
Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    com/ui4j/test/Main$WebKitElement$ByteBuddy$x3pjoCmV.addClass([Ljava/lang/String;)Lcom/ui4j/test/Main$Element; @6: invokespecial
  Reason:
    Type '[Ljava/lang/String;' (current frame, stack[3]) is not assignable to 'java/lang/String'
  Current Frame:
    bci: @6
    flags: { }
    locals: { 'com/ui4j/test/Main$WebKitElement$ByteBuddy$x3pjoCmV', '[Ljava/lang/String;' }
    stack: { uninitialized 0, uninitialized 0, 'com/ui4j/test/Main$WebKitElement$ByteBuddy$x3pjoCmV', '[Ljava/lang/String;' }
  Bytecode:
    0x0000000: bb00 2059 2a2b b700 212a b200 2404 bd00
    0x0000010: 1559 032b 53b8 001b c000 1db0          

    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
    at java.lang.Class.getConstructor0(Unknown Source)
    at java.lang.Class.getConstructor(Unknown Source)
    at com.ui4j.test.Main.main(Main.java:69)

IllegalAccessError when loading a class generated with a NamingStrategy

I have a simple scenario where I receive an IllegalAccessError when loading a generated class that uses a NamingStrategy.

java.lang.IllegalAccessError: class FooBar.Foo cannot access its superclass org.modelmapper.FooTest$Foo
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
    at net.bytebuddy.dynamic.loading.ByteArrayClassLoader.findClass(ByteArrayClassLoader.java:48)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    at net.bytebuddy.dynamic.ClassLoadingStrategy$Default.load(ClassLoadingStrategy.java:59)
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:1132)
    at org.modelmapper.FooTest.proxyClassFor(FooTest.java:35)
    at org.modelmapper.FooTest.test(FooTest.java:40)

Here's the complete test:

@Test
public class FooTest {
  static class Foo {
  }

  public void test() {
    new ByteBuddy().withNamingStrategy(new NamingStrategy() {
          public String getName(UnnamedType unnamedType) {
            return "FooBar." + unnamedType.getSuperClass().getSimpleName();
          }
        })
        .subclass(Foo.class)
        .method(MethodMatchers.any())
        .intercept(InvocationHandlerAdapter.of(new InvocationHandler() {
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return null;
          }
        }))
        .make()
        .load(FooTest.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
        .getLoaded();
  }
}

Cannot build byte-buddy .jar , only byte-budy-deps.jar

The github culture seems to have created an interesting twist to open source .. It is very very rare that I can find a pre-built project / library . The assumption seems to be that noone would want that ... ( this just a background comment, not specific to to BB but its relevent).

Fortuantly I did find byte-budy in the Maven repo ...
I do like cloning or forking projects so I can see the source, but prefer if I get a pre build 'official' libary, especially for Java where its inherently platform neutral. Otherwise its often significant effort and risk to duplicate a build properly (another assumption common on github - that everyone has the same tools and build environments, and knows how to pick the correct branches etc).

I'm learning ! and BB does have actual documentation on building (again rare!)
Very useful as for some reason Maven projects tend to confuse both me and Eclipse ...
I never know what the right command to use, what versions etc and Eclipse gets equally confused.

Thankful for your docs I did exactly this (after cloning from HEAD)
mvn package

it appeared to succeed

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] Byte Buddy (parent) ................................ SUCCESS [ 1.234 s]
[INFO] Byte Buddy Java agent .............................. SUCCESS [ 1.806 s]
[INFO] Byte Buddy (with dependencies) ..................... SUCCESS [ 8.480 s]
[INFO] Byte Buddy (without dependencies) .................. SUCCESS [ 0.142 s]
[INFO] Byte Buddy benchmarks .............................. SUCCESS [ 1.694 s]
[INFO] Byte Buddy for Android ............................. SUCCESS [ 0.921 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 14.397 s
[INFO] Finished at: 2015-01-17T09:35:42-05:00
[INFO] Final Memory: 28M/689M
[INFO] ------------------------------------------------------------------------
E:\Work\DEI\github\byte-buddy>

Except -- only the -dep version has any classes in it

E:\Work\DEI\github\byte-buddy\byte-buddy\target>ls -l
total 14
-rwxr-xr-x 1 DLEE None 5236 Jan 17 09:35 byte-buddy-0.6-SNAPSHOT.jar
E:\Work\DEI\github\byte-buddy\byte-buddy\target>jar t < byte-buddy-0.6-SNAPSHOT.jar
META-INF/
META-INF/MANIFEST.MF
META-INF/maven/
META-INF/maven/net.bytebuddy/
META-INF/maven/net.bytebuddy/byte-buddy/
META-INF/maven/net.bytebuddy/byte-buddy/pom.properties
META-INF/maven/net.bytebuddy/byte-buddy/pom.xml
META-INF/maven/net.bytebuddy/byte-buddy/pom.xml
META-INF/maven/net.bytebuddy/byte-buddy/pom.properties

E:\Work\DEI\github\byte-buddy\byte-buddy-dep\target>ls -l
total 1572
-rwxr-xr-x 1 DLEE None 1021281 Jan 17 09:35 byte-buddy-dep-0.6-SNAPSHOT.jar
META-INF/
META-INF/MANIFEST.MF
...
...
net/bytebuddy/utility/PropertyDispatcher$5.class
net/bytebuddy/utility/PropertyDispatcher$6.class
net/bytebuddy/utility/PropertyDispatcher$7.class
net/bytebuddy/utility/PropertyDispatcher$8.class
net/bytebuddy/utility/PropertyDispatcher$9.class
net/bytebuddy/utility/PropertyDispatcher.class
net/bytebuddy/utility/RandomString.class
net/bytebuddy/utility/StreamDrainer.class
META-INF/maven/net.bytebuddy/byte-buddy-dep/pom.xml

META-INF/maven/net.bytebuddy/byte-buddy-dep/pom.properties

I tried a lot of guessing based on looking at help and what other packages ask for
(I dont know maven more then being able to type "mvn")
mvn install
mvn clean
mvn generate-sources
mvn build

a few dozen like that to no avail.
Eclipse M2 plugin didnt even get that far ...

I was just about to go ahead and use the -dep.jar when I did a little RTFM and found your great docs on NOT to do that ... but fortunately you also said its on Maven Central (had to poke around to find what URL that is) but successfully downloaded the non dep .jar and its working.
( pointing the source to my local git branch )

Any suggestions on what Im doing wrong ?
Im happy to try things and send you the results.

-David

release-notes.md latest notes first

Hi,

imho it is more convenient if the latest note are at the top and the oldest are at the button.

Thanks for providing byte-buddy!

Cheers,
Pascal

LoggerInterceptor for final method not working

Hi, I have a class where I have a final method. I used LoggerInterceptor as mentioned in you example. I cannot able to see the log for it. If I remove the final quantifier, I can able to see the log.

Creating Proxy from Interface with Setter Method with a Primative Parameter Doesn't Work

I am trying to create a proxy class that delegates all method invocation to an existing InvocationHandler implementation without success. The issue seems to stem from having a setter method that has a primitive parameter in my implemented interface (ProxyedInterface). With the bellow test case I get the following exception:

java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    test/ProxyedInterface_Proxy_T3rJCc0Y.setPrimitive(JLjava/lang/String;)V @33: aastore
  Reason:
    Type long_2nd (current frame, stack[7]) is not assignable to 'java/lang/Object'
  Current Frame:
    bci: @33
    flags: { }
    locals: { 'test/ProxyedInterface_Proxy_T3rJCc0Y', long, long_2nd, 'java/lang/String' }
    stack: { 'java/lang/reflect/InvocationHandler', 'test/ProxyedInterface_Proxy_T3rJCc0Y', 'java/lang/reflect/Method', '[Ljava/lang/Object;', '[Ljava/lang/Object;', integer, long, long_2nd }
  Bytecode:
    0x0000000: b200 102a 1206 1222 05bd 0013 5903 b200
    0x0000010: 2653 5904 1229 53b6 0019 05bd 0004 5903
    0x0000020: 1f53 5904 2d53 b900 1f04 0057 b1       
    at java.lang.Class.getDeclaredFields0(Native Method)
    at java.lang.Class.privateGetDeclaredFields(Class.java:2575)
    at java.lang.Class.getDeclaredField(Class.java:2060)
    at net.bytebuddy.instrumentation.LoadedTypeInitializer$ForStaticField.onLoad(LoadedTypeInitializer.java:119)
    at net.bytebuddy.instrumentation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:195)
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.initialize(DynamicType.java:2519)
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:2507)
    at saden1.issues.bytebuddy.ServiceLocatorProxyNGTest.testSomeMethod(ServiceLocatorProxyNGTest.java:37)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.NamingStrategy;
import net.bytebuddy.dynamic.ClassLoadingStrategy;
import net.bytebuddy.instrumentation.InvocationHandlerAdapter;
import static net.bytebuddy.instrumentation.method.matcher.MethodMatchers.*;
import net.bytebuddy.utility.RandomString;
import org.testng.annotations.Test;

public class ProxyNGTest {

    @Test
    public void testSomeMethod() throws InstantiationException, IllegalAccessException {
        Class<?> type = ProxyedInterface.class;
        ClassLoader classLoader = type.getClassLoader();

        Class<?> proxyType = new ByteBuddy(ClassFileVersion.JAVA_V8)
                .withNamingStrategy(new ProxyNamingStrategy(type))
                .subclass(Object.class)
                .implement(type)
                .method(isDeclaredBy(type))
                .intercept(InvocationHandlerAdapter.of(new ProxyInvocationHandler()))
                .make()
                .load(classLoader, ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();

        Object result = proxyType.newInstance();
    }

    public static interface ProxyedInterface {

        //fails on any setter that takes a primitive
        void setPrimitive(long value);

        //fails on any setter that takes a primitive
        void setPrimitive(long value, String string);

        //works
        void setObject(Long value);
    }

    public static class ProxyInvocationHandler implements InvocationHandler {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return method.invoke(proxy, args);
        }
    }

    public static class ProxyNamingStrategy implements NamingStrategy {

        private final Class<?> type;

        public ProxyNamingStrategy(Class<?> type) {
            this.type = type;
        }

        @Override
        public String name(UnnamedType unnamedType) {
            String packageName = type.getPackage().getName();
            String simpleName = type.getSimpleName();
            return String.format("test.%s_Proxy_%s", simpleName, RandomString.make());
        }

    }

}

Byte Buddy does not weave bridge methods

Byte Buddy does currently not weave bridge methods. Therefore, overriding methods with type variables in their signature are currently not overridden. Byte Buddy must discover such methods and add bridge methods on demand.

Similarly, when invoking a super method, the signature of the erased method must be resolved correctly.

Can I create an abstract class with byte buddy?

I need to create some abstract Mixin classes for a package of our framework persistent objects so I can use the jackson framework to serialize them. Are there any examples about how to create an abstract class so I can reference it in the JacksonObjectMapper as a Mixin Class?
objectMapper.addMixInAnnotations(POJO.class, POJOMixin.class);

Or am I screwed due to classloader issues?
Sample Class:

public abstract class JacksonItemMixin {
    @JsonCreator
    protected JacksonItemMixin(@JsonProperty("objId") final Long objId) {
    }
}

The code I have so far:

        Annotation methodAnnotation = JacksonItemMixin.class.getDeclaredConstructor(Long.class).getAnnotation(JsonCreator.class);
        Annotation parameterAnnotation = JacksonItemMixin.class.getDeclaredConstructor(Long.class).getParameterAnnotations()[0][0];
        Class<?> dynamicType = new ByteBuddy().withModifiers(TypeManifestation.ABSTRACT)
                                              .subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
                                              .name(declaringClass.getCanonicalName().concat("MixIn"))
                                              .defineConstructor(Arrays.<Class<?>>asList(Long.class), Visibility.PROTECTED)
                                              .withoutCode()
                                              .annotateMethod(methodAnnotation)
                                              .annotateParameter(0, parameterAnnotation)
                                              .make()
                                              .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
                                              .getLoaded();
        dynamicType.newInstance();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
        assert (false);
    } catch (InstantiationException e) {
        e.printStackTrace();
        assert (true);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
        assert (false);
    }

However this thows this Exception:

java.lang.IllegalStateException: Exception on invoking loader method
    at    net.bytebuddy.dynamic.loading.ClassLoaderByteArrayInjector.inject(ClassLoaderByteArrayInjector.java:142)
at net.bytebuddy.dynamic.loading.ClassLoaderByteArrayInjector.inject(ClassLoaderByteArrayInjector.java:107)
at net.bytebuddy.dynamic.ClassLoadingStrategy$Default$5.load(ClassLoadingStrategy.java:144)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:2944)
at de.idealo.core.factory.CachingItemFactoryTest.createMixinFor(CachingItemFactoryTest.java:293)
at de.idealo.core.factory.CachingItemFactoryTest.testClassScanning(CachingItemFactoryTest.java:277)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Caused by: java.lang.ClassFormatError: Method in class de/pinuts/core/CatalogItemMixIn has illegal modifiers: 0x404
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at net.bytebuddy.dynamic.loading.ClassLoaderByteArrayInjector$ClassLoadingAction.run(ClassLoaderByteArrayInjector.java:320)
at net.bytebuddy.dynamic.loading.ClassLoaderByteArrayInjector$ClassLoadingAction.run(ClassLoaderByteArrayInjector.java:290)
at java.security.AccessController.doPrivileged(Native Method)
at net.bytebuddy.dynamic.loading.ClassLoaderByteArrayInjector.inject(ClassLoaderByteArrayInjector.java:127)
... 32 more
`

Transformation does not expose method in its declared form.

When transforming an instrumented method, this method is recreated as a latent method description and not retained in its declared form. This breaks the lookup of, for example, method constants. Therefore, a more flexible transformer is required.

Create builder for AnnotationDescriptions

Add a builder for defining annotation descriptions programmatically in order to allow easily defining values of unloaded annotations. This is useful when defining annotated types and when definign default values for annotations.

Also, from this builder, allow to define EnumerationValues directly for using with default values.

loading an external class

I am getting a complete class definition from another application in the form of a string, as well as some information about it like the class and package name. How can I pass use this information to create and load the class using the Byte Buddy?
PS: The classes have to implement an interface which my application knows about.

Conflicting interface methods are erased

Currently, Byte Buddy erases the types of two methods if they are defined by two incompatible interfaces. Alternatively, this should only be done if the generic types of the interfaces are in conflict.

Class redefinition failure when loading new class.

new ByteBuddy().redefine(BlockDirt.class).method(named("updateTick")).intercept(MethodDelegation.to(CppDirtInterceptor.class)).make().load(BlockDirt.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());

Upon calling the load method this crashes, despite the CppDirtInterceptor containing a method taking the exact parameters that the updateTick method in the class takes.

java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method
    at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method) ~[?:1.8.0_40]
    at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170) ~[?:1.8.0_40]
    at net.bytebuddy.dynamic.loading.ClassReloadingStrategy$Engine$1.apply(ClassReloadingStrategy.java:242) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.dynamic.loading.ClassReloadingStrategy.load(ClassReloadingStrategy.java:154) ~[byte-buddy-0.6.12.jar:?]
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:3486) ~[byte-buddy-0.6.12.jar:?]

Note that the method is not declared directly in the BlockDirt class, but rather it is declared in the Block class it extends from. Could that be why?

@inline annotation

Can you provide the functionality to in line methods though annotations?

Support for Other JVM Languages

This is awesome. Is it possible to extent this so it can be easily used with other JVM languages with their idiomatic naming conventions. Especially Scala.

Add OSGi manifest headers

I'd like to use Byte Buddy in an OSGi application but cannot because the jar does not contain the necessary META-INF/manifest headers.

The easy way to add them is to use the maven-bundle-plugin.

@Flatten

Add functionality to flatten and object so it in a more optimised layout.

how can we new proxied object and set it into a field?

Hi~

I want to use byte-buddy to generate a proxy-class at compile stage...

e.g. input file like

 public class Rule {

    @AnRule
     public void doRule1() {
     }

    @AnRule
     public void doRule2() {
     }

 }

and want to generate a proxy

 public class RuleInvoker implement Invoker {

     private Rule rule;

     public RuleInvoker() {
         this.rule = new Rule();
     }

     public void invoke() {
          this.rule.doRule1();
          this.rule.doRule2();
     }

 }

now, I can generate RuleInvoker with rule field, and I create a constructor..

But...how can I new a Rule then set it to rule field at constructor...

I try this..

 final Constructor constructor = rawRuleClazz.getConstructor();

 final DynamicType.Unloaded<Invoker> invokerType = new ByteBuddy()
                .subclass(Invoker.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
                .defineField("rule", new TypeDescription.ForLoadedType(rawRuleClazz),
                        Visibility.PRIVATE, FieldManifestation.FINAL)
                .defineConstructor(Collections.<Class<?>>emptyList(), Visibility.PUBLIC)
                .intercept(new Instrumentation() {
                    @Override
                    public InstrumentedType prepare(InstrumentedType instrumentedType) {
                        return instrumentedType;
                    }

                    @Override
                    public ByteCodeAppender appender(final Target instrumentationTarget) {
                        return new ByteCodeAppender() {
                            @Override
                            public boolean appendsCode() {
                                return true;
                            }

                            @Override
                            public Size apply(MethodVisitor methodVisitor,
                                              Context instrumentationContext,
                                              MethodDescription instrumentedMethod) {
                                StackManipulation.Size size = new StackManipulation.Compound(
                                        MethodVariableAccess.REFERENCE.loadOffset(0),
                                        MethodInvocation
                                                .invoke(new TypeDescription.ForLoadedType(
                                                        TestRule.class)
                                                        .getDeclaredMethods()
                                                        .filter(isConstructor()
                                                                .and(takesArguments(0)))
                                                        .getOnly()),
                                        MethodVariableAccess.REFERENCE.loadOffset(0),
                                        MethodConstant.forMethod(
                                                new MethodDescription.ForLoadedConstructor(
                                                        constructor)),
                                        FieldAccess.forField(
                                                instrumentationTarget.getTypeDescription()
                                                        .getDeclaredFields().get(0))
                                                .putter(),
                                        MethodReturn.VOID
                                ).apply(methodVisitor, instrumentationContext);
                                return new Size(size.getMaximalSize(),
                                        instrumentedMethod.getStackSize());
                            }
                        };
                    }
                })
                .make();

It seems that doest do invokespecial , has any short-cut to do this?

  • - sorry I try to found it on document or TestCase, but doesn't found it..so create this 'question issue'~

^ ^ thx~

saveIn throws FileNotFoundException

Hi,

The sample code snippet throws FileNotFoundException. If the folder structure created manually (c:/app-classpath/sample/app) saveIn works successfully. I am not sure if this is a bug, should i create package structure manually?

Thanks

package sample.app;

import java.io.File;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType.Unloaded;
import net.bytebuddy.instrumentation.FixedValue;
import net.bytebuddy.instrumentation.method.matcher.MethodMatchers;

public class Sample {

    public String test() {
        return null;
    }

    public static void main(String[] args) throws Exception {
        File file = new File("C:\\app-classpath");
        file.mkdir();
        ByteBuddy buddy = new ByteBuddy();
        Unloaded<Sample> unloaded = buddy
                                        .subclass(Sample.class)
                                        .method(MethodMatchers.named("test"))
                                        .intercept(FixedValue.value("test"))
                                        .make();
        unloaded.saveIn(file);
    }
}

Exception Message:

Exception in thread "main" java.io.FileNotFoundException: C:\app-classpath\sample\app\Sample$ByteBuddy$314824326.class (No such file or directory)
    at java.io.FileOutputStream.open(Native Method)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:206)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:156)
    at net.bytebuddy.dynamic.DynamicType$Default.saveIn(DynamicType.java:1289)
    at sample.app.Sample.main(Sample.java:25)

Environment:
Windows 8.1
Java 1.8.0_20-b26

Documentation on creating fields

I was unable to work out how to generate a final field and populate it in the synthetic constructor. After playing with the API I presume this is supported (is this right?). Improved documentation - example! - of beginning-to-end creating of immutable classes would be nice.

In general the API is quite good. Perhaps a high-level wrapper API would help?

Add Support for New Naming Strategy Based on First Available Declared Interface

If your super type is an interface the use of the current out of the box naming strategies result in the name of the proxy class being the concatenation of javaLangPackagePrefix, the Object class name, and random string. While this is fine in terms of creating a unique proxy class names it leads to the loss of contextual information about what's being proxyed.

I'd like to propose the addition of a new naming strategy that uses the fully qualified name of the first available declared interface if the super type represents Object.class type. If the super type does not represent an Object.class type the naming strategy will be behaves like SuffixingRandom naming strategy. Something like this:

    /**
     * A naming strategy that uses the name of the first interface if the super type is {@link Object Object.class}
     * otherwise the naming strategy behaves exactly like the {@link SuffixingRandom} naming strategy.
     * <ol>
     * <li>The fully qualified name of the super class or the first interface</li>
     * <li>A given suffix string</li>
     * <li>A random number</li>
     * </ol>
     * Between all these elements, a {@code $} sign is included into the name to improve readability. As an exception,
     * types that subclass classes from the {@code java.**} packages are prefixed with a given package. This is
     * necessary as it is illegal to define non-bootstrap classes in this name space. The same strategy is applied when
     * subclassing a signed type which is equally illegal.
     */
    static class FirstInterface implements NamingStrategy {

        /**
         * The package prefix of the {@code java.**} packages for which the definition of non-bootstrap types is
         * illegal.
         */
        private static final String JAVA_PACKAGE = "java.";

        /**
         * The default package for defining types that are renamed to not be contained in the
         * {@link net.bytebuddy.NamingStrategy.SuffixingRandom#JAVA_PACKAGE} package.
         */
        private static final String BYTE_BUDDY_RENAME_PACKAGE = "net.bytebuddy.renamed";

        /**
         * The suffix to attach to a super type name.
         */
        private final String suffix;

        /**
         * The renaming location for types of the {@link net.bytebuddy.NamingStrategy.SuffixingRandom#JAVA_PACKAGE}.
         */
        private final String javaLangPackagePrefix;

        /**
         * An instance for creating random seed values.
         */
        private final RandomString randomString;

        /**
         * Creates an immutable naming strategy with a given suffix but moves types that subclass types within the
         * {@code java.lang} package into ByteBuddy's package namespace.
         *
         * @param suffix The suffix for the generated class.
         */
        public FirstInterface(String suffix) {
            this(suffix, BYTE_BUDDY_RENAME_PACKAGE);
        }

        /**
         * Creates an immutable naming strategy with a given suffix but moves types that subclass types within the
         * {@code java.lang} package into a given namespace.
         *
         * @param suffix The suffix for the generated class.
         * @param javaLangPackagePrefix The fallback namespace for type's that subclass types within the
         * {@code java.lang} namespace.
         */
        public FirstInterface(String suffix, String javaLangPackagePrefix) {
            this.suffix = suffix;
            this.javaLangPackagePrefix = javaLangPackagePrefix;
            randomString = new RandomString();
        }

        @Override
        public String name(NamingStrategy.UnnamedType unnamedType) {
            TypeDescription superClass = unnamedType.getSuperClass();
            Collection<TypeDescription> interfaces = unnamedType.getDeclaredInterfaces();

            if (superClass.represents(Object.class) && !interfaces.isEmpty()) {
                superClass = interfaces.iterator().next();
            }

            String superClassName = superClass.getName();
            if (superClassName.startsWith(JAVA_PACKAGE) || superClass.isSealed()) {
                superClassName = javaLangPackagePrefix + "." + superClassName;
            }

            return String.format("%s$%s$%s", superClassName, suffix, randomString.nextString());
        }

        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
            if (other == null || getClass() != other.getClass()) {
                return false;
            }
            FirstInterface that = (FirstInterface) other;
            return javaLangPackagePrefix.equals(that.javaLangPackagePrefix)
                    && suffix.equals(that.suffix);
        }

        @Override
        public int hashCode() {
            int result = suffix.hashCode();
            result = 31 * result + javaLangPackagePrefix.hashCode();
            return result;
        }

        @Override
        public String toString() {
            return "NamingStrategy.FirstInterface{"
                    + "suffix='" + suffix + '\''
                    + ", javaLangPackagePrefix='" + javaLangPackagePrefix + '\''
                    + ", randomString=" + randomString
                    + '}';
        }
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.