Comparing EObjects with EcoreUtils [message #911425] |
Tue, 11 September 2012 15:22 |
El Arbi Aboussoror Messages: 90 Registered: June 2010 |
Member |
|
|
Hello,
I have troubles with the equals(EObject, EObject) method in EcoreUtils.
I have loaded the same xmi resource twice and have written a test that compares Transition eobjects and then another test that compares Action eobjects and I don't understand why the first test passes while the second fails !?
@Test
public void testActions() {
Transition enabledTrans = (Transition) enabledTransRes.getContents()
.get(0);
Transition scenarioTrans = (Transition) scenarioTransRes.getContents()
.get(0);
for (int i = 0; i < enabledTrans.getActions().size(); i++) {
Action enabledAction = enabledTrans.getActions().get(i);
Action scenarioAction = scenarioTrans.getActions().get(i);
System.err.println("i:"+i+" kind:"+scenarioAction.getKind());
assertTrue(EcoreUtil.equals(enabledAction, scenarioAction));
}
}
@Test
public void testTansition() {
Transition enabledTrans = (Transition) enabledTransRes.getContents()
.get(0);
Transition scenarioTrans = (Transition) scenarioTransRes.getContents()
.get(0);
assertTrue(EcoreUtil.equals(enabledTrans, scenarioTrans));
}
I have attached a test project.
[Updated on: Tue, 11 September 2012 16:05] Report message to a moderator
|
|
|
|
|
|
|
|
|
|
|
|
Re: Comparing EObjects with EcoreUtils [message #911720 is a reply to message #911707] |
Wed, 12 September 2012 07:20 |
Ed Merks Messages: 33133 Registered: July 2009 |
Senior Member |
|
|
Comments below.
On 12/09/2012 9:05 AM, ElArbi Mising name wrote:
> Ed Merks wrote on Tue, 11 September 2012 16:35
>> Your model is a little strange. It has actions that are definition
>> structurally equal to each other, e.g.,
>>
>> <actions kind="IMPORT" value="">
>> <by name="u2i__default_constructor_Default_System"/>
>> <from name="Default_System"/>
>> </actions>
>> <actions kind="IMPORT" value="">
>> <by name="u2i__default_constructor_Default_System"/>
>> <from name="Default_System"/>
>> </actions>
> This is strange but it is a derived model (from parsing some XML traces...)
Oh well, in the end this thing causes a problem in the equality code
because the map finds the wrong object. Someone complained that I
should have used an IdentityHashMap, which is true, but it's an API
breaking change, and I don't do those as a general rule. And it
shouldn't be necessary given the documented constraints on EObject
implementations...
>
> [quote title=Ed Merks wrote on Tue, 11 September 2012 16:35]
> Then I noticed you did this:
>
> @Override
> public int hashCode() {
> final int prime = 31;
> int result = 1;
> result = prime * result + ((name == null) ? 0 : name.hashCode());
> result = prime * result + number;
> return result;
> }
>
> @Override
> public boolean equals(Object obj) {
> if (this == obj)
> return true;
> if (obj == null)
> return false;
> if (!(obj instanceof PidImpl))
> return false;
> PidImpl other = (PidImpl) obj;
> if (name == null) {
> if (other.name != null)
> return false;
> } else if (!name.equals(other.name))
> return false;
> if (number != other.number)
> return false;
> return true;
> }
>
> That violates this constraint document in EObject:
>
> The framework also assumes that implementations will not specialize
> |equals(Object)
> <eclipse-javadoc:%E2%98%82=org.eclipse.emf.ecore/src%3Corg.eclipse.emf.ecore%7BEObject.java%E2%98%83EObject%E2%98%82%E2%98%82equals%E2%98%82Object>|
> (nor |hashCode()
> <eclipse-javadoc:%E2%98%82=org.eclipse.emf.ecore/src%3Corg.eclipse.emf.ecore%7BEObject.java%E2%98%83EObject%E2%98%82%E2%98%82hashCode%E2%98%82>|)
> so that "|==|" can be always used for equality testing;
> |EcoreUtil.equals
> <eclipse-javadoc:%E2%98%82=org.eclipse.emf.ecore/src%3Corg.eclipse.emf.ecore%7BEObject.java%E2%98%83EObject%E2%98%82org.eclipse.emf.ecore.util.EcoreUtil%E2%98%82equals%E2%98%82EObject%E2%98%82EObject>|
> should be used for doing structural equality testing.
>
> Why do you do this? It's generally a bad idea to define equality and
> hashCodes for values that are mutable...
>
> [/quote]
>
> I have generated equals and hashCode methods to be able to use java.util.Set for the Pid Eobjects, please see testPidRegistry() method in the EcoreUtilTest class in the attached project.
> @Test
> public void testPidRegistry() {
> PidRegistry registry = new PidRegistry();
> // store a Pid twice
> Pid server1 = IFConfigFactory.eINSTANCE.createPid();
> server1.setName("Server");
> server1.setNumber(0);
> Pid server2 = IFConfigFactory.eINSTANCE.createPid();
> server2.setName("Server");
> server2.setNumber(0);
>
> // check that there's no duplicates
> registry.store(server1);
> assertEquals(1, registry.size());
> registry.store(server2);
> assertEquals(1, registry.size());
>
> }
> I haven't found in the Elist implementations something that do the same as Set... I'm wrong ?
Consider that most of the of the ELists for managing EObject require the
object to be in the list at most once. So the framework needs to do a
lot of List.contains testing which turns out to be very expensive
because of so many calls to .equals. The following approach in
BasicEList optimizes that nicely by using == instead of equals.
public boolean contains(Object object)
{
if (useEquals() && object != null)
{
for (int i = 0; i < size; ++i)
{
if (object.equals(data[i]))
{
return true;
}
}
}
else
{
for (int i = 0; i < size; ++i)
{
if (data[i] == object)
{
return true;
}
}
}
return false;
}
So all EMF's list implementations for EObjects override useEquals to be
false and drop into the fast implementation. But that's valid behavior
for such a list only if (o1 == o2) == (o1.equals(o2)) which is the case
only if the object doesn't override hashCode and equals. You might
argue next, so what, but if you consider that you have an EMF
implementation List, x, and do x.contains(o) and it returns false, but
then you do "new ArrayList(x).contains(o)" and it returns true, because
the former uses == but that later uses .equals for testing, then you
have confusing inconsistent behavior.
So that's the way it is and it's not going to change. If you choose to
ignore that, you'll run into problems like the one you found and there
will be other problems you've not noticed yet.
>
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
|
Powered by
FUDForum. Page generated in 0.02333 seconds