Document is hard to read
- Missing is a description of each component and its common methods (like
TypePool,DynamicType,ClassLoadingStrategyetc.) - Class calls may vary from version to version, such as the current version is:
package foo;
class Bar { }
class MyApplication {
public static void main(String[] args) {
TypePool typePool = TypePool.Default.ofClassPath();
new ByteBuddy()
.redefine(typePool.describe("foo.Bar").resolve(), // do not use 'Bar.class'
ClassFileLocator.ForClassLoader.ofClassPath())
.defineField("qux", String.class) // we learn more about defining fields later
.make()
.load(ClassLoader.getSystemClassLoader());
assertThat(Bar.class.getDeclaredField("qux"), notNullValue());
}
}
It was not compiled in 1.9.13, but the 1.9.13 version of the document could not be found. Try to change it to:
package foo;
class Bar { }
class MyApplication {
public static void main(String[] args) {
TypePool typePool = TypePool.Default.of(Thread.currentThread().getContextClassLoader());
new ByteBuddy()
.redefine(typePool.describe("foo.Bar").resolve(), // do not use 'Bar.class'
ClassFileLocator.ForClassLoader.of(Thread.currentThread().getContextClassLoader()))
.defineField("qux", String.class) // we learn more about defining fields later
.make()
.load(ClassLoader.getSystemClassLoader());
assertThat(Bar.class.getDeclaredField("qux"), notNullValue());
}
}
But in the end:
Exception in thread "main" java.lang.IllegalStateException: Class already loaded: foo.Bar
Much more complex than using javassist
.load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTION);
So it works. By passing ClassLoadingStrategy.Default.INJECTION.
the default ClassLoadingStrategy.Default.WRAPPER use another ByteArrayClassLoader and it's parent is SystemLoader.
A feature was added to Byte Buddy that throws an exception if a class that is injected is already loaded. In Byte Buddy 1.9.*, any use unsafe (unofficial) API is opt-in, therefore, INJECTION is no longer the default.
But you are right, there should be more documentation, I simply lack the time to write it.
Thanks for answering questions and considering Suggestions
The examples from Section "Accessing fields" of this tutorial (http://bytebuddy.net/#/tutorial) will not work in version 1.9.13.
When running to
InstanceCreator factory = new ByteBuddy()
.subclass(InstanceCreator.class)
.method(not(isDeclaredBy(Object.class)))
.intercept(MethodDelegation.toConstructor(dynamicUserType))
.make()
.load(I.class.getClassLoader())
.getLoaded()
.newInstance();
An exception is thrown here, beause:
MethodDelegationBinder$Processor#bind(Implementation.Target implementationTarget,
MethodDescription source,
TerminationHandler terminationHandler,
MethodInvoker methodInvoker,
Assigner assigne)
How to solve this problem?
in @Argumen$Binder#bind(...) :
Argument argument = annotation.loadSilent();
if (argument.value() < 0) {
throw new IllegalArgumentException("@Argument annotation on " + target + " specifies negative index");
} else if (source.getParameters().size() <= argument.value()) {
return MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE;
}
source.getParameters().size() <= argument.value() make this exception.
-
sourceisInstanceCreatorand it's argument length is empty, -
argument.value()also zero In such a case, the judgment must be illegal. The logic here is confusing to me.
@raphw