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:
Greg Wilkins 2020-02-06 14:11:58 +01:00
parent 13458ab515
commit d27f4ee556
3 changed files with 467 additions and 305 deletions

View File

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

View File

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

View File

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