Take a look at this strange issue:

- I have a breakpoint on all access to the field
res1 - Res1 is assigned the value of f, which is “bar”
- Res1 now is “bar”
- At the next break, res1 is suddenly
null
Why is this impossible?
- Because of the breakpoint on res1, I can see that it shouldn’t have changed at all
- And it couldn’t, because I don’t explicitly change it between the assignment and the
assertEqualsand this code is running in a single JUnit thread. - There are no other fields or variables named
res1.
What could be up? I’m assuming it’s not a bug in the JVM, but who knows.
As Jon Skeet said, the problem is that the instances are different. This is caused by this strange reflection issue:
public class ServiceObject {
private static final Map<Class<?>, Map<String, Operation>> opsByClass =
new ConcurrentHashMap<Class<?>, Map<String,Operation>>();
private final Object target;
private final Map<String, Operation> myClassOps;
private class Operation {
private final Method method;
public Operation(Method met) {
this.method = met;
method.setAccessible(true);
}
public void execute(Map<String,?> args, Responder responder, Object context, boolean coerce) {
...
method.invoke(target, mArgs);
}
}
public ServiceObject(Object target) {
Class<?> myClass = target.getClass();
Map<String, Operation> op = opsByClass.get(myClass);
if (op == null) {
op = new HashMap<String, Operation>();
for (Method meth : myClass.getMethods()) {
...
op.put(opName, new Operation(meth));
}
opsByClass.put(myClass, op);
}
this.target = target;
this.myClassOps = op;
}
public void execute(String opName) {
Operation op = myClassOps.get(opName);
...
op.execute(args, responder, context, coerce);
}
}
// Foo is equivalent to the class that contains <res1> above
class Foo {
@ServiceOperation
public void bar() {
// breakpoint here
}
}
What happens when the tests are run:
a = new Foo();
b = new Foo();
svc = new ServiceObject(a);
svc.execute("bar", ...); // inside Foo.bar() <this> will be <a>
svc = new ServiceObject(b);
svc.execute("bar", ...); // inside Foo.bar() <this> will still be <a>, but should be <b>
At a guess: you’re looking at a different instance of the class during the assertion phase than you were when it was set to “bar”.
It’s hard to tell without seeing the rest of the code though.
EDIT: The problem is that your
opsByClasscache is going to include an Operation, which implicitly has an associatedServiceObject. So when you create the firstServiceObjectwith aFoo, it will cache Operation instances associated with that first instance ofServiceObject. When you callsvc.executeon the second instance ofServiceObject, it will look up the operation in the map, and find theOperationassociated with the first instance… which probably isn’t what you intended.