parent
3906f9595f
commit
cbf8c971aa
|
@ -28,8 +28,8 @@ import javax.websocket.Session;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* javax.websocket {@link OnMessage} method {@link Function} for BINARY/byte[] types
|
||||
|
|
|
@ -29,8 +29,8 @@ import javax.websocket.Session;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* javax.websocket {@link OnMessage} method {@link Function} for BINARY/{@link ByteBuffer} types
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.eclipse.jetty.websocket.api.WebSocketException;
|
|||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* javax.websocket {@link OnClose} method {@link Function}
|
||||
|
|
|
@ -29,8 +29,8 @@ import javax.websocket.Session;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* javax.websocket {@link OnMessage} method {@link Function} for BINARY/{@link InputStream} streaming
|
||||
|
|
|
@ -28,8 +28,8 @@ import javax.websocket.Session;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* javax.websocket {@link OnOpen} method {@link Function}
|
||||
|
|
|
@ -29,7 +29,7 @@ import javax.websocket.Session;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,8 +28,8 @@ import javax.websocket.Session;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* javax.websocket {@link OnMessage} method {@link Function} for TEXT/{@link String} types
|
||||
|
|
|
@ -35,17 +35,13 @@ public class InvalidSignatureException extends InvalidWebSocketException
|
|||
err.append(method);
|
||||
err.append(System.lineSeparator());
|
||||
|
||||
err.append("Acceptable method declarations for @");
|
||||
err.append("Acceptable #").append(method.getName());
|
||||
err.append("() argument declarations for @");
|
||||
err.append(annoClass.getSimpleName());
|
||||
err.append(" are:");
|
||||
for (DynamicArgs.Builder argsBuilder : dynArgsBuilders)
|
||||
{
|
||||
for (DynamicArgs.Signature signature : argsBuilder.getSignatures())
|
||||
{
|
||||
err.append(System.lineSeparator());
|
||||
err.append("public void ").append(method.getName());
|
||||
signature.appendDescription(err);
|
||||
}
|
||||
argsBuilder.appendDescription(err);
|
||||
}
|
||||
return new InvalidSignatureException(err.toString());
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
|||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
|||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* Jetty {@link WebSocket} {@link OnWebSocketMessage} method {@link Function} for BINARY/{@link ByteBuffer} types
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
|||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* Jetty {@link WebSocket} {@link OnWebSocketClose} method {@link Function}
|
||||
|
|
|
@ -28,8 +28,8 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
|||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* Jetty {@link WebSocket} {@link OnWebSocketError} method {@link Function}
|
||||
|
|
|
@ -30,8 +30,8 @@ import org.eclipse.jetty.websocket.api.extensions.Frame;
|
|||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* Jetty {@link WebSocket} {@link OnWebSocketFrame} method {@link Function}
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
|||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* Jetty {@link WebSocket} {@link OnWebSocketMessage} method {@link Function} for BINARY/{@link InputStream} streaming
|
||||
|
|
|
@ -28,8 +28,8 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
|||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* Jetty {@link WebSocket} {@link OnWebSocketConnect} method {@link Function}
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
|||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* Jetty {@link WebSocket} {@link OnWebSocketMessage} method {@link Function} for TEXT/{@link Reader} streaming types
|
||||
|
|
|
@ -28,8 +28,8 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
|||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.common.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs;
|
||||
import org.eclipse.jetty.websocket.common.util.ExactSignature;
|
||||
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.ExactSignature;
|
||||
|
||||
/**
|
||||
* Jetty {@link WebSocket} {@link OnWebSocketMessage} method {@link Function} for TEXT/{@link String} types
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.util;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Provide argument utilities for working with methods that
|
||||
|
@ -29,184 +32,53 @@ import java.util.List;
|
|||
* <li>Can identify a set of parameters as matching the Builder</li>
|
||||
* <li>Can create a DynamicArgs for the matched signature</li>
|
||||
* <li>Can create an argument array for the provided potential arguments,
|
||||
* suitable to be used with {@link Method#invoke(Object, Object...)}</li>
|
||||
* suitable to be used with {@link Method#invoke(Object, Object...)}</li>
|
||||
* </ol>
|
||||
*/
|
||||
public class DynamicArgs
|
||||
{
|
||||
public static interface Signature
|
||||
{
|
||||
public boolean matches(Class<?>[] types);
|
||||
/**
|
||||
* Predicate to test if signature matches
|
||||
*
|
||||
* @return the predicate to test if signature matches
|
||||
*/
|
||||
public Predicate<Class<?>[]> getPredicate();
|
||||
|
||||
/**
|
||||
* BiFunction to use to invoke method
|
||||
* against give object, with provided (potential) arguments,
|
||||
* returning appropriate result from invocation.
|
||||
*
|
||||
* @param method
|
||||
* the method to base BiFunction off of.
|
||||
* @param callArgs
|
||||
* the description of arguments passed into each {@link DynamicArgs#invoke(Object, Object...)}
|
||||
* call in the future. Used to map the incoming arguments to the method arguments.
|
||||
* @return the return result of the invoked method
|
||||
*/
|
||||
public BiFunction<Object, Object[], Object> getInvoker(Method method, DynamicArgs.Arg... callArgs);
|
||||
|
||||
public void appendDescription(StringBuilder str);
|
||||
public Object[] toArgs(Object[] potentialArgs, int[] argReferences);
|
||||
}
|
||||
|
||||
public static class UnorderedSignature implements Signature
|
||||
{
|
||||
private final Class<?>[] validParams;
|
||||
private int[] validParamsIndex;
|
||||
|
||||
public UnorderedSignature(Class<?> ... classes)
|
||||
{
|
||||
this.validParams = classes;
|
||||
}
|
||||
|
||||
public UnorderedSignature indexedAs(int ... index)
|
||||
{
|
||||
this.validParamsIndex = index;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Class<?>[] getParams()
|
||||
{
|
||||
return validParams;
|
||||
}
|
||||
|
||||
public int[] getIndex()
|
||||
{
|
||||
return validParamsIndex;
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return validParams.length;
|
||||
}
|
||||
|
||||
public boolean matches(Class<?>[] types)
|
||||
{
|
||||
// Matches if the provided types
|
||||
// match the valid params in any order
|
||||
|
||||
if (types.length != validParams.length)
|
||||
return false;
|
||||
int len = validParams.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (!validParams[i].equals(types[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void appendDescription(StringBuilder str)
|
||||
{
|
||||
str.append('(');
|
||||
boolean delim = false;
|
||||
for (Class<?> type : validParams)
|
||||
{
|
||||
if (delim)
|
||||
{
|
||||
str.append(',');
|
||||
}
|
||||
str.append(' ');
|
||||
str.append(type.getName());
|
||||
if (type.isArray())
|
||||
{
|
||||
str.append("[]");
|
||||
}
|
||||
delim = true;
|
||||
}
|
||||
str.append(')');
|
||||
}
|
||||
|
||||
public Object[] toArgs(Object[] potentialArgs, int[] argReferences)
|
||||
{
|
||||
int slen = size();
|
||||
int plen = potentialArgs.length;
|
||||
Object args[] = new Object[slen];
|
||||
for (int sidx = 0; sidx < slen; sidx++)
|
||||
{
|
||||
int wantIdx = validParamsIndex[sidx];
|
||||
for (int argIdx = 0; argIdx < plen; argIdx++)
|
||||
{
|
||||
if (argReferences[argIdx] == wantIdx)
|
||||
args[sidx] = potentialArgs[argIdx];
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExactSignature implements Signature
|
||||
public static class Arg
|
||||
{
|
||||
private final Class<?>[] params;
|
||||
private int[] index;
|
||||
|
||||
public ExactSignature(Class<?> ... classes)
|
||||
public Arg(int idx, Class<?> type)
|
||||
{
|
||||
this.params = classes;
|
||||
this.index = idx;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ExactSignature indexedAs(int ... index)
|
||||
|
||||
public int index;
|
||||
public Class<?> type;
|
||||
public Object tag;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
this.index = index;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Class<?>[] getParams()
|
||||
{
|
||||
return params;
|
||||
}
|
||||
|
||||
public int[] getIndex()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return params.length;
|
||||
}
|
||||
|
||||
public boolean matches(Class<?>[] types)
|
||||
{
|
||||
if (types.length != params.length)
|
||||
return false;
|
||||
int len = params.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (!params[i].equals(types[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void appendDescription(StringBuilder str)
|
||||
{
|
||||
str.append('(');
|
||||
boolean delim = false;
|
||||
for (Class<?> type : params)
|
||||
{
|
||||
if (delim)
|
||||
{
|
||||
str.append(',');
|
||||
}
|
||||
str.append(' ');
|
||||
str.append(type.getName());
|
||||
if (type.isArray())
|
||||
{
|
||||
str.append("[]");
|
||||
}
|
||||
delim = true;
|
||||
}
|
||||
str.append(')');
|
||||
}
|
||||
|
||||
public Object[] toArgs(Object[] potentialArgs, int[] argReferences)
|
||||
{
|
||||
int slen = size();
|
||||
int plen = potentialArgs.length;
|
||||
Object args[] = new Object[slen];
|
||||
for (int sidx = 0; sidx < slen; sidx++)
|
||||
{
|
||||
int wantIdx = index[sidx];
|
||||
for (int argIdx = 0; argIdx < plen; argIdx++)
|
||||
{
|
||||
if (argReferences[argIdx] == wantIdx)
|
||||
args[sidx] = potentialArgs[argIdx];
|
||||
}
|
||||
}
|
||||
return args;
|
||||
return String.format("%s[%d%s]",type.getSimpleName(),index,tag == null ? "" : "/" + tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,60 +86,60 @@ public class DynamicArgs
|
|||
{
|
||||
private List<Signature> signatures = new ArrayList<>();
|
||||
|
||||
public DynamicArgs build(Method method)
|
||||
public DynamicArgs build(Method method, Arg... callArgs)
|
||||
{
|
||||
Class<?> paramTypes[] = method.getParameterTypes();
|
||||
for (Signature sig : signatures)
|
||||
{
|
||||
if (sig.matches(paramTypes))
|
||||
if (sig.getPredicate().test(paramTypes))
|
||||
{
|
||||
return new DynamicArgs(sig);
|
||||
return new DynamicArgs(sig.getInvoker(method,callArgs));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasMatchingSignature(Method method)
|
||||
{
|
||||
Class<?> paramTypes[] = method.getParameterTypes();
|
||||
for (Signature sig : signatures)
|
||||
{
|
||||
if (sig.matches(paramTypes))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Builder addSignature(Signature sig)
|
||||
{
|
||||
signatures.add(sig);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Signature> getSignatures()
|
||||
public void appendDescription(StringBuilder err)
|
||||
{
|
||||
return this.signatures;
|
||||
for (Signature sig : signatures)
|
||||
{
|
||||
err.append(System.lineSeparator());
|
||||
sig.appendDescription(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Signature signature;
|
||||
private int argReferences[];
|
||||
private final BiFunction<Object, Object[], Object> invoker;
|
||||
|
||||
public DynamicArgs(Signature sig)
|
||||
private DynamicArgs(BiFunction<Object, Object[], Object> invoker)
|
||||
{
|
||||
this.signature = sig;
|
||||
this.invoker = invoker;
|
||||
}
|
||||
|
||||
public void setArgReferences(int... argIndex)
|
||||
/**
|
||||
* Invoke the signature / method with the provided potential args.
|
||||
*
|
||||
* @param o
|
||||
* the object to call method on
|
||||
* @param potentialArgs
|
||||
* the potential args in the same order as the FIXME
|
||||
* @return the response object from the invoke
|
||||
* @throws IllegalAccessException
|
||||
* if unable to access the method or object
|
||||
* @throws IllegalArgumentException
|
||||
* if call to method has invalid/illegal arguments
|
||||
* @throws InvocationTargetException
|
||||
* if unable to invoke the method on the object
|
||||
*/
|
||||
public Object invoke(Object o, Object... potentialArgs) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
|
||||
{
|
||||
this.argReferences = argIndex;
|
||||
}
|
||||
|
||||
public Object[] toArgs(Object... potentialArgs)
|
||||
{
|
||||
return signature.toArgs(potentialArgs,argReferences);
|
||||
return invoker.apply(o,potentialArgs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.util;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class DynamicArgsException extends RuntimeException
|
||||
{
|
||||
public DynamicArgsException(String message, Throwable cause)
|
||||
{
|
||||
super(message,cause);
|
||||
}
|
||||
|
||||
public DynamicArgsException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.util;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Signature;
|
||||
|
||||
public class ExactSignature implements Signature, Predicate<Class<?>[]>
|
||||
{
|
||||
private final Arg[] params;
|
||||
|
||||
public ExactSignature(Arg... params)
|
||||
{
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<Class<?>[]> getPredicate()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Class<?>[] types)
|
||||
{
|
||||
if (types.length != params.length)
|
||||
return false;
|
||||
int len = params.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (!params[i].type.equals(types[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void appendDescription(StringBuilder str)
|
||||
{
|
||||
str.append('(');
|
||||
boolean delim = false;
|
||||
for (Arg arg : params)
|
||||
{
|
||||
if (delim)
|
||||
{
|
||||
str.append(',');
|
||||
}
|
||||
str.append(' ');
|
||||
str.append(arg.type.getName());
|
||||
if (arg.type.isArray())
|
||||
{
|
||||
str.append("[]");
|
||||
}
|
||||
delim = true;
|
||||
}
|
||||
str.append(')');
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiFunction<Object, Object[], Object> getInvoker(Method method, DynamicArgs.Arg... callArgs)
|
||||
{
|
||||
// Figure out mapping of calling args to method args
|
||||
Class<?> paramTypes[] = method.getParameterTypes();
|
||||
int paramTypesLength = paramTypes.length;
|
||||
|
||||
// Method argument array pointing to index in calling array
|
||||
int argMapping[] = new int[paramTypesLength];
|
||||
int callArgsLen = callArgs.length;
|
||||
|
||||
for (int mi = 0; mi < paramTypesLength; mi++)
|
||||
{
|
||||
int ref = -1;
|
||||
// Find reference to argument in callArgs
|
||||
for (int ci = 0; ci < callArgsLen; ci++)
|
||||
{
|
||||
if (callArgs[ci].index == params[mi].index)
|
||||
{
|
||||
ref = ci;
|
||||
}
|
||||
}
|
||||
if (ref < 0)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to map type [");
|
||||
err.append(params[mi]);
|
||||
err.append("] in method ");
|
||||
ReflectUtils.append(err,method);
|
||||
err.append(" to calling args: (");
|
||||
boolean delim = false;
|
||||
for (Arg arg : callArgs)
|
||||
{
|
||||
if (delim)
|
||||
err.append(", ");
|
||||
err.append(arg);
|
||||
delim = true;
|
||||
}
|
||||
err.append(")");
|
||||
|
||||
throw new DynamicArgsException(err.toString());
|
||||
}
|
||||
argMapping[mi] = ref;
|
||||
}
|
||||
|
||||
// Return function capable of calling method
|
||||
return (obj, potentialArgs) -> {
|
||||
Object args[] = new Object[paramTypesLength];
|
||||
for (int i = 0; i < paramTypesLength; i++)
|
||||
{
|
||||
args[i] = potentialArgs[argMapping[i]];
|
||||
}
|
||||
try
|
||||
{
|
||||
return method.invoke(obj,args);
|
||||
}
|
||||
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to call: ");
|
||||
ReflectUtils.append(err,obj.getClass(),method);
|
||||
err.append(" [with ");
|
||||
boolean delim = false;
|
||||
for (Object arg : args)
|
||||
{
|
||||
if (delim)
|
||||
err.append(", ");
|
||||
if (arg == null)
|
||||
{
|
||||
err.append("<null>");
|
||||
}
|
||||
else
|
||||
{
|
||||
err.append(arg.getClass().getSimpleName());
|
||||
}
|
||||
delim = true;
|
||||
}
|
||||
err.append("]");
|
||||
throw new DynamicArgsException(err.toString(),e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.util;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Signature;
|
||||
|
||||
public class UnorderedSignature implements Signature, Predicate<Class<?>[]>
|
||||
{
|
||||
private final Arg[] params;
|
||||
|
||||
public UnorderedSignature(Arg ... args)
|
||||
{
|
||||
this.params = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<Class<?>[]> getPredicate()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Class<?>[] types)
|
||||
{
|
||||
// Matches if the provided types
|
||||
// match the valid params in any order
|
||||
|
||||
int len = types.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
UnorderedSignature.Param p = findParam(types[i]);
|
||||
if (p == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void appendDescription(StringBuilder str)
|
||||
{
|
||||
str.append('(');
|
||||
boolean delim = false;
|
||||
for (Arg arg : params)
|
||||
{
|
||||
if (delim)
|
||||
{
|
||||
str.append(',');
|
||||
}
|
||||
str.append(' ');
|
||||
str.append(arg.type.getName());
|
||||
if (arg.type.isArray())
|
||||
{
|
||||
str.append("[]");
|
||||
}
|
||||
delim = true;
|
||||
}
|
||||
str.append(')');
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiFunction<Object, Object[], Object> getInvoker(Method method, Arg... callArgs)
|
||||
{
|
||||
// Figure out mapping of calling args to method args
|
||||
Class<?> paramTypes[] = method.getParameterTypes();
|
||||
int paramTypesLength = paramTypes.length;
|
||||
|
||||
// Method argument array pointing to index in calling array
|
||||
int argMapping[] = new int[paramTypesLength];
|
||||
int callArgsLen = callArgs.length;
|
||||
|
||||
for (int mi = 0; mi < paramTypesLength; mi++)
|
||||
{
|
||||
// TODO: ask optional ArgFunction to populate method.paramTypes[i] Arg
|
||||
// TODO: perhaps have this be loaded via ServiceLoader
|
||||
// TODO: jsr356 impl can find @PathParam and populate the Arg.tag entry
|
||||
|
||||
int ref = -1;
|
||||
// Find reference to argument in callArgs
|
||||
for (int ci = 0; ci < callArgsLen; ci++)
|
||||
{
|
||||
if (callArgs[ci].index == params[mi].index)
|
||||
{
|
||||
ref = ci;
|
||||
}
|
||||
}
|
||||
if (ref < 0)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to map type [");
|
||||
err.append(params[mi]);
|
||||
err.append("] in method ");
|
||||
ReflectUtils.append(err,method);
|
||||
err.append(" to calling args: (");
|
||||
boolean delim = false;
|
||||
for (Arg arg : callArgs)
|
||||
{
|
||||
if (delim)
|
||||
err.append(", ");
|
||||
err.append(arg);
|
||||
delim = true;
|
||||
}
|
||||
err.append(")");
|
||||
|
||||
throw new DynamicArgsException(err.toString());
|
||||
}
|
||||
argMapping[mi] = ref;
|
||||
}
|
||||
|
||||
// Return function capable of calling method
|
||||
return (obj, potentialArgs) -> {
|
||||
Object args[] = new Object[paramTypesLength];
|
||||
for (int i = 0; i < paramTypesLength; i++)
|
||||
{
|
||||
args[i] = potentialArgs[argMapping[i]];
|
||||
}
|
||||
try
|
||||
{
|
||||
return method.invoke(obj,args);
|
||||
}
|
||||
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to call: ");
|
||||
ReflectUtils.append(err,obj.getClass(),method);
|
||||
err.append(" [with ");
|
||||
boolean delim = false;
|
||||
for (Object arg : args)
|
||||
{
|
||||
if (delim)
|
||||
err.append(", ");
|
||||
if (arg == null)
|
||||
{
|
||||
err.append("<null>");
|
||||
}
|
||||
else
|
||||
{
|
||||
err.append(arg.getClass().getSimpleName());
|
||||
}
|
||||
delim = true;
|
||||
}
|
||||
err.append("]");
|
||||
throw new DynamicArgsException(err.toString(),e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.util;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.util.DynamicArgs.Arg;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExactSignatureTest
|
||||
{
|
||||
public static class SampleSignatures
|
||||
{
|
||||
public String sigEmpty()
|
||||
{
|
||||
return "sigEmpty<>";
|
||||
}
|
||||
|
||||
public String sigStr(String str)
|
||||
{
|
||||
return String.format("sigStr<%s>",str);
|
||||
}
|
||||
|
||||
public String sigByteArray(byte[] buf, int offset, int len)
|
||||
{
|
||||
return String.format("sigByteArray<%s,%d,%d>",buf == null ? "<null>" : ("[" + buf.length + "]"),offset,len);
|
||||
}
|
||||
}
|
||||
|
||||
public static Method findMethodByName(Object obj, String name)
|
||||
{
|
||||
for (Method method : obj.getClass().getMethods())
|
||||
{
|
||||
if (method.getName().equals(name))
|
||||
{
|
||||
return method;
|
||||
}
|
||||
}
|
||||
throw new AssertionError("Unable to find method: " + name);
|
||||
}
|
||||
|
||||
private static final Arg ARG_STR = new Arg(1,String.class);
|
||||
private static final Arg ARG_BOOL = new Arg(2,Boolean.class);
|
||||
private static final Arg ARG_FILE = new Arg(3,File.class);
|
||||
private static final Arg ARG_BYTEARRAY = new Arg(4,byte[].class);
|
||||
private static final Arg ARG_OFFSET = new Arg(5,int.class);
|
||||
private static final Arg ARG_LEN = new Arg(6,int.class);
|
||||
|
||||
@Test
|
||||
public void testEmptySignature() throws Exception
|
||||
{
|
||||
DynamicArgs.Builder dab = new DynamicArgs.Builder();
|
||||
dab.addSignature(new ExactSignature());
|
||||
|
||||
SampleSignatures ssigs = new SampleSignatures();
|
||||
Method m = findMethodByName(ssigs, "sigEmpty");
|
||||
DynamicArgs dargs = dab.build(m,ARG_STR,ARG_BOOL,ARG_FILE);
|
||||
assertThat("DynamicArgs", dargs, notNullValue());
|
||||
|
||||
// Test with potential args
|
||||
String result = (String)dargs.invoke(ssigs,"Hello", Boolean.TRUE, new File("bar"));
|
||||
assertThat("result", result, is("sigEmpty<>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringSignature() throws Exception
|
||||
{
|
||||
DynamicArgs.Builder dab = new DynamicArgs.Builder();
|
||||
dab.addSignature(new ExactSignature(ARG_STR));
|
||||
|
||||
SampleSignatures ssigs = new SampleSignatures();
|
||||
Method m = findMethodByName(ssigs, "sigStr");
|
||||
DynamicArgs dargs = dab.build(m,ARG_STR,ARG_BOOL,ARG_FILE);
|
||||
assertThat("DynamicArgs", dargs, notNullValue());
|
||||
|
||||
// Test with potential args
|
||||
String result = (String)dargs.invoke(ssigs,"Hello", Boolean.TRUE, new File("bar"));
|
||||
assertThat("result", result, is("sigStr<Hello>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByteArraySignature() throws Exception
|
||||
{
|
||||
DynamicArgs.Builder dab = new DynamicArgs.Builder();
|
||||
dab.addSignature(new ExactSignature(ARG_BYTEARRAY,ARG_OFFSET,ARG_LEN));
|
||||
|
||||
SampleSignatures ssigs = new SampleSignatures();
|
||||
Method m = findMethodByName(ssigs, "sigByteArray");
|
||||
DynamicArgs dargs = dab.build(m,ARG_BYTEARRAY,ARG_OFFSET,ARG_LEN);
|
||||
assertThat("DynamicArgs", dargs, notNullValue());
|
||||
|
||||
// Test with potential args
|
||||
byte buf[] = new byte[222];
|
||||
int offset = 3;
|
||||
int len = 44;
|
||||
String result = (String)dargs.invoke(ssigs,buf,offset,len);
|
||||
assertThat("result", result, is("sigByteArray<[222],3,44>"));
|
||||
|
||||
// Test with empty potential args
|
||||
result = (String)dargs.invoke(ssigs,null,123,456);
|
||||
assertThat("result", result, is("sigByteArray<<null>,123,456>"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.util;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class UnorderedSignatureTest
|
||||
{
|
||||
public static class SampleSignatures
|
||||
{
|
||||
public String sigEmpty()
|
||||
{
|
||||
return "sigEmpty<>";
|
||||
}
|
||||
|
||||
public String sigStr(String str)
|
||||
{
|
||||
return String.format("sigStr<%s>",str);
|
||||
}
|
||||
|
||||
public String sigStrFile(String str, File foo)
|
||||
{
|
||||
return String.format("sigStrFile<%s,%s>",str,foo);
|
||||
}
|
||||
|
||||
public String sigFileStr(File foo, String str)
|
||||
{
|
||||
return String.format("sigFileStr<%s,%s>",foo,str);
|
||||
}
|
||||
|
||||
public String sigFileStrFin(File foo, String str, boolean fin)
|
||||
{
|
||||
return String.format("sigFileStrFin<%s,%s,%b>",foo,str,fin);
|
||||
}
|
||||
|
||||
public String sigByteArray(byte[] buf, int offset, int len)
|
||||
{
|
||||
return String.format("sigByteArray<%s,%d,%d>",buf == null ? "<null>" : ("[" + buf.length + "]"),offset,len);
|
||||
}
|
||||
}
|
||||
|
||||
public static Method findMethodByName(Object obj, String name)
|
||||
{
|
||||
for (Method method : obj.getClass().getMethods())
|
||||
{
|
||||
if (method.getName().equals(name))
|
||||
{
|
||||
return method;
|
||||
}
|
||||
}
|
||||
throw new AssertionError("Unable to find method: " + name);
|
||||
}
|
||||
|
||||
private static final int ROLE_STR = 1;
|
||||
private static final int ROLE_BOOL = 2;
|
||||
private static final int ROLE_FILE = 3;
|
||||
private static final int ROLE_BYTEARRAY = 4;
|
||||
private static final int ROLE_OFFSET = 5;
|
||||
private static final int ROLE_LEN = 6;
|
||||
private static final int ROLE_FIN = 7;
|
||||
|
||||
@Test
|
||||
public void testEmptySignature() throws Exception
|
||||
{
|
||||
DynamicArgs.Builder<String> dab = new DynamicArgs.Builder<>();
|
||||
dab.addSignature(new UnorderedSignature()
|
||||
.addParam(String.class,ROLE_STR)
|
||||
.addParam(File.class,ROLE_FILE)
|
||||
.addParam(Boolean.class,ROLE_FIN));
|
||||
|
||||
SampleSignatures ssigs = new SampleSignatures();
|
||||
Method m = findMethodByName(ssigs, "sigEmpty");
|
||||
DynamicArgs dargs = dab.build(m);
|
||||
assertThat("DynamicArgs", dargs, notNullValue());
|
||||
dargs.setArgReferences(ROLE_STR,ROLE_BOOL,ROLE_FILE);
|
||||
|
||||
// Test with potential args
|
||||
Object args[] = dargs.toArgs("Hello", Boolean.TRUE, new File("bar"));
|
||||
|
||||
String result = (String)m.invoke(ssigs,args);
|
||||
assertThat("result", result, is("sigEmpty<>"));
|
||||
|
||||
// Test with empty potential args
|
||||
args = dargs.toArgs();
|
||||
|
||||
result = (String)m.invoke(ssigs,args);
|
||||
assertThat("result", result, is("sigEmpty<>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringSignature() throws Exception
|
||||
{
|
||||
DynamicArgs.Builder dab = new DynamicArgs.Builder();
|
||||
dab.addSignature(new UnorderedSignature()
|
||||
.addParam(String.class,ROLE_STR)
|
||||
.addParam(File.class,ROLE_FILE)
|
||||
.addParam(Boolean.class,ROLE_FIN));
|
||||
|
||||
SampleSignatures ssigs = new SampleSignatures();
|
||||
Method m = findMethodByName(ssigs, "sigStr");
|
||||
DynamicArgs dargs = dab.build(m);
|
||||
assertThat("DynamicArgs", dargs, notNullValue());
|
||||
dargs.setArgReferences(ROLE_STR,ROLE_BOOL,ROLE_FILE);
|
||||
|
||||
// Test with potential args
|
||||
Object args[] = dargs.toArgs("Hello", Boolean.TRUE, new File("bar"));
|
||||
|
||||
String result = (String)m.invoke(ssigs,args);
|
||||
assertThat("result", result, is("sigStr<Hello>"));
|
||||
|
||||
// Test with empty potential args
|
||||
args = dargs.toArgs();
|
||||
|
||||
result = (String)m.invoke(ssigs,args);
|
||||
assertThat("result", result, is("sigStr<null>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByteArraySignature() throws Exception
|
||||
{
|
||||
DynamicArgs.Builder dab = new DynamicArgs.Builder();
|
||||
dab.addSignature(new UnorderedSignature()
|
||||
.addParam(String.class,ROLE_STR)
|
||||
.addParam(File.class,ROLE_FILE)
|
||||
.addParam(Boolean.class,ROLE_FIN));
|
||||
|
||||
SampleSignatures ssigs = new SampleSignatures();
|
||||
Method m = findMethodByName(ssigs, "sigByteArray");
|
||||
DynamicArgs dargs = dab.build(m);
|
||||
assertThat("DynamicArgs", dargs, notNullValue());
|
||||
dargs.setArgReferences(ROLE_BYTEARRAY,ROLE_OFFSET,ROLE_LEN);
|
||||
|
||||
// Test with potential args
|
||||
byte buf[] = new byte[222];
|
||||
int offset = 3;
|
||||
int len = 44;
|
||||
String result = (String)dargs.invoke(m,ssigs,buf,offset,len);
|
||||
assertThat("result", result, is("sigByteArray<[222],3,44>"));
|
||||
|
||||
// Test with empty potential args
|
||||
result = (String)dargs.invoke(m,ssigs,null,123,456);
|
||||
assertThat("result", result, is("sigByteArray<<null>,123,456>"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue