Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 339261

Summary: EpsilonTestSuite fails on test case "testRemove" from CollectionsTests.eol
Product: [Modeling] Epsilon Reporter: Antonio Garcia-Dominguez <agarcdomi>
Component: CoreAssignee: Louis Rose <louis>
Status: CLOSED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: dkolovos, louis, maarten.bezemer
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Whiteboard: interim
Attachments:
Description Flags
Patch which implements a 2-phase lookup process
none
Rebased Antonio's patch on top of HEAD none

Description Antonio Garcia-Dominguez CLA 2011-03-08 12:32:42 EST
Build Identifier: 20100917-0705

I've tried running the EpsilonTestSuite and the testRemove test case in CollectionsTests.eol in the o.e.e.eol.engine.test.acceptance project fails:

@test
operation testRemove() {
	var s = Sequence{1,2,3};
	s.remove(1);
	assertEquals(s, Sequence{2,3});
}

Apparently, l.remove(1) is being interpreted as "remove the second element" rather than "remove the element equal to 1", when l is an ArrayList. That is correct in Java (as 1 is used straight away as an int), but Epsilon converts the 1 to an Integer, so I would expect the test to pass. This would be consistent with the Epsilon book, which defines remove(item) but not remove(int), using removeAt(int) instead to avoid this ambiguity.

I have looked a bit into it and I think I have found the cause of the problem: the method resolution process in ReflectionUtil#getMethodFor is slightly off. The correct process, according to the Java Language Specification, sections 15.12.2.2 to 15.12.2.4, is to do it in three stages:

1. Try to find it without autoboxing/unboxing.
2. Try to find it with autoboxing/unboxing.
3. Try to find it with varargs.

However, ReflectionUtil#getMethodFor seems to do phase 2 straight away, as it used ReflectionUtil#isInstance, which seems to do the autoboxing/unboxing bits:

/**
 * Checks if the instance is an instance of clazz
 * Necessary because in Java, int.class != Integer.class etc
 * @param clazz
 * @param instance
 * @return
 */
public static boolean isInstance(Class clazz, Object instance){
	if (instance == null) return true;
	else if (clazz == int.class) return Integer.class.isInstance(instance);
	else if (clazz == float.class) return Float.class.isInstance(instance);
	else if (clazz == double.class) return Double.class.isInstance(instance);
	else if (clazz == boolean.class) return Boolean.class.isInstance(instance);
	else if (clazz == long.class) return Long.class.isInstance(instance);
	else return clazz.isInstance(instance);
}

I think method resolution is too tricky for us to be reimplementing it: perhaps we should just use Class#getMethod and cache the results to save time.

Reproducible: Always

Steps to Reproduce:
1. Run the EpsilonTestSuite in the org.eclipse.epsilon.test project.
Comment 1 Antonio Garcia-Dominguez CLA 2011-03-08 12:34:24 EST
Created attachment 190676 [details]
Patch which implements a 2-phase lookup process

This patch implements phase 1 of the JLS method resolution process, but we'd still be missing phase 3 (varargs). I really think we should stick to Class#getMethod.
Comment 2 Louis Rose CLA 2011-04-07 11:33:54 EDT
I'm not sure if this is helpful, but on my Windows installation this test passes! Maybe due to a different version of Java? I'm running:

Java(TM) SE Runtime Environment (build 1.6.0_15-b03)
Java HotSpot(TM) Client VM (build 14.1-b02, mixed mode, sharing)
Comment 3 Antonio Garcia-Dominguez CLA 2011-04-07 17:22:24 EDT
I'm running OpenJDK 6 on Linux. And you're right: I ran the tests today on Windows 7 and this one passed :-/.
Comment 4 Antonio Garcia-Dominguez CLA 2012-05-15 11:42:49 EDT
One of our users has been bitten by this problem, according to this thread:

http://www.eclipse.org/forums/index.php/mv/msg/351807/872040/#msg_872040

Dimitris, Louis: could you have another look at the patch?
Comment 5 Louis Rose CLA 2012-05-16 11:38:24 EDT
Antonio,

Thanks for continuing to drive this forward

I agree with your diagnosis. I've investigated whether we can use Class#getMethod, but sadly this doesn't help. According to [1,2], Class#getMethod doesn't correctly manage auto-boxing and it seems we'd have to continue to maintain our own logic for this. 

Consequently I believe your patch on comment 1 is the solution we should use. I've rebased this patch on HEAD, added some unit tests, and refactored out some duplication that has been in ReflectionUtil for a little while. 

[1] - http://royontechnology.blogspot.co.uk/2010/10/issue-of-autoboxing-and-reflection.html
[2] - http://stackoverflow.com/questions/1894740/any-solution-for-class-getmethod-reflection-and-autoboxing
Comment 6 Louis Rose CLA 2012-05-16 11:40:36 EDT
Created attachment 215718 [details]
Rebased Antonio's patch on top of HEAD

Latest version of Antonio's solution attached.

@Dimitris, @Antonio: could you take a look, and give a +1 if we can push this forward?
Comment 7 Antonio Garcia-Dominguez CLA 2012-05-16 12:05:21 EDT
(In reply to comment #6)
> Created attachment 215718 [details]
> Rebased Antonio's patch on top of HEAD
> 
> Latest version of Antonio's solution attached.
> 
> @Dimitris, @Antonio: could you take a look, and give a +1 if we can push this
> forward?

+1

The patch looks good to me. Did that fix testRemove at last?
Comment 8 Louis Rose CLA 2012-05-16 12:26:14 EDT
(In reply to comment #7)
> (In reply to comment #6)
> > @Dimitris, @Antonio: could you take a look, and give a +1 if we can push this
> > forward?
> 
> +1
> 
> The patch looks good to me. Did that fix testRemove at last?

It did on Mac OS X. When I get home, I'll check on Windows (which I think implements Class#getMethod differently, judging by comment 2).
Comment 9 Louis Rose CLA 2012-05-17 10:21:18 EDT
(In reply to comment #8)
> It did on Mac OS X. When I get home, I'll check on Windows (which I think
> implements Class#getMethod differently, judging by comment 2).

Confirming that the attached patch works on Windows (XP, Java 7 update 4).
Comment 10 Antonio Garcia-Dominguez CLA 2012-05-17 11:26:37 EDT
(In reply to comment #9)
> (In reply to comment #8)
> > It did on Mac OS X. When I get home, I'll check on Windows (which I think
> > implements Class#getMethod differently, judging by comment 2).
> 
> Confirming that the attached patch works on Windows (XP, Java 7 update 4).

The attached patch also works on Linux:

java.runtime.name=OpenJDK Runtime Environment
java.runtime.version=1.6.0_24-b24
java.vm.info=mixed mode, sharing
java.vm.name=OpenJDK Client VM
java.vm.specification.name=Java Virtual Machine Specification
java.vm.specification.vendor=Sun Microsystems Inc.
java.vm.specification.version=1.0
java.vm.vendor=Sun Microsystems Inc.
java.vm.version=20.0-b12
Comment 11 Antonio Garcia-Dominguez CLA 2012-05-25 18:18:07 EDT
Louis, shall I go ahead and apply the patch, or would you like to show it to Dimitris first?
Comment 12 Louis Rose CLA 2012-05-28 04:17:06 EDT
(In reply to comment #11)
> Louis, shall I go ahead and apply the patch, or would you like to show it to
> Dimitris first?

Let me just check my rebasing with Dimitris first. It'd be good to make sure I've not accidentally squashed one of Dimitris's recent changes!
Comment 13 Louis Rose CLA 2012-05-30 09:50:52 EDT
I've committed the rebased patch to SVN.
Comment 14 Dimitris Kolovos CLA 2012-07-03 06:40:28 EDT
This has been fixed in the latest interim version.
Comment 15 Dimitris Kolovos CLA 2012-11-08 16:36:47 EST
Fixed in 1.0