-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Issue #4691 - use static methods with javadoc to get MethodHandle lookups #4694
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -374,7 +374,7 @@ public <T> void addMessageHandler(JavaxWebSocketSession session, Class<T> clazz, | |
try | ||
{ | ||
// TODO: move methodhandle lookup to container? | ||
MethodHandles.Lookup lookup = MethodHandles.publicLookup(); | ||
MethodHandles.Lookup lookup = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup(); | ||
MethodHandle partialMessageHandler = lookup | ||
.findVirtual(MessageHandler.Partial.class, "onMessage", MethodType.methodType(void.class, Object.class, boolean.class)); | ||
partialMessageHandler = partialMessageHandler.bindTo(handler); | ||
|
@@ -432,7 +432,7 @@ public <T> void addMessageHandler(JavaxWebSocketSession session, Class<T> clazz, | |
try | ||
{ | ||
// TODO: move MethodHandle lookup to container? | ||
MethodHandles.Lookup lookup = MethodHandles.publicLookup(); | ||
MethodHandles.Lookup lookup = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto. |
||
MethodHandle wholeMsgMethodHandle = lookup.findVirtual(MessageHandler.Whole.class, "onMessage", MethodType.methodType(void.class, Object.class)); | ||
wholeMsgMethodHandle = wholeMsgMethodHandle.bindTo(handler); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -124,7 +124,7 @@ public abstract class JavaxWebSocketFrameHandlerFactory | |
{ | ||
try | ||
{ | ||
FILTER_RETURN_TYPE_METHOD = MethodHandles.lookup() | ||
FILTER_RETURN_TYPE_METHOD = getServerMethodHandleLookup() | ||
.findVirtual(JavaxWebSocketSession.class, "filterReturnType", MethodType.methodType(void.class, Object.class)); | ||
} | ||
catch (Throwable e) | ||
|
@@ -322,16 +322,17 @@ public static MessageSink createMessageSink(JavaxWebSocketSession session, Messa | |
|
||
try | ||
{ | ||
MethodHandles.Lookup lookup = getServerMethodHandleLookup(); | ||
if (DecodedMessageSink.class.isAssignableFrom(msgMetadata.sinkClass)) | ||
{ | ||
MethodHandle ctorHandle = MethodHandles.lookup().findConstructor(msgMetadata.sinkClass, | ||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.sinkClass, | ||
MethodType.methodType(void.class, CoreSession.class, msgMetadata.registeredDecoder.interfaceType, MethodHandle.class)); | ||
Decoder decoder = session.getDecoders().getInstanceOf(msgMetadata.registeredDecoder); | ||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), decoder, msgMetadata.handle); | ||
} | ||
else | ||
{ | ||
MethodHandle ctorHandle = MethodHandles.lookup().findConstructor(msgMetadata.sinkClass, | ||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.sinkClass, | ||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class)); | ||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.handle); | ||
} | ||
|
@@ -388,7 +389,7 @@ private MethodHandle toMethodHandle(MethodHandles.Lookup lookup, Method method) | |
protected JavaxWebSocketFrameHandlerMetadata createEndpointMetadata(Class<? extends javax.websocket.Endpoint> endpointClass, EndpointConfig endpointConfig) | ||
{ | ||
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig); | ||
MethodHandles.Lookup lookup = getMethodHandleLookup(endpointClass); | ||
MethodHandles.Lookup lookup = getApplicationMethodHandleLookup(endpointClass); | ||
|
||
Method openMethod = ReflectUtils.findMethod(endpointClass, "onOpen", | ||
javax.websocket.Session.class, javax.websocket.EndpointConfig.class); | ||
|
@@ -410,7 +411,7 @@ protected JavaxWebSocketFrameHandlerMetadata createEndpointMetadata(Class<? exte | |
|
||
protected JavaxWebSocketFrameHandlerMetadata discoverJavaxFrameHandlerMetadata(Class<?> endpointClass, JavaxWebSocketFrameHandlerMetadata metadata) | ||
{ | ||
MethodHandles.Lookup lookup = getMethodHandleLookup(endpointClass); | ||
MethodHandles.Lookup lookup = getApplicationMethodHandleLookup(endpointClass); | ||
Method onmethod; | ||
|
||
// OnOpen [0..1] | ||
|
@@ -704,9 +705,53 @@ private void assertSignatureValid(Class<?> endpointClass, Method method, Class<? | |
} | ||
} | ||
|
||
private MethodHandles.Lookup getMethodHandleLookup(Class<?> endpointClass) | ||
/** | ||
* <p> | ||
* Gives a {@link MethodHandles.Lookup} instance to be used to find methods in server classes. | ||
* For lookups on application classes use {@link #getApplicationMethodHandleLookup(Class)} ()} instead. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is an additional |
||
* </p> | ||
* <p> | ||
* This uses the caller sensitive {@link MethodHandles#lookup()}, this will allow MethodHandle access | ||
* to server classes we need to use and will give access permissions to private methods as well. | ||
* </p> | ||
* | ||
* @return | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing description of what it returns. |
||
*/ | ||
public static MethodHandles.Lookup getServerMethodHandleLookup() | ||
{ | ||
return MethodHandles.lookup(); | ||
} | ||
|
||
/** | ||
* <p> | ||
* Gives a {@link MethodHandles.Lookup} instance to be used to find public methods in application classes. | ||
* For lookups on server classes use {@link #getServerMethodHandleLookup()} instead. | ||
* </p> | ||
* <p> | ||
* This uses {@link MethodHandles#publicLookup()} as we only need access to public method of the lookupClass. | ||
* To look up a method on the lookupClass, it must be public and the class must be accessible from this | ||
* module, so if the lookupClass is in a JPMS module it must be exported so that the public methods | ||
* of the lookupClass are accessible outside of the module. | ||
* </p> | ||
* <p> | ||
* The {@link java.lang.invoke.MethodHandles.Lookup#in(Class)} allows us to search specifically | ||
* in the endpoint Class to avoid any potential linkage errors which could occur if the same | ||
* class is present in multiple web apps. Unlike using {@link MethodHandles#publicLookup()} | ||
* using {@link MethodHandles#lookup()} with {@link java.lang.invoke.MethodHandles.Lookup#in(Class)} | ||
* will cause the lookup to lose its public access to the lookup class if they are in different modules. | ||
* </p> | ||
* <p> | ||
* {@link MethodHandles#privateLookupIn(Class, MethodHandles.Lookup)} is also unsuitable because it | ||
* requires the caller module to read the target module, and the target module to open reflective | ||
* access to the lookupClasses private methods. This is possible but requires extra configuration | ||
* to provide private access which is not necessary for the purpose of accessing the public methods. | ||
* </p> | ||
* @param lookupClass the desired lookup class for the new lookup object. | ||
* @return a lookup object to be used to find methods on the lookupClass. | ||
*/ | ||
public static MethodHandles.Lookup getApplicationMethodHandleLookup(Class<?> lookupClass) | ||
{ | ||
return MethodHandles.publicLookup().in(endpointClass); | ||
return MethodHandles.publicLookup().in(lookupClass); | ||
} | ||
|
||
private static class DecodedArgs | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -157,7 +157,8 @@ public static MessageSink createMessageSink(MethodHandle msgHandle, Class<? exte | |
|
||
try | ||
{ | ||
MethodHandle ctorHandle = MethodHandles.lookup().findConstructor(sinkClass, | ||
MethodHandles.Lookup lookup = JettyWebSocketFrameHandlerFactory.getServerMethodHandleLookup(); | ||
MethodHandle ctorHandle = lookup.findConstructor(sinkClass, | ||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class)); | ||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgHandle); | ||
} | ||
|
@@ -194,7 +195,7 @@ private MethodHandle toMethodHandle(MethodHandles.Lookup lookup, Method method) | |
private JettyWebSocketFrameHandlerMetadata createListenerMetadata(Class<?> endpointClass) | ||
{ | ||
JettyWebSocketFrameHandlerMetadata metadata = new JettyWebSocketFrameHandlerMetadata(); | ||
MethodHandles.Lookup lookup = getMethodHandleLookup(endpointClass); | ||
MethodHandles.Lookup lookup = JettyWebSocketFrameHandlerFactory.getApplicationMethodHandleLookup(endpointClass); | ||
|
||
Method openMethod = ReflectUtils.findMethod(endpointClass, "onWebSocketConnect", Session.class); | ||
MethodHandle open = toMethodHandle(lookup, openMethod); | ||
|
@@ -273,7 +274,7 @@ private JettyWebSocketFrameHandlerMetadata createAnnotatedMetadata(WebSocket ann | |
metadata.setIdleTimeout(Duration.ofMillis(max)); | ||
metadata.setBatchMode(anno.batchMode()); | ||
|
||
MethodHandles.Lookup lookup = getMethodHandleLookup(endpointClass); | ||
MethodHandles.Lookup lookup = getApplicationMethodHandleLookup(endpointClass); | ||
Method onmethod; | ||
|
||
// OnWebSocketConnect [0..1] | ||
|
@@ -456,9 +457,53 @@ private void assertSignatureValid(Class<?> endpointClass, Method method, Class<? | |
throw new InvalidSignatureException(err.toString()); | ||
} | ||
|
||
private MethodHandles.Lookup getMethodHandleLookup(Class<?> endpointClass) | ||
/** | ||
* <p> | ||
* Gives a {@link MethodHandles.Lookup} instance to be used to find methods in server classes. | ||
* For lookups on application classes use {@link #getApplicationMethodHandleLookup(Class)} ()} instead. | ||
* </p> | ||
* <p> | ||
* This uses the caller sensitive {@link MethodHandles#lookup()}, this will allow MethodHandle access | ||
* to server classes we need to use and will give access permissions to private methods as well. | ||
* </p> | ||
* | ||
* @return | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To avoid duplicating these javadocs, I would rather So that if we improve the javadocs, we only do it in one place. Check that we can actually do this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can't be done, I think they will have to be duplicated. |
||
*/ | ||
public static MethodHandles.Lookup getServerMethodHandleLookup() | ||
{ | ||
return MethodHandles.publicLookup().in(endpointClass); | ||
return MethodHandles.lookup(); | ||
} | ||
|
||
/** | ||
* <p> | ||
* Gives a {@link MethodHandles.Lookup} instance to be used to find public methods in application classes. | ||
* For lookups on server classes use {@link #getServerMethodHandleLookup()} instead. | ||
* </p> | ||
* <p> | ||
* This uses {@link MethodHandles#publicLookup()} as we only need access to public method of the lookupClass. | ||
* To look up a method on the lookupClass, it must be public and the class must be accessible from this | ||
* module, so if the lookupClass is in a JPMS module it must be exported so that the public methods | ||
* of the lookupClass are accessible outside of the module. | ||
* </p> | ||
* <p> | ||
* The {@link java.lang.invoke.MethodHandles.Lookup#in(Class)} allows us to search specifically | ||
* in the endpoint Class to avoid any potential linkage errors which could occur if the same | ||
* class is present in multiple web apps. Unlike using {@link MethodHandles#publicLookup()} | ||
* using {@link MethodHandles#lookup()} with {@link java.lang.invoke.MethodHandles.Lookup#in(Class)} | ||
* will cause the lookup to lose its public access to the lookup class if they are in different modules. | ||
* </p> | ||
* <p> | ||
* {@link MethodHandles#privateLookupIn(Class, MethodHandles.Lookup)} is also unsuitable because it | ||
* requires the caller module to read the target module, and the target module to open reflective | ||
* access to the lookupClasses private methods. This is possible but requires extra configuration | ||
* to provide private access which is not necessary for the purpose of accessing the public methods. | ||
* </p> | ||
* @param lookupClass the desired lookup class for the new lookup object. | ||
* @return a lookup object to be used to find methods on the lookupClass. | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto. |
||
public static MethodHandles.Lookup getApplicationMethodHandleLookup(Class<?> lookupClass) | ||
{ | ||
return MethodHandles.publicLookup().in(lookupClass); | ||
} | ||
|
||
@Override | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you still need the TODO above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove it, I don't know why we would want to do this in the container, it seems better to contain the MethodHandle stuff in the FrameHandler.