467246 - Support javax.websocket version 1.1

WIP
This commit is contained in:
Joakim Erdfelt 2016-02-13 07:29:04 -07:00
parent 39f1d7332c
commit d60d6363b4
23 changed files with 742 additions and 217 deletions

View File

@ -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

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -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}

View File

@ -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;
/**

View File

@ -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

View File

@ -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());
}

View File

@ -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;
/**

View File

@ -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

View File

@ -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}

View File

@ -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}

View File

@ -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}

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
};
}
}

View File

@ -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);
}
};
}
}

View File

@ -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>"));
}
}

View File

@ -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>"));
}
}