Home » Modeling » EMF » EcoreUtil.EqualityHelper and 'ordered' feature
EcoreUtil.EqualityHelper and 'ordered' feature [message #1647088] |
Tue, 03 March 2015 08:46 |
Mark Hoffmann Messages: 113 Registered: July 2009 Location: Jena |
Senior Member |
|
|
Hello together,
I noticed that the 'ordered' feature in the ecore has no influence on the code generation process. It is no bigger problem until now. Currently I have a use case where I want to compare to model instance for equality. But there are many-references with content that has not the same order in the list. The order is not important for the equality in this case, but only the content of the objects.
For that I created my own EqualityHelper extending the EcoreUtil.EqualityHelper to support sorting like this:
protected boolean haveEqualReference(EObject eObject1, EObject eObject2, EReference reference) {
Object value1 = eObject1.eGet(reference);
Object value2 = eObject2.eGet(reference);
if (reference.isMany()) {
List<EObject> list1 = (List<EObject>) value1;
List<EObject> list2 = (List<EObject>) value2;
if (reference.isOrdered()) {
Comparator<EObject> comparator = new EObjectComparator(reference.getEKeys());
Collections.sort(list1, comparator);
Collections.sort(list2, comparator);
}
return equals(list1, list2);
} else {
return equals((EObject)value1, (EObject)value2);
}
}
The comparator sorts depending on the keys, if any are given, otherwise it uses toString comparison. The values in the key attributes are checked, if they implement java.lang.Comparable, which works for Numbers, String, Date and Enums
What do you think of this pattern? Is it something to contribute to enhance the EcoreUtil.EqualityHelper? Because this use-case is probalby not the most common one, maybe it should be parameterized.
EcoreUtil.equals(EObject eObject1, EObject eObject2, boolean sort)
By the way my implementation supports ignore-features too, that are ignored during comparison when they are not important for the equality.
Regards,
Mark
|
|
|
Re: EcoreUtil.EqualityHelper and 'ordered' feature [message #1647123 is a reply to message #1647088] |
Tue, 03 March 2015 09:07 |
Ed Merks Messages: 33140 Registered: July 2009 |
Senior Member |
|
|
Mark,
Comments below.
On 03/03/2015 9:46 AM, Mark Hoffmann wrote:
> Hello together,
>
> I noticed that the 'ordered' feature in the ecore has no influence on
> the code generation process. It is no bigger problem until now.
> Currently I have a use case where I want to compare to model instance
> for equality. But there are many-references with content that has not
> the same order in the list. The order is not important for the
> equality in this case, but only the content of the objects.
>
> For that I created my own EqualityHelper extending the
> EcoreUtil.EqualityHelper to support sorting like this:
>
> protected boolean haveEqualReference(EObject eObject1, EObject
> eObject2, EReference reference) {
> Object value1 = eObject1.eGet(reference);
> Object value2 = eObject2.eGet(reference);
> if (reference.isMany()) {
> List<EObject> list1 = (List<EObject>) value1;
> List<EObject> list2 = (List<EObject>) value2;
> if (reference.isOrdered()) {
> Comparator<EObject> comparator = new
> EObjectComparator(reference.getEKeys());
> Collections.sort(list1, comparator);
> Collections.sort(list2, comparator);
This actually modifies the state of the model as part of equality
testing... That seems not so ideal...
> }
> return equals(list1, list2);
> } else {
> return equals((EObject)value1, (EObject)value2);
> }
> }
>
>
> The comparator sorts depending on the keys, if any are given,
> otherwise it uses toString comparison. The values in the key
> attributes are checked, if they implement java.lang.Comparable, which
> works for Numbers, String, Date and Enums
>
> What do you think of this pattern? Is it something to contribute to
> enhance the EcoreUtil.EqualityHelper? Because this use-case is
> probalby not the most common one, maybe it should be parameterized.
> EcoreUtil.equals(EObject eObject1, EObject eObject2, boolean sort)
It seems odd to me that an equality tester should modify the state of
the model. One generally expects a tester to be side-effect free...
>
> By the way my implementation supports ignore-features too, that are
> ignored during comparison when they are not important for the equality.
>
> Regards,
> Mark
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
Re: EcoreUtil.EqualityHelper and 'ordered' feature [message #1647219 is a reply to message #1647088] |
Tue, 03 March 2015 10:08 |
Ed Willink Messages: 7655 Registered: July 2009 |
Senior Member |
|
|
Hi
Perhaps I misunderstand, but it seems you have an ordered collection
whose order you are unhappy with.
Surely the solution is either to make the collection unordered, or to
fix-up your assignment algorithm so that it is sensibly ordered?
EMF unordered collections are realised by ELists so that they do
actually have an order that can be inconvenient if you use something
like org.eclipse.xtext.util.EmfFormatter as the basis for a
JUnit-friendly model comparison. For that purpose, I use a hierarchy of
Normalizer classes, so that a first traversal pass over the model
gathers all the normalizations that are necessary, then the
normalizations can be performed in a second 'pass' without corrupting an
iterator domain. Once normalized, 'equivalent' models can be compared
for exact equality. But as EdM observed, modifying models is dubious. It
is often tolerable at the end of JUnit tests., however where
intolerable, the Normalizers support an inverse denormalization
operation so that the normalization can be reverted.
Your Comparator assumes that getEKeys() is the basis for an ordering.
There are many different comparisons, so hardwiring one doesn't seem
helpful.
An idea! Rather than a disruptive normalizer, why not provide an Guava
Iterable that presents a normalized view of your collection? An
EStructuralFeature to NormalizedIteratableFactory registry could provide
something extensible and neutral.
Regards
Ed Willink
On 03/03/2015 08:46, Mark Hoffmann wrote:
> Hello together,
>
> I noticed that the 'ordered' feature in the ecore has no influence on
> the code generation process. It is no bigger problem until now.
> Currently I have a use case where I want to compare to model instance
> for equality. But there are many-references with content that has not
> the same order in the list. The order is not important for the
> equality in this case, but only the content of the objects.
>
> For that I created my own EqualityHelper extending the
> EcoreUtil.EqualityHelper to support sorting like this:
>
> protected boolean haveEqualReference(EObject eObject1, EObject
> eObject2, EReference reference) {
> Object value1 = eObject1.eGet(reference);
> Object value2 = eObject2.eGet(reference);
> if (reference.isMany()) {
> List<EObject> list1 = (List<EObject>) value1;
> List<EObject> list2 = (List<EObject>) value2;
> if (reference.isOrdered()) {
> Comparator<EObject> comparator = new
> EObjectComparator(reference.getEKeys());
> Collections.sort(list1, comparator);
> Collections.sort(list2, comparator);
> }
> return equals(list1, list2);
> } else {
> return equals((EObject)value1, (EObject)value2);
> }
> }
>
>
> The comparator sorts depending on the keys, if any are given,
> otherwise it uses toString comparison. The values in the key
> attributes are checked, if they implement java.lang.Comparable, which
> works for Numbers, String, Date and Enums
>
> What do you think of this pattern? Is it something to contribute to
> enhance the EcoreUtil.EqualityHelper? Because this use-case is
> probalby not the most common one, maybe it should be parameterized.
> EcoreUtil.equals(EObject eObject1, EObject eObject2, boolean sort)
>
> By the way my implementation supports ignore-features too, that are
> ignored during comparison when they are not important for the equality.
>
> Regards,
> Mark
|
|
| |
Re: EcoreUtil.EqualityHelper and 'ordered' feature [message #1647258 is a reply to message #1647219] |
Tue, 03 March 2015 10:31 |
Mark Hoffmann Messages: 113 Registered: July 2009 Location: Jena |
Senior Member |
|
|
Hi Ed,
Thank you for you response.
I already had something like your normalizer in mind.
The two pass step is an good idea. Because I often make use of the EKeys, I can use the comparator for a default implementation of an normalizer.
Thank you,
Mark
Ed Willink wrote on Tue, 03 March 2015 11:08Hi
Perhaps I misunderstand, but it seems you have an ordered collection
whose order you are unhappy with.
Surely the solution is either to make the collection unordered, or to
fix-up your assignment algorithm so that it is sensibly ordered?
EMF unordered collections are realised by ELists so that they do
actually have an order that can be inconvenient if you use something
like org.eclipse.xtext.util.EmfFormatter as the basis for a
JUnit-friendly model comparison. For that purpose, I use a hierarchy of
Normalizer classes, so that a first traversal pass over the model
gathers all the normalizations that are necessary, then the
normalizations can be performed in a second 'pass' without corrupting an
iterator domain. Once normalized, 'equivalent' models can be compared
for exact equality. But as EdM observed, modifying models is dubious. It
is often tolerable at the end of JUnit tests., however where
intolerable, the Normalizers support an inverse denormalization
operation so that the normalization can be reverted.
Your Comparator assumes that getEKeys() is the basis for an ordering.
There are many different comparisons, so hardwiring one doesn't seem
helpful.
An idea! Rather than a disruptive normalizer, why not provide an Guava
Iterable that presents a normalized view of your collection? An
EStructuralFeature to NormalizedIteratableFactory registry could provide
something extensible and neutral.
Regards
Ed Willink
On 03/03/2015 08:46, Mark Hoffmann wrote:
> Hello together,
>
> I noticed that the 'ordered' feature in the ecore has no influence on
> the code generation process. It is no bigger problem until now.
> Currently I have a use case where I want to compare to model instance
> for equality. But there are many-references with content that has not
> the same order in the list. The order is not important for the
> equality in this case, but only the content of the objects.
>
> For that I created my own EqualityHelper extending the
> EcoreUtil.EqualityHelper to support sorting like this:
>
> protected boolean haveEqualReference(EObject eObject1, EObject
> eObject2, EReference reference) {
> Object value1 = eObject1.eGet(reference);
> Object value2 = eObject2.eGet(reference);
> if (reference.isMany()) {
> List<EObject> list1 = (List<EObject>) value1;
> List<EObject> list2 = (List<EObject>) value2;
> if (reference.isOrdered()) {
> Comparator<EObject> comparator = new
> EObjectComparator(reference.getEKeys());
> Collections.sort(list1, comparator);
> Collections.sort(list2, comparator);
> }
> return equals(list1, list2);
> } else {
> return equals((EObject)value1, (EObject)value2);
> }
> }
>
>
> The comparator sorts depending on the keys, if any are given,
> otherwise it uses toString comparison. The values in the key
> attributes are checked, if they implement java.lang.Comparable, which
> works for Numbers, String, Date and Enums
>
> What do you think of this pattern? Is it something to contribute to
> enhance the EcoreUtil.EqualityHelper? Because this use-case is
> probalby not the most common one, maybe it should be parameterized.
> EcoreUtil.equals(EObject eObject1, EObject eObject2, boolean sort)
>
> By the way my implementation supports ignore-features too, that are
> ignored during comparison when they are not important for the equality.
>
> Regards,
> Mark
|
|
|
Re: EcoreUtil.EqualityHelper and 'ordered' feature [message #1647267 is a reply to message #1647228] |
Tue, 03 March 2015 10:35 |
Ed Merks Messages: 33140 Registered: July 2009 |
Senior Member |
|
|
Mark,
Comments below.
On 03/03/2015 11:12 AM, Mark Hoffmann wrote:
> Hi Ed,
>
> Touche :).
> I agree completely. Some modifications can avoid the modification:
>
>
> protected boolean haveEqualReference(EObject eObject1, EObject
> eObject2, EReference reference) {
> Object value1 = eObject1.eGet(reference);
> Object value2 = eObject2.eGet(reference);
> if (reference.isMany()) {
> List<EObject> list1 = (List<EObject>) value1;
> List<EObject> list2 = (List<EObject>) value2;
> if (reference.isOrdered() && reference.getEKeys().size() > 0) {
> Comparator<EObject> comparator = new
> EObjectComparator(reference.getEKeys());
> list1 = new ArrayList<EObject>(list1);
> list2 = new ArrayList<EObject>(list2);
> Collections.sort(list1, comparator);
> Collections.sort(list2, comparator);
> }
> return equals(list1, list2);
> } else {
> return equals((EObject)value1, (EObject)value2);
> }
> }
>
>
> The question is, do you think it is useful for EcoreUtil.EqualityHelper?
It hard codes quite specific details that I'm not sure are so generally
applicable. What Ed W suggests, i.e., a normalization traversal, seems
more natural, but of course that doesn't deal with your desire to ignore
some features as well. Certainly the Copier and EqualityHelper are
designed to be subclassed quite easily, so additional refactoring to
make that easier (i.e., less need to duplicate significantly large
methods in order to specialize behavior) seems a more palatable (as was
done with the Copier during the previous release)...
>
> Mark
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
| | |
Goto Forum:
Current Time: Wed Apr 24 23:11:20 GMT 2024
Powered by FUDForum. Page generated in 0.04568 seconds
|