Merge pull request #4694 from eclipse/jetty-10.0.x-4691-consistent_methodhandles_lookup
Issue #4691 - use static methods with javadoc to get MethodHandle lookups
This commit is contained in:
commit
ea80253cca
|
@ -373,8 +373,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
|||
{
|
||||
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);
|
||||
|
@ -431,8 +430,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
|||
{
|
||||
try
|
||||
{
|
||||
// TODO: move MethodHandle lookup to container?
|
||||
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
|
||||
MethodHandles.Lookup lookup = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup();
|
||||
MethodHandle wholeMsgMethodHandle = lookup.findVirtual(MessageHandler.Whole.class, "onMessage", MethodType.methodType(void.class, Object.class));
|
||||
wholeMsgMethodHandle = wholeMsgMethodHandle.bindTo(handler);
|
||||
|
||||
|
|
|
@ -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 abstract class JavaxWebSocketFrameHandlerFactory
|
|||
|
||||
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 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
|||
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 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
|||
|
||||
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 @@ public abstract class JavaxWebSocketFrameHandlerFactory
|
|||
}
|
||||
}
|
||||
|
||||
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 a lookup object to be used to find methods on server classes.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public static MethodHandles.Lookup getApplicationMethodHandleLookup(Class<?> lookupClass)
|
||||
{
|
||||
return MethodHandles.publicLookup().in(lookupClass);
|
||||
}
|
||||
|
||||
private static class DecodedArgs
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.eclipse.jetty.websocket.javax.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.ByteBuffer;
|
||||
import javax.websocket.CloseReason;
|
||||
|
@ -28,6 +27,7 @@ import javax.websocket.Decoder;
|
|||
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.util.messages.ByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class DecodedBinaryMessageSink<T> extends DecodedMessageSink<Decoder.Bina
|
|||
@Override
|
||||
protected MethodHandle newRawMethodHandle() throws NoSuchMethodException, IllegalAccessException
|
||||
{
|
||||
return MethodHandles.lookup().findVirtual(DecodedBinaryMessageSink.class,
|
||||
return JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedBinaryMessageSink.class,
|
||||
"onWholeMessage", MethodType.methodType(void.class, ByteBuffer.class))
|
||||
.bindTo(this);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.websocket.javax.common.messages;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.DecodeException;
|
||||
|
@ -28,6 +27,7 @@ import javax.websocket.Decoder;
|
|||
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.util.messages.InputStreamMessageSink;
|
||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class DecodedBinaryStreamMessageSink<T> extends DecodedMessageSink<Decode
|
|||
@Override
|
||||
protected MethodHandle newRawMethodHandle() throws NoSuchMethodException, IllegalAccessException
|
||||
{
|
||||
return MethodHandles.lookup().findVirtual(DecodedBinaryStreamMessageSink.class,
|
||||
return JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedBinaryStreamMessageSink.class,
|
||||
"onStreamStart", MethodType.methodType(void.class, InputStream.class))
|
||||
.bindTo(this);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.eclipse.jetty.websocket.javax.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.DecodeException;
|
||||
|
@ -27,6 +26,7 @@ import javax.websocket.Decoder;
|
|||
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.util.messages.StringMessageSink;
|
||||
|
||||
|
@ -43,7 +43,7 @@ public class DecodedTextMessageSink<T> extends DecodedMessageSink<Decoder.Text<T
|
|||
@Override
|
||||
protected MethodHandle newRawMethodHandle() throws NoSuchMethodException, IllegalAccessException
|
||||
{
|
||||
return MethodHandles.lookup().findVirtual(DecodedTextMessageSink.class,
|
||||
return JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedTextMessageSink.class,
|
||||
"onWholeMessage", MethodType.methodType(void.class, String.class))
|
||||
.bindTo(this);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.websocket.javax.common.messages;
|
|||
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.DecodeException;
|
||||
|
@ -28,6 +27,7 @@ import javax.websocket.Decoder;
|
|||
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.util.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.util.messages.ReaderMessageSink;
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class DecodedTextStreamMessageSink<T> extends DecodedMessageSink<Decoder.
|
|||
@Override
|
||||
protected MethodHandle newRawMethodHandle() throws NoSuchMethodException, IllegalAccessException
|
||||
{
|
||||
return MethodHandles.lookup().findVirtual(DecodedTextStreamMessageSink.class,
|
||||
return JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(DecodedTextStreamMessageSink.class,
|
||||
"onStreamStart", MethodType.methodType(void.class, Reader.class))
|
||||
.bindTo(this);
|
||||
}
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
package org.eclipse.jetty.websocket.javax.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jetty.websocket.javax.common.AbstractSessionTest;
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||
|
||||
public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
|||
Class<?> refc = copy.getClass();
|
||||
String name = "accept";
|
||||
MethodType methodType = MethodType.methodType(void.class, type);
|
||||
MethodHandle handle = MethodHandles.lookup().findVirtual(refc, name, methodType);
|
||||
MethodHandle handle = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(refc, name, methodType);
|
||||
return handle.bindTo(copy);
|
||||
}
|
||||
catch (NoSuchMethodException | IllegalAccessException e)
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.lang.invoke.MethodHandles;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.util.ReflectUtils;
|
||||
|
||||
|
@ -31,7 +32,8 @@ public class CompletableFutureMethodHandle
|
|||
public static <T> MethodHandle of(Class<T> type, CompletableFuture<T> future)
|
||||
{
|
||||
Method method = ReflectUtils.findMethod(CompletableFuture.class, "complete", type);
|
||||
MethodHandle completeHandle = InvokerUtils.mutatedInvoker(MethodHandles.lookup(), CompletableFuture.class, method, new InvokerUtils.Arg(type));
|
||||
MethodHandles.Lookup lookup = JavaxWebSocketFrameHandlerFactory.getServerMethodHandleLookup();
|
||||
MethodHandle completeHandle = InvokerUtils.mutatedInvoker(lookup, CompletableFuture.class, method, new InvokerUtils.Arg(type));
|
||||
return completeHandle.bindTo(future);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,7 +157,8 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
|
||||
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 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
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 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
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 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
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 a lookup object to be used to find methods on server classes.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public static MethodHandles.Lookup getApplicationMethodHandleLookup(Class<?> lookupClass)
|
||||
{
|
||||
return MethodHandles.publicLookup().in(lookupClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,7 +52,7 @@ public class OutgoingMessageCapture extends CoreSession.Empty implements CoreSes
|
|||
|
||||
public OutgoingMessageCapture()
|
||||
{
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
MethodHandles.Lookup lookup = JettyWebSocketFrameHandlerFactory.getApplicationMethodHandleLookup(this.getClass());
|
||||
try
|
||||
{
|
||||
MethodHandle text = lookup.findVirtual(this.getClass(), "onWholeText", MethodType.methodType(Void.TYPE, String.class));
|
||||
|
|
Loading…
Reference in New Issue