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.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -37,11 +38,11 @@ import java.nio.file.Paths;
|
|||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
@ -51,7 +52,6 @@ import java.util.Queue;
|
|||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.util.ArrayUtil;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
|
@ -412,39 +412,13 @@ public class XmlConfiguration
|
|||
int index = 0;
|
||||
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
|
||||
{
|
||||
obj = construct(oClass, arguments.toArray(), namedArgMap);
|
||||
obj = construct(oClass, new NamedArgs(null, XmlConfiguration.getNodes(_root, "Arg")));
|
||||
}
|
||||
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)
|
||||
|
@ -916,7 +890,6 @@ public class XmlConfiguration
|
|||
String id = aoeNode.getString("Id");
|
||||
String name = aoeNode.getString("Name");
|
||||
String clazz = aoeNode.getString("Class");
|
||||
List<Object> args = aoeNode.getList("Arg");
|
||||
|
||||
Class<?> oClass;
|
||||
if (clazz != null)
|
||||
|
@ -937,7 +910,7 @@ public class XmlConfiguration
|
|||
|
||||
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)
|
||||
_configuration.getIdMap().put(id, nobj);
|
||||
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(methodName, "Method name cannot be null");
|
||||
|
@ -961,7 +934,8 @@ public class XmlConfiguration
|
|||
{
|
||||
if (!method.getName().equals(methodName))
|
||||
continue;
|
||||
if (method.getParameterCount() != arg.length)
|
||||
Object[] arguments = args.applyTo(method);
|
||||
if (arguments == null)
|
||||
continue;
|
||||
if (Modifier.isStatic(method.getModifiers()) != (obj == null))
|
||||
continue;
|
||||
|
@ -970,34 +944,7 @@ public class XmlConfiguration
|
|||
|
||||
try
|
||||
{
|
||||
return invokeMethod(method, obj, arg);
|
||||
}
|
||||
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);
|
||||
return invokeMethod(method, obj, arguments);
|
||||
}
|
||||
catch (IllegalAccessException | IllegalArgumentException e)
|
||||
{
|
||||
|
@ -1020,33 +967,16 @@ public class XmlConfiguration
|
|||
AttrOrElementNode aoeNode = new AttrOrElementNode(obj, node, "Id", "Class", "Arg");
|
||||
String id = aoeNode.getString("Id");
|
||||
String clazz = aoeNode.getString("Class");
|
||||
List<XmlParser.Node> argNodes = aoeNode.getNodes("Arg");
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("XML new " + 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;
|
||||
try
|
||||
{
|
||||
nobj = construct(oClass, arguments.toArray(), namedArgMap);
|
||||
nobj = construct(oClass, new NamedArgs(obj, aoeNode.getNodes("Arg")));
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
|
@ -1061,80 +991,19 @@ public class XmlConfiguration
|
|||
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(namedArgMap, "Named Argument Map cannot be null");
|
||||
Objects.requireNonNull(args, "Named list cannot be null");
|
||||
|
||||
constructors:
|
||||
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
|
||||
{
|
||||
if (arguments == null || arguments.length == 0)
|
||||
{
|
||||
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");
|
||||
Object[] arguments = args.applyTo(constructor);
|
||||
if (arguments != null)
|
||||
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)
|
||||
{
|
||||
|
@ -1777,40 +1646,146 @@ public class XmlConfiguration
|
|||
|
||||
public List<XmlParser.Node> getNodes(String elementName)
|
||||
{
|
||||
String attrName = StringUtil.asciiToLowerCase(elementName);
|
||||
final List<XmlParser.Node> values = new ArrayList<>();
|
||||
|
||||
String attr = _node.getAttribute(attrName);
|
||||
if (attr != null)
|
||||
{
|
||||
for (String a : StringUtil.csvSplit(null, attr, 0, attr.length()))
|
||||
{
|
||||
// create a fake node
|
||||
XmlParser.Node n = new XmlParser.Node(null, elementName, null);
|
||||
n.add(a);
|
||||
values.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _next; i++)
|
||||
{
|
||||
Object o = _node.get(i);
|
||||
if (!(o instanceof XmlParser.Node))
|
||||
continue;
|
||||
XmlParser.Node n = (XmlParser.Node)o;
|
||||
|
||||
if (elementName.equals(n.getTag()))
|
||||
{
|
||||
if (attr != null)
|
||||
throw new IllegalStateException("Cannot have attr '" + attrName + "' and element '" + elementName + "'");
|
||||
|
||||
values.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
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);
|
||||
final List<XmlParser.Node> values = new ArrayList<>();
|
||||
|
||||
String attr = node.getAttribute(attrName);
|
||||
if (attr != null)
|
||||
{
|
||||
for (String a : StringUtil.csvSplit(null, attr, 0, attr.length()))
|
||||
{
|
||||
// create a fake node
|
||||
XmlParser.Node n = new XmlParser.Node(null, elementName, null);
|
||||
n.add(a);
|
||||
values.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < node.size(); i++)
|
||||
{
|
||||
Object o = node.get(i);
|
||||
if (!(o instanceof XmlParser.Node))
|
||||
continue;
|
||||
XmlParser.Node n = (XmlParser.Node)o;
|
||||
|
||||
if (elementName.equals(n.getTag()))
|
||||
{
|
||||
if (attr != null)
|
||||
throw new IllegalStateException("Cannot have attr '" + attrName + "' and element '" + elementName + "'");
|
||||
|
||||
values.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
this.first = first;
|
||||
|
@ -48,6 +60,38 @@ public class AnnotatedTestConfiguration
|
|||
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()
|
||||
{
|
||||
return first;
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.util.Map;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
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.WorkDirExtension;
|
||||
|
@ -45,6 +46,11 @@ import org.eclipse.jetty.util.resource.PathResource;
|
|||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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 static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
@ -67,9 +73,17 @@ public class XmlConfigurationTest
|
|||
{
|
||||
public WorkDir workDir;
|
||||
|
||||
protected String[] _configure = new String[]{
|
||||
"org/eclipse/jetty/xml/configureWithAttr.xml", "org/eclipse/jetty/xml/configureWithElements.xml"
|
||||
};
|
||||
public static class ScenarioProvider implements ArgumentsProvider
|
||||
{
|
||||
@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 INT_ARRAY_XML = "<Array type=\"int\"><Item type=\"int\">1</Item><Item type=\"int\">2</Item></Array>";
|
||||
|
@ -82,170 +96,166 @@ public class XmlConfigurationTest
|
|||
configuration.configure();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPassedObject() throws Exception
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void testPassedObject(String configure) throws Exception
|
||||
{
|
||||
for (String configure : _configure)
|
||||
{
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("whatever", "xxx");
|
||||
TestConfiguration.VALUE = 77;
|
||||
URL url = XmlConfigurationTest.class.getClassLoader().getResource(configure);
|
||||
XmlConfiguration configuration = new XmlConfiguration(url);
|
||||
TestConfiguration tc = new TestConfiguration("tc");
|
||||
configuration.getProperties().putAll(properties);
|
||||
configuration.configure(tc);
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("whatever", "xxx");
|
||||
TestConfiguration.VALUE = 77;
|
||||
URL url = XmlConfigurationTest.class.getClassLoader().getResource(configure);
|
||||
XmlConfiguration configuration = new XmlConfiguration(url);
|
||||
TestConfiguration tc = new TestConfiguration("tc");
|
||||
configuration.getProperties().putAll(properties);
|
||||
configuration.configure(tc);
|
||||
|
||||
assertEquals("SetValue", tc.testObject, "Set String");
|
||||
assertEquals(2, tc.testInt, "Set Type");
|
||||
assertEquals("SetValue", tc.testObject, "Set String");
|
||||
assertEquals(2, tc.testInt, "Set Type");
|
||||
|
||||
assertEquals(18080, tc.propValue);
|
||||
assertEquals(18080, tc.propValue);
|
||||
|
||||
assertEquals("PutValue", tc.get("Test"), "Put");
|
||||
assertEquals("2", tc.get("TestDft"), "Put dft");
|
||||
assertEquals(2, tc.get("TestInt"), "Put type");
|
||||
assertEquals("PutValue", tc.get("Test"), "Put");
|
||||
assertEquals("2", tc.get("TestDft"), "Put dft");
|
||||
assertEquals(2, tc.get("TestInt"), "Put type");
|
||||
|
||||
assertEquals("PutValue", tc.get("Trim"), "Trim");
|
||||
assertNull(tc.get("Null"), "Null");
|
||||
assertNull(tc.get("NullTrim"), "NullTrim");
|
||||
assertEquals("PutValue", tc.get("Trim"), "Trim");
|
||||
assertNull(tc.get("Null"), "Null");
|
||||
assertNull(tc.get("NullTrim"), "NullTrim");
|
||||
|
||||
assertEquals(1.2345, tc.get("ObjectTrim"), "ObjectTrim");
|
||||
assertEquals("-1String", tc.get("Objects"), "Objects");
|
||||
assertEquals("-1String", tc.get("ObjectsTrim"), "ObjectsTrim");
|
||||
assertEquals("\n PutValue\n ", tc.get("String"), "String");
|
||||
assertEquals("", tc.get("NullString"), "NullString");
|
||||
assertEquals("\n ", tc.get("WhiteSpace"), "WhiteSpace");
|
||||
assertEquals("\n 1.2345\n ", tc.get("ObjectString"), "ObjectString");
|
||||
assertEquals("-1String", tc.get("ObjectsString"), "ObjectsString");
|
||||
assertEquals("-1\n String", tc.get("ObjectsWhiteString"), "ObjectsWhiteString");
|
||||
assertEquals(1.2345, tc.get("ObjectTrim"), "ObjectTrim");
|
||||
assertEquals("-1String", tc.get("Objects"), "Objects");
|
||||
assertEquals("-1String", tc.get("ObjectsTrim"), "ObjectsTrim");
|
||||
assertEquals("\n PutValue\n ", tc.get("String"), "String");
|
||||
assertEquals("", tc.get("NullString"), "NullString");
|
||||
assertEquals("\n ", tc.get("WhiteSpace"), "WhiteSpace");
|
||||
assertEquals("\n 1.2345\n ", tc.get("ObjectString"), "ObjectString");
|
||||
assertEquals("-1String", tc.get("ObjectsString"), "ObjectsString");
|
||||
assertEquals("-1\n String", tc.get("ObjectsWhiteString"), "ObjectsWhiteString");
|
||||
|
||||
assertEquals(System.getProperty("user.dir") + "/stuff", tc.get("SystemProperty"), "SystemProperty");
|
||||
assertEquals(System.getenv("HOME"), tc.get("Env"), "Env");
|
||||
assertEquals(System.getProperty("user.dir") + "/stuff", tc.get("SystemProperty"), "SystemProperty");
|
||||
assertEquals(System.getenv("HOME"), tc.get("Env"), "Env");
|
||||
|
||||
assertEquals("xxx", tc.get("Property"), "Property");
|
||||
assertEquals("xxx", tc.get("Property"), "Property");
|
||||
|
||||
assertEquals("Yes", tc.get("Called"), "Called");
|
||||
assertEquals("Yes", tc.get("Called"), "Called");
|
||||
|
||||
assertTrue(TestConfiguration.called);
|
||||
assertTrue(TestConfiguration.called);
|
||||
|
||||
assertEquals("Blah", tc.oa[0], "oa[0]");
|
||||
assertEquals("1.2.3.4:5678", tc.oa[1], "oa[1]");
|
||||
assertEquals(1.2345, tc.oa[2], "oa[2]");
|
||||
assertNull(tc.oa[3], "oa[3]");
|
||||
assertEquals("Blah", tc.oa[0], "oa[0]");
|
||||
assertEquals("1.2.3.4:5678", tc.oa[1], "oa[1]");
|
||||
assertEquals(1.2345, tc.oa[2], "oa[2]");
|
||||
assertNull(tc.oa[3], "oa[3]");
|
||||
|
||||
assertEquals(1, tc.ia[0], "ia[0]");
|
||||
assertEquals(2, tc.ia[1], "ia[1]");
|
||||
assertEquals(3, tc.ia[2], "ia[2]");
|
||||
assertEquals(0, tc.ia[3], "ia[3]");
|
||||
assertEquals(1, tc.ia[0], "ia[0]");
|
||||
assertEquals(2, tc.ia[1], "ia[1]");
|
||||
assertEquals(3, tc.ia[2], "ia[2]");
|
||||
assertEquals(0, tc.ia[3], "ia[3]");
|
||||
|
||||
TestConfiguration tc2 = tc.nested;
|
||||
assertNotNull(tc2);
|
||||
assertEquals(true, tc2.get("Arg"), "Called(bool)");
|
||||
TestConfiguration tc2 = tc.nested;
|
||||
assertNotNull(tc2);
|
||||
assertEquals(true, tc2.get("Arg"), "Called(bool)");
|
||||
|
||||
assertNull(tc.get("Arg"), "nested config");
|
||||
assertEquals(true, tc2.get("Arg"), "nested config");
|
||||
assertNull(tc.get("Arg"), "nested config");
|
||||
assertEquals(true, tc2.get("Arg"), "nested config");
|
||||
|
||||
assertEquals("Call1", tc2.testObject, "nested config");
|
||||
assertEquals(4, tc2.testInt, "nested config");
|
||||
assertEquals("http://www.eclipse.com/", tc2.url.toString(), "nested call");
|
||||
assertEquals("Call1", tc2.testObject, "nested config");
|
||||
assertEquals(4, tc2.testInt, "nested config");
|
||||
assertEquals("http://www.eclipse.com/", tc2.url.toString(), "nested call");
|
||||
|
||||
assertEquals(tc.testField1, 77, "static to field");
|
||||
assertEquals(tc.testField2, 2, "field to field");
|
||||
assertEquals(TestConfiguration.VALUE, 42, "literal to static");
|
||||
assertEquals(tc.testField1, 77, "static to field");
|
||||
assertEquals(tc.testField2, 2, "field to field");
|
||||
assertEquals(TestConfiguration.VALUE, 42, "literal to static");
|
||||
|
||||
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("key0"), "value0");
|
||||
assertEquals(((Map<String, String>)configuration.getIdMap().get("map")).get("key1"), "value1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewObject() throws Exception
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void testNewObject(String configure) throws Exception
|
||||
{
|
||||
for (String configure : _configure)
|
||||
TestConfiguration.VALUE = 71;
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("whatever", "xxx");
|
||||
|
||||
URL url = XmlConfigurationTest.class.getClassLoader().getResource(configure);
|
||||
final AtomicInteger count = new AtomicInteger(0);
|
||||
XmlConfiguration configuration = new XmlConfiguration(url)
|
||||
{
|
||||
TestConfiguration.VALUE = 71;
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("whatever", "xxx");
|
||||
|
||||
URL url = XmlConfigurationTest.class.getClassLoader().getResource(configure);
|
||||
final AtomicInteger count = new AtomicInteger(0);
|
||||
XmlConfiguration configuration = new XmlConfiguration(url)
|
||||
@Override
|
||||
public void initializeDefaults(Object object)
|
||||
{
|
||||
@Override
|
||||
public void initializeDefaults(Object object)
|
||||
if (object instanceof TestConfiguration)
|
||||
{
|
||||
if (object instanceof TestConfiguration)
|
||||
{
|
||||
count.incrementAndGet();
|
||||
((TestConfiguration)object).setNested(null);
|
||||
((TestConfiguration)object).setTestString("NEW DEFAULT");
|
||||
}
|
||||
count.incrementAndGet();
|
||||
((TestConfiguration)object).setNested(null);
|
||||
((TestConfiguration)object).setTestString("NEW DEFAULT");
|
||||
}
|
||||
};
|
||||
configuration.getProperties().putAll(properties);
|
||||
TestConfiguration tc = (TestConfiguration)configuration.configure();
|
||||
}
|
||||
};
|
||||
configuration.getProperties().putAll(properties);
|
||||
TestConfiguration tc = (TestConfiguration)configuration.configure();
|
||||
|
||||
assertEquals(3, count.get());
|
||||
assertEquals(3, count.get());
|
||||
|
||||
assertEquals("NEW DEFAULT", tc.getTestString());
|
||||
assertEquals("nested", tc.getNested().getTestString());
|
||||
assertEquals("NEW DEFAULT", tc.getNested().getNested().getTestString());
|
||||
assertEquals("NEW DEFAULT", tc.getTestString());
|
||||
assertEquals("nested", tc.getNested().getTestString());
|
||||
assertEquals("NEW DEFAULT", tc.getNested().getNested().getTestString());
|
||||
|
||||
assertEquals("SetValue", tc.testObject, "Set String");
|
||||
assertEquals(2, tc.testInt, "Set Type");
|
||||
assertEquals("SetValue", tc.testObject, "Set String");
|
||||
assertEquals(2, tc.testInt, "Set Type");
|
||||
|
||||
assertEquals(18080, tc.propValue);
|
||||
assertEquals(18080, tc.propValue);
|
||||
|
||||
assertEquals("PutValue", tc.get("Test"), "Put");
|
||||
assertEquals("2", tc.get("TestDft"), "Put dft");
|
||||
assertEquals(2, tc.get("TestInt"), "Put type");
|
||||
assertEquals("PutValue", tc.get("Test"), "Put");
|
||||
assertEquals("2", tc.get("TestDft"), "Put dft");
|
||||
assertEquals(2, tc.get("TestInt"), "Put type");
|
||||
|
||||
assertEquals("PutValue", tc.get("Trim"), "Trim");
|
||||
assertNull(tc.get("Null"), "Null");
|
||||
assertNull(tc.get("NullTrim"), "NullTrim");
|
||||
assertEquals("PutValue", tc.get("Trim"), "Trim");
|
||||
assertNull(tc.get("Null"), "Null");
|
||||
assertNull(tc.get("NullTrim"), "NullTrim");
|
||||
|
||||
assertEquals(1.2345, tc.get("ObjectTrim"), "ObjectTrim");
|
||||
assertEquals("-1String", tc.get("Objects"), "Objects");
|
||||
assertEquals("-1String", tc.get("ObjectsTrim"), "ObjectsTrim");
|
||||
assertEquals("\n PutValue\n ", tc.get("String"), "String");
|
||||
assertEquals("", tc.get("NullString"), "NullString");
|
||||
assertEquals("\n ", tc.get("WhiteSpace"), "WhiteSpace");
|
||||
assertEquals("\n 1.2345\n ", tc.get("ObjectString"), "ObjectString");
|
||||
assertEquals("-1String", tc.get("ObjectsString"), "ObjectsString");
|
||||
assertEquals("-1\n String", tc.get("ObjectsWhiteString"), "ObjectsWhiteString");
|
||||
assertEquals(1.2345, tc.get("ObjectTrim"), "ObjectTrim");
|
||||
assertEquals("-1String", tc.get("Objects"), "Objects");
|
||||
assertEquals("-1String", tc.get("ObjectsTrim"), "ObjectsTrim");
|
||||
assertEquals("\n PutValue\n ", tc.get("String"), "String");
|
||||
assertEquals("", tc.get("NullString"), "NullString");
|
||||
assertEquals("\n ", tc.get("WhiteSpace"), "WhiteSpace");
|
||||
assertEquals("\n 1.2345\n ", tc.get("ObjectString"), "ObjectString");
|
||||
assertEquals("-1String", tc.get("ObjectsString"), "ObjectsString");
|
||||
assertEquals("-1\n String", tc.get("ObjectsWhiteString"), "ObjectsWhiteString");
|
||||
|
||||
assertEquals(System.getProperty("user.dir") + "/stuff", tc.get("SystemProperty"), "SystemProperty");
|
||||
assertEquals("xxx", tc.get("Property"), "Property");
|
||||
assertEquals(System.getProperty("user.dir") + "/stuff", tc.get("SystemProperty"), "SystemProperty");
|
||||
assertEquals("xxx", tc.get("Property"), "Property");
|
||||
|
||||
assertEquals("Yes", tc.get("Called"), "Called");
|
||||
assertEquals("Yes", tc.get("Called"), "Called");
|
||||
|
||||
assertTrue(TestConfiguration.called);
|
||||
assertTrue(TestConfiguration.called);
|
||||
|
||||
assertEquals("Blah", tc.oa[0], "oa[0]");
|
||||
assertEquals("1.2.3.4:5678", tc.oa[1], "oa[1]");
|
||||
assertEquals(1.2345, tc.oa[2], "oa[2]");
|
||||
assertNull(tc.oa[3], "oa[3]");
|
||||
assertEquals("Blah", tc.oa[0], "oa[0]");
|
||||
assertEquals("1.2.3.4:5678", tc.oa[1], "oa[1]");
|
||||
assertEquals(1.2345, tc.oa[2], "oa[2]");
|
||||
assertNull(tc.oa[3], "oa[3]");
|
||||
|
||||
assertEquals(1, tc.ia[0], "ia[0]");
|
||||
assertEquals(2, tc.ia[1], "ia[1]");
|
||||
assertEquals(3, tc.ia[2], "ia[2]");
|
||||
assertEquals(0, tc.ia[3], "ia[3]");
|
||||
assertEquals(1, tc.ia[0], "ia[0]");
|
||||
assertEquals(2, tc.ia[1], "ia[1]");
|
||||
assertEquals(3, tc.ia[2], "ia[2]");
|
||||
assertEquals(0, tc.ia[3], "ia[3]");
|
||||
|
||||
TestConfiguration tc2 = tc.nested;
|
||||
assertNotNull(tc2);
|
||||
assertEquals(true, tc2.get("Arg"), "Called(bool)");
|
||||
TestConfiguration tc2 = tc.nested;
|
||||
assertNotNull(tc2);
|
||||
assertEquals(true, tc2.get("Arg"), "Called(bool)");
|
||||
|
||||
assertNull(tc.get("Arg"), "nested config");
|
||||
assertEquals(true, tc2.get("Arg"), "nested config");
|
||||
assertNull(tc.get("Arg"), "nested config");
|
||||
assertEquals(true, tc2.get("Arg"), "nested config");
|
||||
|
||||
assertEquals("Call1", tc2.testObject, "nested config");
|
||||
assertEquals(4, tc2.testInt, "nested config");
|
||||
assertEquals("http://www.eclipse.com/", tc2.url.toString(), "nested call");
|
||||
assertEquals("Call1", tc2.testObject, "nested config");
|
||||
assertEquals(4, tc2.testInt, "nested config");
|
||||
assertEquals("http://www.eclipse.com/", tc2.url.toString(), "nested call");
|
||||
|
||||
assertEquals(71, tc.testField1, "static to field");
|
||||
assertEquals(2, tc.testField2, "field to field");
|
||||
assertEquals(42, TestConfiguration.VALUE, "literal to static");
|
||||
}
|
||||
assertEquals(71, tc.testField1, "static to field");
|
||||
assertEquals(2, tc.testField2, "field to field");
|
||||
assertEquals(42, TestConfiguration.VALUE, "literal to static");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@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
|
||||
public void testArgumentsGetIgnoredMissingDTD() throws Exception
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue