[Bug 380924] xmlconfiguration <Configure and <New supports named constructors, including dynamic ordering of parameters
This commit is contained in:
parent
b5f7e054be
commit
6d3d7b0df8
|
@ -15,6 +15,7 @@ package org.eclipse.jetty.util;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -23,7 +24,9 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.annotation.Name;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
@ -565,4 +568,65 @@ public class TypeUtil
|
||||||
}
|
}
|
||||||
throw new NoSuchMethodException("<init>");
|
throw new NoSuchMethodException("<init>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Object construct(Class<?> klass, Object[] arguments, Map<String, Object> namedArgMap) throws InvocationTargetException, NoSuchMethodException
|
||||||
|
{
|
||||||
|
for (Constructor<?> constructor : klass.getConstructors())
|
||||||
|
{
|
||||||
|
if (constructor.getParameterTypes().length != arguments.length)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
|
||||||
|
|
||||||
|
// target has no annotations
|
||||||
|
if ( parameterAnnotations == null || parameterAnnotations.length == 0 )
|
||||||
|
{
|
||||||
|
LOG.debug("Target has no parameter annotations");
|
||||||
|
return constructor.newInstance(arguments);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Object[] swizzled = new Object[arguments.length];
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for ( Annotation[] annotations : parameterAnnotations )
|
||||||
|
{
|
||||||
|
for ( Annotation annotation : annotations)
|
||||||
|
{
|
||||||
|
if ( annotation instanceof Name )
|
||||||
|
{
|
||||||
|
Name param = (Name)annotation;
|
||||||
|
|
||||||
|
if (namedArgMap.containsKey(param.value()))
|
||||||
|
{
|
||||||
|
LOG.debug("placing named {} in position {}", param.value(), count);
|
||||||
|
swizzled[count] = namedArgMap.get(param.value());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG.debug("placing {} in position {}", arguments[count], count);
|
||||||
|
swizzled[count] = arguments[count];
|
||||||
|
}
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG.debug("passing on annotation {}", annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return constructor.newInstance(swizzled);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (InstantiationException | IllegalAccessException | IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
LOG.ignore(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NoSuchMethodException("<init>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import java.util.Collection;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
@ -49,6 +50,7 @@ import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.eclipse.jetty.xml.XmlParser.Node;
|
import org.eclipse.jetty.xml.XmlParser.Node;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
@ -341,29 +343,50 @@ public class XmlConfiguration
|
||||||
String id = _config.getAttribute("id");
|
String id = _config.getAttribute("id");
|
||||||
Object obj = id == null ? null : _idMap.get(id);
|
Object obj = id == null ? null : _idMap.get(id);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int index = _config.size();
|
int index = _config.size();
|
||||||
if (obj == null && oClass != null)
|
if (obj == null && oClass != null)
|
||||||
{
|
{
|
||||||
List<Object> arguments = new ArrayList<>();
|
Map<String, Object> namedArgMap = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
List<Object> arguments = new LinkedList<>();
|
||||||
for (int i = 0; i < _config.size(); i++)
|
for (int i = 0; i < _config.size(); i++)
|
||||||
{
|
{
|
||||||
Object o = _config.get(i);
|
Object o = _config.get(i);
|
||||||
if (o instanceof String)
|
if (o instanceof String)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
if (!((XmlParser.Node)o).getTag().equals("Arg"))
|
}
|
||||||
|
XmlParser.Node node = (XmlParser.Node)o;
|
||||||
|
|
||||||
|
if (!(node.getTag().equals("Arg")))
|
||||||
{
|
{
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
String namedAttribute = node.getAttribute("name");
|
||||||
|
if ( namedAttribute != null )
|
||||||
|
{
|
||||||
|
namedArgMap.put(namedAttribute,value(obj,(XmlParser.Node)o));
|
||||||
|
}
|
||||||
|
|
||||||
arguments.add(value(obj, (XmlParser.Node)o));
|
arguments.add(value(obj, (XmlParser.Node)o));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
obj = TypeUtil.construct(oClass, arguments.toArray());
|
if ( namedArgMap.size() > 0 )
|
||||||
|
{
|
||||||
|
obj = TypeUtil.construct(oClass, arguments.toArray(), namedArgMap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obj = TypeUtil.construct(oClass, arguments.toArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException x)
|
catch (NoSuchMethodException x)
|
||||||
{
|
{
|
||||||
|
@ -780,13 +803,29 @@ public class XmlConfiguration
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, Object> namedArgMap = new HashMap<String, Object>();
|
||||||
|
List<Object> arguments = new LinkedList<>();
|
||||||
|
|
||||||
Object[] arg = new Object[size];
|
Object[] arg = new Object[size];
|
||||||
for (int i = 0, j = 0; j < size; i++)
|
for (int i = 0, j = 0; j < size; i++)
|
||||||
{
|
{
|
||||||
Object o = node.get(i);
|
Object o = node.get(i);
|
||||||
|
|
||||||
|
XmlParser.Node argNode = (XmlParser.Node)o;
|
||||||
if (o instanceof String)
|
if (o instanceof String)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
arg[j++] = value(obj,(XmlParser.Node)o);
|
arg[j++] = value(obj,(XmlParser.Node)o);
|
||||||
|
|
||||||
|
String namedAttribute = argNode.getAttribute("name");
|
||||||
|
if ( namedAttribute != null )
|
||||||
|
{
|
||||||
|
namedArgMap.put(namedAttribute,value(obj,(XmlParser.Node)o));
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments.add(value(obj,(XmlParser.Node)o));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
|
@ -794,7 +833,18 @@ public class XmlConfiguration
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Object n = TypeUtil.construct(oClass, arg);
|
Object n;
|
||||||
|
if ( namedArgMap.size() > 0 )
|
||||||
|
{
|
||||||
|
LOG.debug("using named mapping");
|
||||||
|
n = TypeUtil.construct(oClass, arguments.toArray(), namedArgMap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG.debug("using normal mapping");
|
||||||
|
n = TypeUtil.construct(oClass, arguments.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
configure(n,node,argi);
|
configure(n,node,argi);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ public class AnnotatedTestConfiguration
|
||||||
private String second;
|
private String second;
|
||||||
private String third;
|
private String third;
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration nested;
|
||||||
|
|
||||||
public AnnotatedTestConfiguration(@Name("first") String first, @Name("second") String second, @Name("third") String third)
|
public AnnotatedTestConfiguration(@Name("first") String first, @Name("second") String second, @Name("third") String third)
|
||||||
{
|
{
|
||||||
this.first = first;
|
this.first = first;
|
||||||
|
@ -45,6 +47,14 @@ public class AnnotatedTestConfiguration
|
||||||
this.third = third;
|
this.third = third;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AnnotatedTestConfiguration getNested()
|
||||||
|
{
|
||||||
|
return nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNested(AnnotatedTestConfiguration nested)
|
||||||
|
{
|
||||||
|
this.nested = nested;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,6 +377,7 @@ public class XmlConfigurationTest
|
||||||
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testConstructorNamedInjectionUnOrdered() throws Exception
|
public void testConstructorNamedInjectionUnOrdered() throws Exception
|
||||||
{
|
{
|
||||||
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
||||||
|
@ -393,6 +394,7 @@ public class XmlConfigurationTest
|
||||||
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testConstructorNamedInjectionOrderedMixed() throws Exception
|
public void testConstructorNamedInjectionOrderedMixed() throws Exception
|
||||||
{
|
{
|
||||||
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
||||||
|
@ -409,6 +411,7 @@ public class XmlConfigurationTest
|
||||||
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testConstructorNamedInjectionUnorderedMixed() throws Exception
|
public void testConstructorNamedInjectionUnorderedMixed() throws Exception
|
||||||
{
|
{
|
||||||
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
||||||
|
@ -424,4 +427,140 @@ public class XmlConfigurationTest
|
||||||
Assert.assertEquals("second parameter not wired correctly","arg2", atc.getSecond());
|
Assert.assertEquals("second parameter not wired correctly","arg2", atc.getSecond());
|
||||||
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNestedConstructorNamedInjection() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg>arg1</Arg> " +
|
||||||
|
" <Arg>arg2</Arg> " +
|
||||||
|
" <Arg>arg3</Arg> " +
|
||||||
|
" <Set name=\"nested\"> " +
|
||||||
|
" <New class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg>arg1</Arg> " +
|
||||||
|
" <Arg>arg2</Arg> " +
|
||||||
|
" <Arg>arg3</Arg> " +
|
||||||
|
" </New>" +
|
||||||
|
" </Set>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
Assert.assertEquals("first parameter not wired correctly","arg1", atc.getFirst());
|
||||||
|
Assert.assertEquals("second parameter not wired correctly","arg2", atc.getSecond());
|
||||||
|
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
||||||
|
Assert.assertEquals("nested first parameter not wired correctly","arg1", atc.getNested().getFirst());
|
||||||
|
Assert.assertEquals("nested second parameter not wired correctly","arg2", atc.getNested().getSecond());
|
||||||
|
Assert.assertEquals("nested third parameter not wired correctly","arg3", atc.getNested().getThird());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNestedConstructorNamedInjectionOrdered() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg name=\"second\">arg2</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" <Set name=\"nested\"> " +
|
||||||
|
" <New class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg name=\"second\">arg2</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" </New>" +
|
||||||
|
" </Set>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
Assert.assertEquals("first parameter not wired correctly","arg1", atc.getFirst());
|
||||||
|
Assert.assertEquals("second parameter not wired correctly","arg2", atc.getSecond());
|
||||||
|
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
||||||
|
Assert.assertEquals("nested first parameter not wired correctly","arg1", atc.getNested().getFirst());
|
||||||
|
Assert.assertEquals("nested second parameter not wired correctly","arg2", atc.getNested().getSecond());
|
||||||
|
Assert.assertEquals("nested third parameter not wired correctly","arg3", atc.getNested().getThird());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNestedConstructorNamedInjectionUnOrdered() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" <Arg name=\"second\">arg2</Arg> " +
|
||||||
|
" <Set name=\"nested\"> " +
|
||||||
|
" <New class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" <Arg name=\"second\">arg2</Arg> " +
|
||||||
|
" </New>" +
|
||||||
|
" </Set>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
Assert.assertEquals("first parameter not wired correctly","arg1", atc.getFirst());
|
||||||
|
Assert.assertEquals("second parameter not wired correctly","arg2", atc.getSecond());
|
||||||
|
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
||||||
|
Assert.assertEquals("nested first parameter not wired correctly","arg1", atc.getNested().getFirst());
|
||||||
|
Assert.assertEquals("nested second parameter not wired correctly","arg2", atc.getNested().getSecond());
|
||||||
|
Assert.assertEquals("nested third parameter not wired correctly","arg3", atc.getNested().getThird());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNestedConstructorNamedInjectionOrderedMixed() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg>arg2</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" <Set name=\"nested\"> " +
|
||||||
|
" <New class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Arg>arg2</Arg> " +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" </New>" +
|
||||||
|
" </Set>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
Assert.assertEquals("first parameter not wired correctly","arg1", atc.getFirst());
|
||||||
|
Assert.assertEquals("second parameter not wired correctly","arg2", atc.getSecond());
|
||||||
|
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
||||||
|
Assert.assertEquals("nested first parameter not wired correctly","arg1", atc.getNested().getFirst());
|
||||||
|
Assert.assertEquals("nested second parameter not wired correctly","arg2", atc.getNested().getSecond());
|
||||||
|
Assert.assertEquals("nested third parameter not wired correctly","arg3", atc.getNested().getThird());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNestedConstructorNamedInjectionUnorderedMixed() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" <Arg>arg2</Arg> " +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" <Set name=\"nested\"> " +
|
||||||
|
" <New class=\"org.eclipse.jetty.xml.AnnotatedTestConfiguration\">" +
|
||||||
|
" <Arg name=\"third\">arg3</Arg> " +
|
||||||
|
" <Arg>arg2</Arg> " +
|
||||||
|
" <Arg name=\"first\">arg1</Arg> " +
|
||||||
|
" </New>" +
|
||||||
|
" </Set>" +
|
||||||
|
"</Configure>");
|
||||||
|
|
||||||
|
AnnotatedTestConfiguration atc = (AnnotatedTestConfiguration)xmlConfiguration.configure();
|
||||||
|
|
||||||
|
Assert.assertEquals("first parameter not wired correctly","arg1", atc.getFirst());
|
||||||
|
Assert.assertEquals("second parameter not wired correctly","arg2", atc.getSecond());
|
||||||
|
Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
|
||||||
|
Assert.assertEquals("nested first parameter not wired correctly","arg1", atc.getNested().getFirst());
|
||||||
|
Assert.assertEquals("nested second parameter not wired correctly","arg2", atc.getNested().getSecond());
|
||||||
|
Assert.assertEquals("nested third parameter not wired correctly","arg3", atc.getNested().getThird());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||||
|
org.eclipse.jetty.xml.LEVEL=DEBUG
|
||||||
|
org.eclipse.jetty.util.LEVEL=DEBUG
|
Loading…
Reference in New Issue