-
-
Notifications
You must be signed in to change notification settings - Fork 808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to cast the actual parametric return type of a method belonging to a generic type? #1725
Comments
You are falling victim to type erasure, where |
Because I have no guarantees that the type of the value returned by I temporarily jury-rigged the type erasure problem picking the first interface available, but it's a horrible (although effective) hack: public static <T> T xcast(Object obj, Class<?> objType) {
final Class<?> sourceType;
if (objType == Object.class) {
// Look for the first interface (if any) to implement as proxy!
objType = obj.getClass();
var candidateSourceType = objType;
while (objType != Object.class) {
var interfaceTypes = objType.getInterfaces();
if (interfaceTypes.length > 0) {
candidateSourceType = interfaceTypes[0];
break;
}
objType = objType.getSuperclass();
}
sourceType = candidateSourceType;
} else {
sourceType = objType != null ? objType : obj.getClass();
}
. . .
} I hoped a more robust solution could possibly be exploited through bytecode manipulation, alas... 😢 |
You can wrap classes in a |
Is there any tutorial/demo which provides a context to grasp the proper usage of |
Simply load a class using |
Thank you very much for your hints! Your library is powerful and its API is slick, but its breadth is a bit intimidating to get started with — maybe something like a community-driven repository of practical code snippets, like a cookbook, would help lowering the learning curve 😅 |
net.bytebuddy:byte-buddy:1.15.10
(LATEST)Context
I am extending a third-party application which dynamically loads extensions via
URLClassLoader
.My extension encompasses two artifacts (say, ext1.jar and ext2.jar), each implementing a distinct kind of functionality (say,
MyExtension1
andMyExtension2
implementingExtension1
andExtension2
application domain interfaces, along with respective ancillary types); ext2.jar depends on ext1.jar, so the public types of ext1.jar (i.e.,MyExtension1
and its ancillary types) are visible to ext2.jar.As the third-party application manages extensions by functionality, those 2 artifacts are loaded separately, along with their respective dependencies, so the resulting class loader hierarchy is:
Application domain types:
MyExtension1
(implementsExtension1
) types:MyExtension2
(implementsExtension2
, depends onMyExtension1
) types:As a consequence, when the logic of
MyExtension2
retrieves from the application domain an instance ofExtension1
(whose actual type isMyExtension1
@urlClassLoader1) and tries to cast it asMyExtension1
@urlClassLoader2, a typicalClassCastException
occurs:Since the loading logic of the application is beyond my control, I cannot fix such type split but work around it: the ugly serialization/deserialization trick is out of the question (I need dynamic interaction, not state copy!), so reflection seems the only viable option. However, since explicit reflection would be a royal pain, I decided to employ proxying via ByteBuddy.
Issue
So far, my solution leveraging ByteBuddy has proved to work quite well at pre-alpha stage (kudos to @raphw!), except for one annoying issue I haven't been able to solve yet: casting of parametric return types for generic interfaces. For example:
The
ClassCastException
here above is due to the circumstance that the proxiedT next()
uses the result ofbaseMethod.getReturnType()
(see code below) as proxied type (which is obviously erased toObject
), instead of the actual type parameter ofIterator<Map.Entry>
.Here it is my proxying logic:
(NOTE: proxy caching logic has been omitted for the sake of clarity)
I read something about
withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC)
, for example on stackoverflow, but I'm unsure whether it is appropriate for my use case; furthermore, apparently it is not applicable to invocation handlers... Out of desperation, I gave a try towithAssigner(Assigner.GENERICS_AWARE)
, but failed ("java.lang.UnsupportedOperationException: Assignability checks for type variables declared by methods are not currently supported").Is there a convenient way to cast the parametric return type of a method belonging to a generic type, so the actual type of that parameter is returned instead of its erasure?
thanks!
The text was updated successfully, but these errors were encountered: