Merge pull request #4553 from eclipse/jetty-9.4.x-4550-XmlConfiguration-named-args
Fixes #4550 XmlConfiguration named parameters
This commit is contained in:
commit
ea5b70ba37
|
@ -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,12 @@ 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.Comparator;
|
||||
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 +53,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;
|
||||
|
@ -98,6 +99,22 @@ public class XmlConfiguration
|
|||
};
|
||||
private static final Iterable<ConfigurationProcessorFactory> __factoryLoader = ServiceLoader.load(ConfigurationProcessorFactory.class);
|
||||
private static final XmlParser __parser = initParser();
|
||||
public static final Comparator<Executable> EXECUTABLE_COMPARATOR = (o1, o2) ->
|
||||
{
|
||||
int p1 = o1.getParameterCount();
|
||||
int p2 = o2.getParameterCount();
|
||||
int compare = Integer.compare(p1, p2);
|
||||
if (compare == 0 && p1 > 0)
|
||||
{
|
||||
boolean a1 = o1.getParameterTypes()[p1 - 1].isArray();
|
||||
boolean a2 = o2.getParameterTypes()[p2 - 1].isArray();
|
||||
if (a1 && !a2)
|
||||
compare = 1;
|
||||
else if (!a1 && a2)
|
||||
compare = -1;
|
||||
}
|
||||
return compare;
|
||||
};
|
||||
|
||||
private static XmlParser initParser()
|
||||
{
|
||||
|
@ -412,39 +429,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 Args(null, oClass, 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 matching constructor %s in %s", oClass, _configuration));
|
||||
}
|
||||
}
|
||||
if (id != null)
|
||||
|
@ -916,7 +907,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 +927,7 @@ public class XmlConfiguration
|
|||
|
||||
try
|
||||
{
|
||||
Object nobj = call(oClass, name, obj, args.toArray(new Object[0]));
|
||||
Object nobj = call(oClass, name, obj, new Args(obj, oClass, aoeNode.getNodes("Arg")));
|
||||
if (id != null)
|
||||
_configuration.getIdMap().put(id, nobj);
|
||||
configure(nobj, node, aoeNode.getNext());
|
||||
|
@ -949,7 +939,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, Args args) throws InvocationTargetException, NoSuchMethodException
|
||||
{
|
||||
Objects.requireNonNull(oClass, "Class cannot be null");
|
||||
Objects.requireNonNull(methodName, "Method name cannot be null");
|
||||
|
@ -957,11 +947,15 @@ public class XmlConfiguration
|
|||
throw new IllegalArgumentException("Method name cannot be blank");
|
||||
|
||||
// Lets just try all methods for now
|
||||
for (Method method : oClass.getMethods())
|
||||
|
||||
Method[] methods = oClass.getMethods();
|
||||
Arrays.sort(methods, EXECUTABLE_COMPARATOR);
|
||||
for (Method method : methods)
|
||||
{
|
||||
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 +964,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 +987,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 Args(obj, oClass, aoeNode.getNodes("Arg")));
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
|
@ -1061,80 +1011,20 @@ public class XmlConfiguration
|
|||
return nobj;
|
||||
}
|
||||
|
||||
private Object construct(Class<?> klass, Object[] arguments, Map<String, Object> namedArgMap) throws InvocationTargetException, NoSuchMethodException
|
||||
private Object construct(Class<?> klass, Args 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");
|
||||
|
||||
for (Constructor<?> constructor : klass.getConstructors())
|
||||
Constructor<?>[] constructors = klass.getConstructors();
|
||||
Arrays.sort(constructors, EXECUTABLE_COMPARATOR);
|
||||
for (Constructor<?> constructor : constructors)
|
||||
{
|
||||
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 +1667,152 @@ 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 Args
|
||||
{
|
||||
private final Class<?> _class;
|
||||
private final List<Object> _arguments;
|
||||
private final List<String> _names;
|
||||
|
||||
private Args(Object obj, Class<?> oClass, List<XmlParser.Node> args) throws Exception
|
||||
{
|
||||
_class = oClass;
|
||||
_arguments = new ArrayList<>();
|
||||
_names = new ArrayList<>();
|
||||
for (XmlParser.Node child : args)
|
||||
{
|
||||
_arguments.add(value(obj, child));
|
||||
_names.add(child.getAttribute("name"));
|
||||
}
|
||||
}
|
||||
|
||||
private Args(List<Object> arguments, List<String> names)
|
||||
{
|
||||
_class = null;
|
||||
_arguments = arguments;
|
||||
_names = names;
|
||||
}
|
||||
|
||||
Object[] applyTo(Executable executable)
|
||||
{
|
||||
Object[] args = matchArgsToParameters(executable);
|
||||
if (args == null && _class != null)
|
||||
{
|
||||
// Could this be an empty varargs match?
|
||||
int count = executable.getParameterCount();
|
||||
if (count > 0 && executable.getParameterTypes()[count - 1].isArray())
|
||||
{
|
||||
// There is not a no varArgs alternative so let's try a an empty varArgs match
|
||||
args = asEmptyVarArgs(executable.getParameterTypes()[count - 1]).matchArgsToParameters(executable);
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
Args 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 Args(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