Actually, I had a brain-fart in my response to you David too. There are two 'make' methods that are separate, and one of them happens at time of execution, not time of mock setup.
Anyway, building on Szczepan's suggestion to look into thenAnswer, and finding StubbingWithCustomAnswerTest.shouldAnswer(), I've made a modest adaptor to leverage Paranamer found bits and pieces:
@Test
public void shouldAnswerUsingParanamerMagic() throws Exception {
when(mock.simpleMethod(anyString(), anyInt(), anyInt(), anyInt(), anyInt())).thenAnswer(new ParanamerAnswer<String>() {
public String inject(InvocationOnMock invocation, String one, Integer two, Integer three, Integer four, Integer five) throws Throwable {
return invocation.getMethod().getName() + "-" + five + "-" + four + "-" + three + "-" + two + "-" + one;
}
});
assertEquals("simpleMethod-55-44-33-22-test", mock.simpleMethod("test", 22, 33, 44, 55));
}
public abstract static class ParanamerAnswer<T> implements Answer<T> {
public final T answer(InvocationOnMock invocation) throws Throwable {
Paranamer paranamer = new DefaultParanamer();
String[] invocationNames = paranamer.lookupParameterNames(invocation.getMethod());
Object[] invocationArgs = invocation.getArguments();
Method[] methods = ParanamerAnswer.this.getClass().getMethods();
for (Method method : methods) {
if (method.getName().equals("inject")) {
String[] injectionNames = paranamer.lookupParameterNames(method);
Object[] injectees = new Object[injectionNames.length];
injectees[0] = invocation;
for (int j = 0; j < injectionNames.length; j++) {
String injectionName = injectionNames[j];
for (int k = 0; k < invocationNames.length; k++) {
String invocationName = invocationNames[k];
if (invocationName.equals(injectionName)) {
injectees[j] = invocationArgs[k];
break;
}
}
}
method.invoke(this, injectees);
break;
}
}
throw new RuntimeException("no 'inject' method found");
}
}
Parameter names are available in the debug tables of classes, but sadly not interfaces. BytecodeReadingParanamer allows us to easily access the debug-table data for classes (but again, not for interfaces). DefaultParanamer requires a post-compilation step that uses QDox to parse source (again), then decorate classes just build with an extra static/final string that is the parameter name info for the classes (and interfaces) processes. This is where you guys might think it's "too much" for inclusion into Mockito. We made an Ant and a Maven capability for that that (that share code obviously)
Nat Pryce was asking the same questions in '08/'09 for Paranamer in respect of interface method parm names, in respect of JMock.