Paul Hammant
2011-12-08 15:26:53 UTC
This looked interesting :-
http://code.google.com/p/reflectasm/
... looks pretty intriguing. Faster it claims.
I did some testing last night and it's only 10% faster than regular
reflection for method invocations, and only if your cache the ASM-made
subclass of "MethodAccess".
There are some flaws too:
1. It generates accessors for each method in a class - you may have
been interested in only a single method.
2. It assumed that there is no method overloading in the class
3. Exceptions will pass through (no InvocationTargetException), yet
are not (and cannot be) concisely listed on the throws clause of the
var-args invoke method you use. You have to be aware of the exceptions
that could be thrown, or catch base Exception (yeesh).
It does one interesting trick. See
http://reflectasm.googlecode.com/svn/trunk/src/com/esotericsoftware/reflectasm/MethodAccess.java
MethodAccess (the class) is in your regular classpath on use, as normal
Java launch semantics. The classes that ASM generates ALSO purport to be
MethodAccess (same package), but by some defineClass magic in a child
class-loader, are instantiated instead of the real deal. The Java Compiler
lets you think you are using static method on MethodAccess, but at runtime
you are using a method with the same signature in a different class (with
the same name).
It got me thinking though.
Say, for @Inject methods (and constructors, poss fields too)
There could be a QDox build stage that kicks in and makes an invoke class
for each so-annotated method.
In the same way that GMaven allows Java and Groovy to interop in the same
source buildable jar (by generating shims of the Groovy classes for the
Java classes to compile against), some tricks that JetBrains and Eclipse
would buy into would allow a method invocation design that was more first
class than reflection. For example:
public class Foo {
@Inject
public void bar(Baz baz) {
}
}
public static void main(String[] args) {
Foo instance = new Foo();
Foo.bar1965ed0b.invoke(instance, new Baz());
}
// 1965ed0b is a CRC32 hash of 'Baz baz'
PicoContainer, Guice etc could speculatively look for the inner
class bar1965ed0b and use it. It would still not preserve throws clauses
as Pico/Guice would cast it to a interface to use it for the speed you're
seeking. It would be in the same jar file of course. Shame about the
extra bytes - AFAICR the min byte size of an inner class is 178.
Java7's project coin <http://openjdk.java.net/projects/coin/> makes this a
bit moot though perhaps.
- Paul
http://code.google.com/p/reflectasm/
... looks pretty intriguing. Faster it claims.
I did some testing last night and it's only 10% faster than regular
reflection for method invocations, and only if your cache the ASM-made
subclass of "MethodAccess".
There are some flaws too:
1. It generates accessors for each method in a class - you may have
been interested in only a single method.
2. It assumed that there is no method overloading in the class
3. Exceptions will pass through (no InvocationTargetException), yet
are not (and cannot be) concisely listed on the throws clause of the
var-args invoke method you use. You have to be aware of the exceptions
that could be thrown, or catch base Exception (yeesh).
It does one interesting trick. See
http://reflectasm.googlecode.com/svn/trunk/src/com/esotericsoftware/reflectasm/MethodAccess.java
MethodAccess (the class) is in your regular classpath on use, as normal
Java launch semantics. The classes that ASM generates ALSO purport to be
MethodAccess (same package), but by some defineClass magic in a child
class-loader, are instantiated instead of the real deal. The Java Compiler
lets you think you are using static method on MethodAccess, but at runtime
you are using a method with the same signature in a different class (with
the same name).
It got me thinking though.
Say, for @Inject methods (and constructors, poss fields too)
There could be a QDox build stage that kicks in and makes an invoke class
for each so-annotated method.
In the same way that GMaven allows Java and Groovy to interop in the same
source buildable jar (by generating shims of the Groovy classes for the
Java classes to compile against), some tricks that JetBrains and Eclipse
would buy into would allow a method invocation design that was more first
class than reflection. For example:
public class Foo {
@Inject
public void bar(Baz baz) {
}
}
public static void main(String[] args) {
Foo instance = new Foo();
Foo.bar1965ed0b.invoke(instance, new Baz());
}
// 1965ed0b is a CRC32 hash of 'Baz baz'
PicoContainer, Guice etc could speculatively look for the inner
class bar1965ed0b and use it. It would still not preserve throws clauses
as Pico/Guice would cast it to a interface to use it for the speed you're
seeking. It would be in the same jar file of course. Shame about the
extra bytes - AFAICR the min byte size of an inner class is 178.
Java7's project coin <http://openjdk.java.net/projects/coin/> makes this a
bit moot though perhaps.
- Paul