
Byte Buddy – runtime code generation for the JVM - raphw
https://github.com/raphw/byte-buddy
======
gdubya
Byte Buddy is also on its way to replace CGLib in Mockito:
[https://github.com/mockito/mockito/pull/171](https://github.com/mockito/mockito/pull/171)

~~~
leonardinius
That's was helpful. I was quite recently wondering that's the alternative,
since cglib seems to be .. at some weird state at least.

Thanks for pointing this out.

------
the8472
I wonder how efficient the generated classes are.

If they're just as good as a final class with directly implemented methods
then this might be useful to implement FieldHandles (similiar to
MethodHandles[1]) with practically zero overhead, since the JVM can optimize
away a lot of runtime checks and devirtualize method calls on leaf classes.

[1]
[http://docs.oracle.com/javase/8/docs/api/java/lang/invoke/Me...](http://docs.oracle.com/javase/8/docs/api/java/lang/invoke/MethodHandles.html)

~~~
raphw
Byte Buddy is quite efficient. It is more or less like implementing Java code
per hand. Byte Buddy comes along with a benchmark where the results are listed
here: [http://bytebuddy.net/#/tutorial](http://bytebuddy.net/#/tutorial)

This way, it even beats the use of MethodHandles for accessing fields which
still have a slight overhead over "normal" field access:
[https://gist.github.com/raphw/881e1745996f9d314ab0](https://gist.github.com/raphw/881e1745996f9d314ab0)

Of course, there might be a flaw in the benchmark, those are tricky. Si please
challange it, I am always interested in such details. I also guess, that the
advantage will decrease with future JVMs.

~~~
the8472
Afaik method handles need to be assigned to final fields (with
-XX:+TrustFinalNonStaticFields) or final static fields for the JIT to be able
to inline them.

~~~
raphw
You are right, it is stated here:
[https://wiki.openjdk.java.net/display/HotSpot/Deconstructing...](https://wiki.openjdk.java.net/display/HotSpot/Deconstructing+MethodHandles)

I will update and rerun the benchmark some time. Unfortunately, storing a
value in a static final field allows the VM to pre-determine the entire method
call and to erase the invocation altogether. This makes it hard to measure the
impact of the method call. It is also questionable if this is the desired
measurement as reflection is normally used to delay a call site determination
to runtime which could not be done using a MethodHandle in a static final
field.

But really good catch! I will hava a look at it some time soon.

------
tootie
Could this replace something like XJC for generating POJOs from an XML Schema?
With XJC the classes are created at build time, but this could allow them to
be fully dynamic allowing schema changes in a running app.

~~~
raphw
Byte Buddy does not generate source code, only byte code. Arguably, when
creating such POJOs that are used within an application, most people would
prefer source code.

------
twic
Looks good! What are the alternatives, and how does it compare to them? cglib?
Javassist? I guess BCEL is much lower-level.

~~~
raphw
The two biggest competitors to Byte Buddy today are javassist and cglib. Both
of them work quite differently:

javassist takes strings containing Java code and compiles these strings at
runtime. This makes it simple to use as every Java developer knows Java.
Unfortunately, the javassist compiler lags a lot behind the actual javac
compiler. For example, it does not support generics or even auto-boxing, not
to speak of lambda expressions. Also, Strings are not type-safe what makes
javassist code quite error prone. (It is the equivalent of concenating SQL
strings together, with all the risks like foreign code injection.)

cglib allows you to register callbacks for an overridden class, similar to the
JDK proxies. However, this requires that all class loaders know about cglib if
they want to know these cglib-proxies as cglib-specific types are hard-coded
into any generated class. Also, cglib only allows subclassing but not the
rewrital of existing classes. Furthermore, the callbacks require any arguments
to be boxed and registeres these boxed values into arrays. It turns out that
cglib is not quite Just-In-Time-compiler friendly.

Byte Buddy works with annotations or its type-safe DSL and realizes its
instrumentation mostly based on delegating to user code. This way, you can
implement interceptors in any JVM language and you avoid dependencies on Byte
Buddy within the generated classes (annotations are fortunately ignored by JVM
class loaders if they cannot be resolved at load-time). This makes for example
for better exception stack traces than when using "string code". Also, Byte
Buddy avoids boxing by creating smarter objects for the interceptors and only
creates those interceptors that are requested by annotated arguments, using
dependency injection.

ASM or BCEL are rather byte code parser than code generation libraries. You
need to have a clear concept of how byte code works in order to use them.
Also, those libraries allow you to create "unverified code", i.e. you have to
do a lot manually. Byte Buddy is itself built on top of ASM, you can even plug
ASM code into Byte Buddy if you need to.

~~~
int3
Another approach would be to translate the compiled output of javac into ASM
method calls:
[https://github.com/int3/java2asm](https://github.com/int3/java2asm)

It's fairly unpolished at the moment, though.

