- In what case is it recommended to reuse ByteBuddy instances?
- Are ByteBuddy instances threadsafe?
- Does ByteBuddy cache classes internally similar to the way that Cglib does, or can it be made to? I'd like to avoid generating the same proxy (defined as a superclass and set of superinterfaces) multiple times.
- Is there a way to make a single `Unloaded` instance and swap in different interceptors prior to instantiation similar to Cglib's `Enhancer.registerCallbacks` method?
- Is there a way to tell if a class was generated via ByteBuddy similar to Cglib's `Enhancer.isEnhanced` method? Would I need to throw in a marker interface to do this?
- Is there a subset of ByteBuddy's packages that I could repackage to support basic proxy creation if that's all I'm interested in? My ByteBuddy usage may look something like this:
    new ByteBuddy().withNamingStrategy(NAMING_STRATEGY)
      .subclass(Object.class)
      .method(METHOD_MATCHER)
      .intercept(INVOCATION_HANDLER_ADAPTER)
      .make()
      .load(ProxyFactory.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
      .getLoaded();
Thanks,
Jonathan
Hey Jonathan,
thank you for using Byte Buddy. As for your questions:
1. You should reuse Byte Buddy instances if you want to reuse a certain configuration without considering performance. Most Byte Buddy instances are dead-cheap to create and I did some benchmarking using JMH where I compared reuse vs. recreation and there is no significant overhead in non-reusing. All instances that ship with Byte Buddy are immutable what makes it rather easy for the JVM's just-in-time compiler to optimize your code in case that the creation is time-critical. The "raw" invocation without just-in-time compilation only cares for a few additional nanoseconds.
2. Yes, All Byte Buddy classes that are exposed to a user are fully immutable what makes them thread safe. The reuse of instances, even among different threads is therefore possible and even recommended.
3. No, Byte Buddy does not keep a cache internally. In order to maintain a cache, Byte Buddy would need to remember a quite complex vector of parameters of what classes it created, including the class loader of this class. This would be potentially expensive and dangerous, especially if Byte Buddy had a different class loader than its created classes as it could create severe memory leaks. Also, from my experience with cglib and javassist, their caches do more harm then good, even though the feature seems convenient at first inspection. If you only want to create proxies that are always loaded with the same class loader as the proxied class, you could for example write a simple class-to-class cache. If Byte Buddy maintained the cache, it could not make this assumption but had to store a vector of all (!) input variables and compare any vector to other inputs. This would not be very efficient. Therefore, you should write your own cache or use a library that specializes on caching such as Ehcache or Guava caches. See this question on Stack Overflow that relates to the same issue: http://stackoverflow.com/questions/23732236/caching-generated-classes-in-byte-buddy
4. If I understand this question correctly, then you want to register an instance-specific callback?
You can use the MethodDelegation to only define a field without a value. This is also possible when using an invocation handler adapter as I assume it is what you intend to to. The invocation handler defines a method MethodDelegation#of(String) where the string describes a field name. All invocations will then be forwarded to the handler in this field (which must be set manually).
You can additionally define an accessor method for this field, using any user-defined interface and the FieldAccessor instrumentation. An example of something similar can be found in the tutorial where the FieldAccessor is explained. The explanation comes with a runnable code example. By using your own interface for accessing a field, you can also avoid limitations such as javassists only working with a single interceptor and its inability to proxy any class that defines methods named "getProxy" or "setProxy".
5. This is against Byte Buddy's philosophy which wants to be as transparent as possible. As a matter of fact, all Byte Buddy generated classes are fully usable without Byte Buddy being found on the class path. This allows for easy serialization and using Byte Buddy in build-time instrumentation. You can however define your own marker interface and simply implement this interface for any instance.
6. No, there is no such submodule, but Byte Buddy is merely 500 kB big and I do not think it will grow much further in size. (As a comparison, cglib is about 350 kB big.) A problem Byte Buddy or any other ASM-using library faces in this context is its repackaging dependency on ASM. This makes modularization hard as you need to offer a dependency with and without dependencies for each module and it tends to confuse both library users and maintainers of code that use ASM. It could also lead to confusing class path issues if someone used a subset of a no-dependency version and someone else used another subset of a dependency-version.
Once again, thanks for using Byte Buddy and stay tuned for an update to version 0.2 which will introduce proper support for Java 8 features such as calling default methods, several runtime performance improvements and some miscellaneousfeatures such as a "forwarder instrumentation" what makes the creation of very fast proxy classes very easy. Stay tuned!
Awesome. Thanks for all of the responses!