Fixes #4550 XmlConfiguration named parameters
Fixed #4550 named parameters with a moderate refactor. The named parameter matching was duplicated, only considering number of args and not applied to call arguments. This refactor puts all the behaviour in common methods and reorders the arguments to match parameters. Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
parent
13458ab515
commit
d27f4ee556
|
@ -24,6 +24,7 @@ import java.io.StringReader;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Executable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -37,11 +38,11 @@ import java.nio.file.Paths;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -51,7 +52,6 @@ import java.util.Queue;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.ArrayUtil;
|
|
||||||
import org.eclipse.jetty.util.LazyList;
|
import org.eclipse.jetty.util.LazyList;
|
||||||
import org.eclipse.jetty.util.Loader;
|
import org.eclipse.jetty.util.Loader;
|
||||||
import org.eclipse.jetty.util.MultiException;
|
import org.eclipse.jetty.util.MultiException;
|
||||||
|
@ -412,39 +412,13 @@ public class XmlConfiguration
|
||||||
int index = 0;
|
int index = 0;
|
||||||
if (obj == null && oClass != null)
|
if (obj == null && oClass != null)
|
||||||
{
|
{
|
||||||
index = _root.size();
|
|
||||||
Map<String, Object> namedArgMap = new HashMap<>();
|
|
||||||
|
|
||||||
List<Object> arguments = new LinkedList<>();
|
|
||||||
for (int i = 0; i < _root.size(); i++)
|
|
||||||
{
|
|
||||||
Object o = _root.get(i);
|
|
||||||
if (o instanceof String)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
XmlParser.Node node = (XmlParser.Node)o;
|
|
||||||
if (node.getTag().equals("Arg"))
|
|
||||||
{
|
|
||||||
String namedAttribute = node.getAttribute("name");
|
|
||||||
Object value = value(null, (XmlParser.Node)o);
|
|
||||||
if (namedAttribute != null)
|
|
||||||
namedArgMap.put(namedAttribute, value);
|
|
||||||
arguments.add(value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
obj = construct(oClass, arguments.toArray(), namedArgMap);
|
obj = construct(oClass, new NamedArgs(null, XmlConfiguration.getNodes(_root, "Arg")));
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException x)
|
catch (NoSuchMethodException x)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException(String.format("No constructor %s(%s,%s) in %s", oClass, arguments, namedArgMap, _configuration));
|
throw new IllegalStateException(String.format("No maatching constructor %s in %s", oClass, _configuration));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (id != null)
|
if (id != null)
|
||||||
|
@ -916,7 +890,6 @@ public class XmlConfiguration
|
||||||
String id = aoeNode.getString("Id");
|
String id = aoeNode.getString("Id");
|
||||||
String name = aoeNode.getString("Name");
|
String name = aoeNode.getString("Name");
|
||||||
String clazz = aoeNode.getString("Class");
|
String clazz = aoeNode.getString("Class");
|
||||||
List<Object> args = aoeNode.getList("Arg");
|
|
||||||
|
|
||||||
Class<?> oClass;
|
Class<?> oClass;
|
||||||
if (clazz != null)
|
if (clazz != null)
|
||||||
|
@ -937,7 +910,7 @@ public class XmlConfiguration
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Object nobj = call(oClass, name, obj, args.toArray(new Object[0]));
|
Object nobj = call(oClass, name, obj, new NamedArgs(obj, aoeNode.getNodes("Arg")));
|
||||||
if (id != null)
|
if (id != null)
|
||||||
_configuration.getIdMap().put(id, nobj);
|
_configuration.getIdMap().put(id, nobj);
|
||||||
configure(nobj, node, aoeNode.getNext());
|
configure(nobj, node, aoeNode.getNext());
|
||||||
|
@ -949,7 +922,7 @@ public class XmlConfiguration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object call(Class<?> oClass, String methodName, Object obj, Object[] arg) throws InvocationTargetException, NoSuchMethodException
|
private Object call(Class<?> oClass, String methodName, Object obj, NamedArgs args) throws InvocationTargetException, NoSuchMethodException
|
||||||
{
|
{
|
||||||
Objects.requireNonNull(oClass, "Class cannot be null");
|
Objects.requireNonNull(oClass, "Class cannot be null");
|
||||||
Objects.requireNonNull(methodName, "Method name cannot be null");
|
Objects.requireNonNull(methodName, "Method name cannot be null");
|
||||||
|
@ -961,7 +934,8 @@ public class XmlConfiguration
|
||||||
{
|
{
|
||||||
if (!method.getName().equals(methodName))
|
if (!method.getName().equals(methodName))
|
||||||
continue;
|
continue;
|
||||||
if (method.getParameterCount() != arg.length)
|
Object[] arguments = args.applyTo(method);
|
||||||
|
if (arguments == null)
|
||||||
continue;
|
continue;
|
||||||
if (Modifier.isStatic(method.getModifiers()) != (obj == null))
|
if (Modifier.isStatic(method.getModifiers()) != (obj == null))
|
||||||
continue;
|
continue;
|
||||||
|
@ -970,34 +944,7 @@ public class XmlConfiguration
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return invokeMethod(method, obj, arg);
|
return invokeMethod(method, obj, arguments);
|
||||||
}
|
|
||||||
catch (IllegalAccessException | IllegalArgumentException e)
|
|
||||||
{
|
|
||||||
LOG.ignore(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lets look for a method with varargs arguments
|
|
||||||
Object[] argsWithVarargs = null;
|
|
||||||
for (Method method : oClass.getMethods())
|
|
||||||
{
|
|
||||||
if (!method.getName().equals(methodName))
|
|
||||||
continue;
|
|
||||||
if (method.getParameterCount() != arg.length + 1)
|
|
||||||
continue;
|
|
||||||
if (!method.getParameterTypes()[arg.length].isArray())
|
|
||||||
continue;
|
|
||||||
if (Modifier.isStatic(method.getModifiers()) != (obj == null))
|
|
||||||
continue;
|
|
||||||
if ((obj == null) && method.getDeclaringClass() != oClass)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (argsWithVarargs == null)
|
|
||||||
argsWithVarargs = ArrayUtil.addToArray(arg, new Object[0], Object.class);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return invokeMethod(method, obj, argsWithVarargs);
|
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException | IllegalArgumentException e)
|
catch (IllegalAccessException | IllegalArgumentException e)
|
||||||
{
|
{
|
||||||
|
@ -1020,33 +967,16 @@ public class XmlConfiguration
|
||||||
AttrOrElementNode aoeNode = new AttrOrElementNode(obj, node, "Id", "Class", "Arg");
|
AttrOrElementNode aoeNode = new AttrOrElementNode(obj, node, "Id", "Class", "Arg");
|
||||||
String id = aoeNode.getString("Id");
|
String id = aoeNode.getString("Id");
|
||||||
String clazz = aoeNode.getString("Class");
|
String clazz = aoeNode.getString("Class");
|
||||||
List<XmlParser.Node> argNodes = aoeNode.getNodes("Arg");
|
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("XML new " + clazz);
|
LOG.debug("XML new " + clazz);
|
||||||
|
|
||||||
Class<?> oClass = Loader.loadClass(clazz);
|
Class<?> oClass = Loader.loadClass(clazz);
|
||||||
|
|
||||||
// Find the <Arg> elements
|
|
||||||
Map<String, Object> namedArgMap = new HashMap<>();
|
|
||||||
List<Object> arguments = new LinkedList<>();
|
|
||||||
for (XmlParser.Node child : argNodes)
|
|
||||||
{
|
|
||||||
String namedAttribute = child.getAttribute("name");
|
|
||||||
Object value = value(obj, child);
|
|
||||||
if (namedAttribute != null)
|
|
||||||
{
|
|
||||||
// named arguments
|
|
||||||
namedArgMap.put(namedAttribute, value);
|
|
||||||
}
|
|
||||||
// raw arguments
|
|
||||||
arguments.add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object nobj;
|
Object nobj;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
nobj = construct(oClass, arguments.toArray(), namedArgMap);
|
nobj = construct(oClass, new NamedArgs(obj, aoeNode.getNodes("Arg")));
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e)
|
catch (NoSuchMethodException e)
|
||||||
{
|
{
|
||||||
|
@ -1061,81 +991,20 @@ public class XmlConfiguration
|
||||||
return nobj;
|
return nobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object construct(Class<?> klass, Object[] arguments, Map<String, Object> namedArgMap) throws InvocationTargetException, NoSuchMethodException
|
private Object construct(Class<?> klass, NamedArgs args) throws InvocationTargetException, NoSuchMethodException
|
||||||
{
|
{
|
||||||
Objects.requireNonNull(klass, "Class cannot be null");
|
Objects.requireNonNull(klass, "Class cannot be null");
|
||||||
Objects.requireNonNull(namedArgMap, "Named Argument Map cannot be null");
|
Objects.requireNonNull(args, "Named list cannot be null");
|
||||||
|
|
||||||
|
constructors:
|
||||||
for (Constructor<?> constructor : klass.getConstructors())
|
for (Constructor<?> constructor : klass.getConstructors())
|
||||||
{
|
{
|
||||||
if (arguments == null)
|
|
||||||
{
|
|
||||||
// null arguments in .newInstance() is allowed
|
|
||||||
if (constructor.getParameterCount() != 0)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (constructor.getParameterCount() != arguments.length)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (arguments == null || arguments.length == 0)
|
Object[] arguments = args.applyTo(constructor);
|
||||||
{
|
if (arguments != null)
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Invoking constructor, no arguments");
|
|
||||||
return invokeConstructor(constructor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (namedArgMap.isEmpty())
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Invoking constructor, no XML parameter mapping");
|
|
||||||
return invokeConstructor(constructor, arguments);
|
return invokeConstructor(constructor, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
|
|
||||||
if (parameterAnnotations == null || parameterAnnotations.length == 0)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Invoking constructor, no parameter annotations");
|
|
||||||
return invokeConstructor(constructor, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
Object[] swizzled = new Object[arguments.length];
|
|
||||||
for (Annotation[] annotations : parameterAnnotations)
|
|
||||||
{
|
|
||||||
for (Annotation annotation : annotations)
|
|
||||||
{
|
|
||||||
if (annotation instanceof Name)
|
|
||||||
{
|
|
||||||
Name param = (Name)annotation;
|
|
||||||
if (namedArgMap.containsKey(param.value()))
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Mapping named parameter {} in position {}", param.value(), count);
|
|
||||||
swizzled[count] = namedArgMap.get(param.value());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Mapping argument {} in position {}", arguments[count], count);
|
|
||||||
swizzled[count] = arguments[count];
|
|
||||||
}
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Skipping parameter annotated with {}", annotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return invokeConstructor(constructor, swizzled);
|
|
||||||
}
|
|
||||||
catch (InstantiationException | IllegalAccessException | IllegalArgumentException e)
|
catch (InstantiationException | IllegalAccessException | IllegalArgumentException e)
|
||||||
{
|
{
|
||||||
LOG.ignore(e);
|
LOG.ignore(e);
|
||||||
|
@ -1776,11 +1645,119 @@ public class XmlConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<XmlParser.Node> getNodes(String elementName)
|
public List<XmlParser.Node> getNodes(String elementName)
|
||||||
|
{
|
||||||
|
return XmlConfiguration.getNodes(_node, elementName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NamedArgs
|
||||||
|
{
|
||||||
|
final List<Object> _arguments;
|
||||||
|
final List<String> _names;
|
||||||
|
|
||||||
|
NamedArgs(Object obj, List<XmlParser.Node> args) throws Exception
|
||||||
|
{
|
||||||
|
_arguments = new ArrayList<>();
|
||||||
|
_names = new ArrayList<>();
|
||||||
|
for (XmlParser.Node child : args)
|
||||||
|
{
|
||||||
|
_arguments.add(value(obj, child));
|
||||||
|
_names.add(child.getAttribute("name"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedArgs(List<Object> arguments, List<String> names)
|
||||||
|
{
|
||||||
|
_arguments = arguments;
|
||||||
|
_names = names;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] applyTo(Executable executable)
|
||||||
|
{
|
||||||
|
Object[] args = matchArgsToParameters(executable);
|
||||||
|
if (args == null)
|
||||||
|
{
|
||||||
|
// Could this be an empty varargs match?
|
||||||
|
int count = executable.getParameterCount();
|
||||||
|
if (count > 0 && executable.getParameterTypes()[count - 1].isArray())
|
||||||
|
args = asEmptyVarArgs(executable.getParameterTypes()[count - 1]).matchArgsToParameters(executable);
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedArgs asEmptyVarArgs(Class<?> varArgType)
|
||||||
|
{
|
||||||
|
List<Object> arguments = new ArrayList<>(_arguments);
|
||||||
|
arguments.add(Array.newInstance(varArgType.getComponentType(), 0));
|
||||||
|
List<String> names = new ArrayList<>(_names);
|
||||||
|
names.add(null);
|
||||||
|
return new NamedArgs(arguments, names);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] matchArgsToParameters(Executable executable)
|
||||||
|
{
|
||||||
|
int count = executable.getParameterCount();
|
||||||
|
|
||||||
|
// No match of wrong number of parameters
|
||||||
|
if (count != _arguments.size())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Handle no parameter case
|
||||||
|
if (count == 0)
|
||||||
|
return new Object[0];
|
||||||
|
|
||||||
|
// If no arg names are specified, keep the arg order
|
||||||
|
if (_names.stream().noneMatch(Objects::nonNull))
|
||||||
|
return _arguments.toArray(new Object[0]);
|
||||||
|
|
||||||
|
// If we don't have any parameters with names, then no match
|
||||||
|
Annotation[][] parameterAnnotations = executable.getParameterAnnotations();
|
||||||
|
if (parameterAnnotations == null || parameterAnnotations.length == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Find the position of all named parameters from the executable
|
||||||
|
Map<String, Integer> position = new HashMap<>();
|
||||||
|
int p = 0;
|
||||||
|
for (Annotation[] paramAnnotation : parameterAnnotations)
|
||||||
|
{
|
||||||
|
Integer pos = p++;
|
||||||
|
Arrays.stream(paramAnnotation)
|
||||||
|
.filter(Name.class::isInstance)
|
||||||
|
.map(Name.class::cast)
|
||||||
|
.findFirst().ifPresent(n -> position.put(n.value(), pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Object> arguments = new ArrayList<>(_arguments);
|
||||||
|
List<String> names = new ArrayList<>(_names);
|
||||||
|
// Map the actual arguments to the names
|
||||||
|
for (p = 0; p < count; p++)
|
||||||
|
{
|
||||||
|
String name = names.get(p);
|
||||||
|
if (name != null)
|
||||||
|
{
|
||||||
|
Integer pos = position.get(name);
|
||||||
|
if (pos == null)
|
||||||
|
return null;
|
||||||
|
if (pos != p)
|
||||||
|
{
|
||||||
|
// adjust position of parameter
|
||||||
|
arguments.add(pos, arguments.remove(p));
|
||||||
|
names.add(pos, names.remove(p));
|
||||||
|
p = Math.min(p, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arguments.toArray(new Object[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<XmlParser.Node> getNodes(XmlParser.Node node, String elementName)
|
||||||
{
|
{
|
||||||
String attrName = StringUtil.asciiToLowerCase(elementName);
|
String attrName = StringUtil.asciiToLowerCase(elementName);
|
||||||
final List<XmlParser.Node> values = new ArrayList<>();
|
final List<XmlParser.Node> values = new ArrayList<>();
|
||||||
|
|
||||||
String attr = _node.getAttribute(attrName);
|
String attr = node.getAttribute(attrName);
|
||||||
if (attr != null)
|
if (attr != null)
|
||||||
{
|
{
|
||||||
for (String a : StringUtil.csvSplit(null, attr, 0, attr.length()))
|
for (String a : StringUtil.csvSplit(null, attr, 0, attr.length()))
|
||||||
|
@ -1792,9 +1769,9 @@ public class XmlConfiguration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < _next; i++)
|
for (int i = 0; i < node.size(); i++)
|
||||||
{
|
{
|
||||||
Object o = _node.get(i);
|
Object o = node.get(i);
|
||||||
if (!(o instanceof XmlParser.Node))
|
if (!(o instanceof XmlParser.Node))
|
||||||
continue;
|
continue;
|
||||||
XmlParser.Node n = (XmlParser.Node)o;
|
XmlParser.Node n = (XmlParser.Node)o;
|
||||||
|
@ -1810,8 +1787,6 @@ public class XmlConfiguration
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the XML configurations as a main application.
|
* Runs the XML configurations as a main application.
|
||||||
|
|
|
@ -41,6 +41,18 @@ public class AnnotatedTestConfiguration
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AnnotatedTestConfiguration(Integer test)
|
||||||
|
{
|
||||||
|
// exists to make constructor matching harder
|
||||||
|
throw new UnsupportedOperationException("Should not be called");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnnotatedTestConfiguration(Integer one, Integer two, Integer three)
|
||||||
|
{
|
||||||
|
// exists to make constructor matching harder
|
||||||
|
throw new UnsupportedOperationException("Should not be called");
|
||||||
|
}
|
||||||
|
|
||||||
public AnnotatedTestConfiguration(@Name("first") String first, @Name("second") String second, @Name("third") String third)
|
public AnnotatedTestConfiguration(@Name("first") String first, @Name("second") String second, @Name("third") String third)
|
||||||
{
|
{
|
||||||
this.first = first;
|
this.first = first;
|
||||||
|
@ -48,6 +60,38 @@ public class AnnotatedTestConfiguration
|
||||||
this.third = third;
|
this.third = third;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AnnotatedTestConfiguration(Long one, Long two, Long three)
|
||||||
|
{
|
||||||
|
// exists to make constructor matching harder
|
||||||
|
throw new UnsupportedOperationException("Should not be called");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAll(Integer one, Integer two, Integer three)
|
||||||
|
{
|
||||||
|
// exists to make method matching harder
|
||||||
|
throw new UnsupportedOperationException("Should not be called");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAll(@Name("first") String first, @Name("second") String second, @Name("third") String third)
|
||||||
|
{
|
||||||
|
this.first = first;
|
||||||
|
this.second = second;
|
||||||
|
this.third = third;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAll(long one, long two, long three)
|
||||||
|
{
|
||||||
|
// exists to make method matching harder
|
||||||
|
throw new UnsupportedOperationException("Should not be called");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVarArgs(String first, String... theRest)
|
||||||
|
{
|
||||||
|
this.first = first;
|
||||||
|
this.second = theRest.length > 0 ? theRest[0] : null;
|
||||||
|
this.third = theRest.length > 1 ? theRest[1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
public String getFirst()
|
public String getFirst()
|
||||||
{
|
{
|
||||||
return first;
|
return first;
|
||||||
|
|
|
@ -35,6 +35,7 @@ import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||||
|
@ -45,6 +46,11 @@ import org.eclipse.jetty.util.resource.PathResource;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.ArgumentsProvider;
|
||||||
|
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
@ -67,9 +73,17 @@ public class XmlConfigurationTest
|
||||||
{
|
{
|
||||||
public WorkDir workDir;
|
public WorkDir workDir;
|
||||||
|
|
||||||
protected String[] _configure = new String[]{
|
public static class ScenarioProvider implements ArgumentsProvider
|
||||||
"org/eclipse/jetty/xml/configureWithAttr.xml", "org/eclipse/jetty/xml/configureWithElements.xml"
|
{
|
||||||
};
|
@Override
|
||||||
|
public Stream<? extends Arguments> provideArguments(ExtensionContext context)
|
||||||
|
{
|
||||||
|
return Stream.of(
|
||||||
|
"org/eclipse/jetty/xml/configureWithAttr.xml",
|
||||||
|
"org/eclipse/jetty/xml/configureWithElements.xml"
|
||||||
|
).map(Arguments::of);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final String STRING_ARRAY_XML = "<Array type=\"String\"><Item type=\"String\">String1</Item><Item type=\"String\">String2</Item></Array>";
|
private static final String STRING_ARRAY_XML = "<Array type=\"String\"><Item type=\"String\">String1</Item><Item type=\"String\">String2</Item></Array>";
|
||||||
private static final String INT_ARRAY_XML = "<Array type=\"int\"><Item type=\"int\">1</Item><Item type=\"int\">2</Item></Array>";
|
private static final String INT_ARRAY_XML = "<Array type=\"int\"><Item type=\"int\">1</Item><Item type=\"int\">2</Item></Array>";
|
||||||
|
@ -82,10 +96,9 @@ public class XmlConfigurationTest
|
||||||
configuration.configure();
|
configuration.configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void testPassedObject() throws Exception
|
@ArgumentsSource(ScenarioProvider.class)
|
||||||
{
|
public void testPassedObject(String configure) throws Exception
|
||||||
for (String configure : _configure)
|
|
||||||
{
|
{
|
||||||
Map<String, String> properties = new HashMap<>();
|
Map<String, String> properties = new HashMap<>();
|
||||||
properties.put("whatever", "xxx");
|
properties.put("whatever", "xxx");
|
||||||
|
@ -156,12 +169,10 @@ public class XmlConfigurationTest
|
||||||
assertEquals(((Map<String, String>)configuration.getIdMap().get("map")).get("key0"), "value0");
|
assertEquals(((Map<String, String>)configuration.getIdMap().get("map")).get("key0"), "value0");
|
||||||
assertEquals(((Map<String, String>)configuration.getIdMap().get("map")).get("key1"), "value1");
|
assertEquals(((Map<String, String>)configuration.getIdMap().get("map")).get("key1"), "value1");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void testNewObject() throws Exception
|
@ArgumentsSource(ScenarioProvider.class)
|
||||||
{
|
public void testNewObject(String configure) throws Exception
|
||||||
for (String configure : _configure)
|
|
||||||
{
|
{
|
||||||
TestConfiguration.VALUE = 71;
|
TestConfiguration.VALUE = 71;
|
||||||
Map<String, String> properties = new HashMap<>();
|
Map<String, String> properties = new HashMap<>();
|
||||||
|
@ -246,7 +257,6 @@ public class XmlConfigurationTest
|
||||||
assertEquals(2, tc.testField2, "field to field");
|
assertEquals(2, tc.testField2, "field to field");
|
||||||
assertEquals(42, TestConfiguration.VALUE, "literal to static");
|
assertEquals(42, TestConfiguration.VALUE, "literal to static");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public XmlConfiguration asXmlConfiguration(String rawXml) throws IOException, SAXException
|
public XmlConfiguration asXmlConfiguration(String rawXml) throws IOException, SAXException
|
||||||
{
|
{
|
||||||
|
@ -648,6 +658,139 @@ public class XmlConfigurationTest
|
||||||
assertEquals("arg3", atc.getNested().getThird(), "nested third parameter not wired correctly");
|
assertEquals("arg3", atc.getNested().getThird(), "nested third parameter not wired correctly");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallNamedInjection() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Call name=\"setAll\">" +
|
||||||
|
" <Arg>arg1</Arg> " +
|
||||||
|
" <Arg>arg2</Arg> " +
|
||||||
|
" <Arg>arg3</Arg> " +
|
||||||
|
" </Call>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
assertEquals("arg1", atc.getFirst(), "first parameter not wired correctly");
|
||||||
|
assertEquals("arg2", atc.getSecond(), "second parameter not wired correctly");
|
||||||
|
assertEquals("arg3", atc.getThird(), "third parameter not wired correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallNamedInjectionOrdered() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Call name=\"setAll\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg name=\"second\">arg2</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" </Call>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
assertEquals("arg1", atc.getFirst(), "first parameter not wired correctly");
|
||||||
|
assertEquals("arg2", atc.getSecond(), "second parameter not wired correctly");
|
||||||
|
assertEquals("arg3", atc.getThird(), "third parameter not wired correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallNamedInjectionUnOrdered() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Call name=\"setAll\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" <Arg name=\"second\">arg2</Arg> " +
|
||||||
|
" </Call>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
assertEquals("arg1", atc.getFirst(), "first parameter not wired correctly");
|
||||||
|
assertEquals("arg2", atc.getSecond(), "second parameter not wired correctly");
|
||||||
|
assertEquals("arg3", atc.getThird(), "third parameter not wired correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallNamedInjectionOrderedMixed() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Call name=\"setAll\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg>arg2</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" </Call>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
assertEquals("arg1", atc.getFirst(), "first parameter not wired correctly");
|
||||||
|
assertEquals("arg2", atc.getSecond(), "second parameter not wired correctly");
|
||||||
|
assertEquals("arg3", atc.getThird(), "third parameter not wired correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallNamedInjectionUnorderedMixed() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Call name=\"setAll\">" +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" <Arg>arg2</Arg> " +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" </Call>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
assertEquals("arg1", atc.getFirst(), "first parameter not wired correctly");
|
||||||
|
assertEquals("arg2", atc.getSecond(), "second parameter not wired correctly");
|
||||||
|
assertEquals("arg3", atc.getThird(), "third parameter not wired correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallVarArgs() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Call name=\"setVarArgs\">" +
|
||||||
|
" <Arg>one</Arg> " +
|
||||||
|
" <Arg><Array type=\"String\"><Item type=\"String\">two</Item><Item type=\"String\">three</Item></Array></Arg> " +
|
||||||
|
" </Call>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
assertEquals("one", atc.getFirst(), "first parameter not wired correctly");
|
||||||
|
assertEquals("two", atc.getSecond(), "second parameter not wired correctly");
|
||||||
|
assertEquals("three", atc.getThird(), "third parameter not wired correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallMissingVarArgs() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg name=\"second\">arg2</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" <Call name=\"setVarArgs\">" +
|
||||||
|
" <Arg>one</Arg>" +
|
||||||
|
" </Call>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
assertEquals("one", atc.getFirst(), "first parameter not wired correctly");
|
||||||
|
assertNull(atc.getSecond());
|
||||||
|
assertNull(atc.getThird());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testArgumentsGetIgnoredMissingDTD() throws Exception
|
public void testArgumentsGetIgnoredMissingDTD() throws Exception
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue