Skip to content
Snippets Groups Projects
Commit d6639c9c authored by Alexander Diewald's avatar Alexander Diewald
Browse files

EcoreUtils: Functional style for data traversal

parent 4fa969b8
No related branches found
No related tags found
1 merge request!563727
...@@ -2,7 +2,7 @@ CompositionUtils.java 34c0a191bd0fb4176c94b4d61abb5c88a679d5e8 GREEN ...@@ -2,7 +2,7 @@ CompositionUtils.java 34c0a191bd0fb4176c94b4d61abb5c88a679d5e8 GREEN
ConstraintsUtils.java 0f8be020f2ca4bb08931c32452163c04a28e30ce GREEN ConstraintsUtils.java 0f8be020f2ca4bb08931c32452163c04a28e30ce GREEN
EMFResourceUtils.java 979d0e1f4f66a2b3e715d2da0ebef6493f547fd7 GREEN EMFResourceUtils.java 979d0e1f4f66a2b3e715d2da0ebef6493f547fd7 GREEN
EcoreSerializerBase.java 0a0c2969d793d2e68094c55c8f7b0a662ef6e5d5 GREEN EcoreSerializerBase.java 0a0c2969d793d2e68094c55c8f7b0a662ef6e5d5 GREEN
EcoreUtils.java 91087233c50130c4abde858d892c6a1e7991e1bf GREEN EcoreUtils.java 3a41fa0ff5a0ea30a132eeac11cb04edb40ba4fa YELLOW
ExtensionPointUtils.java 7ce63242b49eb9a7cd4eaadd223f5ebce1dfd75b GREEN ExtensionPointUtils.java 7ce63242b49eb9a7cd4eaadd223f5ebce1dfd75b GREEN
HierarchicalNameComparator.java 6face1b673126701a0721af48ead2f9766c17d46 GREEN HierarchicalNameComparator.java 6face1b673126701a0721af48ead2f9766c17d46 GREEN
IdentifierUtils.java fff43dc4e84cdd89c3ece4f5d9d89aec4b0749c2 GREEN IdentifierUtils.java fff43dc4e84cdd89c3ece4f5d9d89aec4b0749c2 GREEN
......
...@@ -17,6 +17,7 @@ package org.fortiss.tooling.kernel.utils; ...@@ -17,6 +17,7 @@ package org.fortiss.tooling.kernel.utils;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import static org.eclipse.emf.common.notify.Notification.EVENT_TYPE_COUNT; import static org.eclipse.emf.common.notify.Notification.EVENT_TYPE_COUNT;
import static org.eclipse.emf.common.util.ECollections.unmodifiableEList;
import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents; import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
import static org.eclipse.emf.ecore.util.EcoreUtil.getRootContainer; import static org.eclipse.emf.ecore.util.EcoreUtil.getRootContainer;
import static org.eclipse.emf.ecore.util.EcoreUtil.replace; import static org.eclipse.emf.ecore.util.EcoreUtil.replace;
...@@ -29,6 +30,7 @@ import java.util.HashSet; ...@@ -29,6 +30,7 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
...@@ -36,7 +38,6 @@ import org.eclipse.emf.common.notify.Notification; ...@@ -36,7 +38,6 @@ import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.NotificationImpl; import org.eclipse.emf.common.notify.impl.NotificationImpl;
import org.eclipse.emf.common.util.AbstractEList; import org.eclipse.emf.common.util.AbstractEList;
import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClass;
...@@ -108,27 +109,41 @@ public class EcoreUtils { ...@@ -108,27 +109,41 @@ public class EcoreUtils {
/** /**
* From a given {@link EList} with objects of type <code>S</code>, create another unmodifiable * From a given {@link EList} with objects of type <code>S</code>, create another unmodifiable
* {@link EList} with objects of type <code>T</code>. The resulting {@link EList} is * {@link EList} whose elements satisfy the given predicate.
* unmodifiable thereby it represents only a view over the source list.
* *
* @param target * @param pred
* a class representing type <code>T</code>. * {@link Predicate} to test each element of the given list against.
* @param srcList * @param srcList
* an EList with objects of type <code>S</code>. * an EList with objects to tested.
* @return an unmodifiable EList of objects of type T. * @return an unmodifiable EList of objects of type T.
*/ */
@SuppressWarnings("unchecked") public static <S> EList<?> pickInstanceOf(Predicate<S> pred, List<S> srcList) {
public static <T> EList<T> pickInstanceOf(Class<T> target, List<?> srcList) {
if(srcList == null) { if(srcList == null) {
return null; return null;
} }
EList<T> result = new BasicEList<T>(); EList<S> result = new BasicEList<>();
for(Object sourceElement : srcList) { for(S sourceElement : srcList) {
if(target.isAssignableFrom(sourceElement.getClass())) { if(pred.test(sourceElement)) {
result.add((T)sourceElement); result.add(sourceElement);
} }
} }
return ECollections.unmodifiableEList(result); return unmodifiableEList(result);
}
/**
* From a given {@link EList} with objects of type <code>S</code>, create another unmodifiable
* {@link EList} with objects of type <code>T</code> if assignable.
*
* @param target
* a class representing type <code>T</code>.
* @param srcList
* an EList with objects to tested.
* @return an unmodifiable EList of objects of type T.
*/
@SuppressWarnings("unchecked")
public static <S, T> EList<T> pickInstanceOf(Class<T> target, List<S> srcList) {
Predicate<S> isAssignable = element -> target.isAssignableFrom(element.getClass());
return (EList<T>)pickInstanceOf(isAssignable, srcList);
} }
/** /**
...@@ -140,27 +155,16 @@ public class EcoreUtils { ...@@ -140,27 +155,16 @@ public class EcoreUtils {
* *
* @param targetClasses * @param targetClasses
* a collection of classes representing types of elements to be picked. * a collection of classes representing types of elements to be picked.
* @param sourceList * @param srcList
* an EList with objects of type <code>S</code>. * an EList with objects of type <code>S</code>.
* @return an unmodifiable EList of objects of type <code>S</code> containing only the * @return an unmodifiable EList of objects of type <code>S</code> containing only the
* targetClasses instances. * targetClasses instances.
*/ */
public static <S> EList<S> pickInstanceOf(Collection<Class<?>> targetClasses, @SuppressWarnings("unchecked")
List<S> sourceList) { public static <S> EList<S> pickInstanceOf(Collection<Class<?>> targetClasses, List<S> srcList) {
if(sourceList == null) { Predicate<S> isAssignableFromAny = element -> targetClasses.stream()
return null; .anyMatch(t -> t.isAssignableFrom(element.getClass()));
} return (EList<S>)pickInstanceOf(isAssignableFromAny, srcList);
EList<S> result = new BasicEList<S>();
for(S sourceElement : sourceList) {
Class<?> sourceClass = sourceElement.getClass();
for(Class<?> targetClass : targetClasses) {
if(targetClass.isAssignableFrom(sourceClass)) {
result.add(sourceElement);
break;
}
}
}
return ECollections.unmodifiableEList(result);
} }
/** /**
...@@ -171,23 +175,38 @@ public class EcoreUtils { ...@@ -171,23 +175,38 @@ public class EcoreUtils {
* *
* @param targetClass * @param targetClass
* a class representing types of elements to be picked. * a class representing types of elements to be picked.
* @param sourceList * @param srcList
* an {@link EList} with objects of type <code>S</code>. * an {@link EList} with objects of type <code>S</code>.
* @return an unmodifiable {@link EList} of objects of type <code>S</code> containing only the * @return an unmodifiable {@link EList} of objects of type <code>S</code> containing only the
* <code>targetClass</code> instances * <code>targetClass</code> instances
*/ */
public static <S> EList<S> filterOutInstanceOf(Class<?> targetClass, List<S> sourceList) { @SuppressWarnings("unchecked")
public static <S> EList<S> filterOutInstanceOf(Class<?> targetClass, List<S> srcList) {
Predicate<S> isNotAssignable = element -> !targetClass.isAssignableFrom(element.getClass());
return (EList<S>)pickInstanceOf(isNotAssignable, srcList);
}
/**
* From a given {@link EList} with source objects of type <code>S</code> pick the first object
* which satisfies the given {@link Predicate}.
*
* @param pred
* {@link Predicate} to test elements of the given list against.
* @param sourceList
* an {@link EList} with objects of type <code>S</code>.
* @return an object of type <code>T</code> or <code>null</code> if none exists.
*/
@SuppressWarnings("unchecked")
public static <S, T extends S> T pickFirstInstanceOf(Predicate<S> pred, List<S> sourceList) {
if(sourceList == null) { if(sourceList == null) {
return null; return null;
} }
EList<S> result = new BasicEList<S>();
for(S sourceElement : sourceList) { for(S sourceElement : sourceList) {
Class<?> sourceClass = sourceElement.getClass(); if(pred.test(sourceElement)) {
if(!targetClass.isAssignableFrom(sourceClass)) { return (T)sourceElement;
result.add(sourceElement);
} }
} }
return ECollections.unmodifiableEList(result); return null;
} }
/** /**
...@@ -200,37 +219,29 @@ public class EcoreUtils { ...@@ -200,37 +219,29 @@ public class EcoreUtils {
* an {@link EList} with objects of type <code>S</code>. * an {@link EList} with objects of type <code>S</code>.
* @return an object of type <code>T</code> or <code>null</code> if none exists. * @return an object of type <code>T</code> or <code>null</code> if none exists.
*/ */
@SuppressWarnings("unchecked")
public static <S, T extends S> T pickFirstInstanceOf(Class<T> targetClass, List<S> sourceList) { public static <S, T extends S> T pickFirstInstanceOf(Class<T> targetClass, List<S> sourceList) {
if(sourceList == null) { Predicate<S> isAssignable = element -> targetClass.isAssignableFrom(element.getClass());
return null; return pickFirstInstanceOf(isAssignable, sourceList);
}
for(S sourceElement : sourceList) {
if(targetClass.isAssignableFrom(sourceElement.getClass())) {
return (T)sourceElement;
}
}
return null;
} }
/** /**
* For a given {@link EObject} recursively returns all its children that have a * For a given {@link EObject} recursively returns all its children that satisfy the given
* certain type. * {@link Predicate}.
* *
* @param parent * @param parent
* the parent {@link EObject}. * the parent {@link EObject}.
* @param type * @param pred
* the type. * {@link Predicate} to be satisfied by the children.
* @return a list of children. * @return a list of children.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <S> EList<S> getChildrenWithType(EObject parent, Class<S> type) { public static <S> EList<S> getChildrenWith(EObject parent, Predicate<EObject> pred) {
EList<S> children = new BasicEList<S>(); EList<S> children = new BasicEList<S>();
TreeIterator<EObject> content = EcoreUtil.getAllContents(parent, true); TreeIterator<EObject> content = getAllContents(parent, true);
while(content.hasNext()) { while(content.hasNext()) {
EObject child = content.next(); EObject child = content.next();
if(type.isAssignableFrom(child.getClass())) { if(pred.test(child)) {
children.add((S)child); children.add((S)child);
} }
} }
...@@ -238,49 +249,81 @@ public class EcoreUtils { ...@@ -238,49 +249,81 @@ public class EcoreUtils {
} }
/** /**
* For a given {@link EObject}, recursively returns the first child that has a certain type. * For a given {@link EObject} recursively returns all its children that have the given type.
* Using this method is more efficient than returning the first element of the result of *
* @param parent
* the parent {@link EObject}.
* @param type
* the type.
* @return a list of children.
*/
public static <S> EList<S> getChildrenWithType(EObject parent, Class<S> type) {
Predicate<EObject> isAssignable = element -> type.isAssignableFrom(element.getClass());
return getChildrenWith(parent, isAssignable);
}
/**
* For a given {@link EObject}, recursively returns the first child that satisfies the given
* {@link Predicate}.
* This method is more efficient than returning the first element of the result of
* {@link #getChildrenWithType(EObject, Class)}. * {@link #getChildrenWithType(EObject, Class)}.
* *
* @param parent * @param parent
* the parent {@link EObject} * the parent {@link EObject}
* @param type * @param pred
* the type * {@link Predicate} to be satisfied by child elements.
* *
* @return the first child of the given type. * @return the first child of the given type.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <S> S getFirstChildWithType(EObject parent, Class<S> type) { public static <S> S getFirstChildWith(EObject parent, Predicate<EObject> pred) {
TreeIterator<EObject> content = EcoreUtil.getAllContents(parent, true); TreeIterator<EObject> content = EcoreUtil.getAllContents(parent, true);
while(content.hasNext()) { while(content.hasNext()) {
EObject child = content.next(); EObject child = content.next();
if(type.isAssignableFrom(child.getClass())) { if(pred.test(child)) {
return (S)child; return (S)child;
} }
} }
return null; return null;
} }
/**
* For a given {@link EObject}, recursively returns the first child that has a certain type.
* Using this method is more efficient than returning the first element of the result of
* {@link #getChildrenWithType(EObject, Class)}.
*
* @param parent
* the parent {@link EObject}
* @param type
* the type
*
* @return the first child of the given type.
*/
public static <S> S getFirstChildWithType(EObject parent, Class<S> type) {
Predicate<EObject> isAssignable = element -> type.isAssignableFrom(element.getClass());
return getFirstChildWith(parent, isAssignable);
}
/** /**
* Returns a list of all parent {@link EObject}s that have the type <code>type</code>. If none * Returns a list of all parent {@link EObject}s that have the type <code>type</code>. If none
* are found, an empty list is returned. * are found, an empty list is returned.
* *
* @param startElement * @param child
* The {@link EObject} from which the "upwards" search shall begin. * The {@link EObject} from which the "upwards" search shall begin.
* @param type * @param pred
* The class type which is used to filter the search. * {@link Predicate} to be satisfied by parent elements.
* @return List of parent {@link EObject}s of type <code>type</code>. * @return List of parent {@link EObject}s of type <code>type</code>.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends EObject> EList<T> getParentsWithType(EObject startElement, public static <T extends EObject> EList<T> getParentsWith(EObject child,
Class<T> type) { Predicate<EObject> pred) {
EList<T> parentElements = new BasicEList<T>(); EList<T> parentElements = new BasicEList<T>();
EObject currentParent = startElement.eContainer(); EObject currentParent = child.eContainer();
while(currentParent != null) { while(currentParent != null) {
if(type.isAssignableFrom(currentParent.getClass())) { if(pred.test(currentParent)) {
parentElements.add((T)currentParent); parentElements.add((T)currentParent);
} }
currentParent = currentParent.eContainer(); currentParent = currentParent.eContainer();
...@@ -289,21 +332,35 @@ public class EcoreUtils { ...@@ -289,21 +332,35 @@ public class EcoreUtils {
} }
/** /**
* Returns the first parent {@link EObject} that has the type <code>T</code>. If none are * Returns a list of all parent {@link EObject}s that have the type <code>type</code>. If none
* found, null is returned. * are found, an empty list is returned.
* *
* @param startElement * @param child
* The {@link EObject} from which the "upwards" search shall begin. * The {@link EObject} from which the "upwards" search shall begin.
* @param type * @param type
* The class type to find the first parent with. * The class type which is used to filter the search.
* @return List of parent {@link EObject}s of type <code>type</code>.
*/
public static <T extends EObject> EList<T> getParentsWithType(EObject child, Class<T> type) {
Predicate<EObject> isAssignable = element -> type.isAssignableFrom(element.getClass());
return getParentsWith(child, isAssignable);
}
/**
* Returns the first parent {@link EObject} that satisfies the given {@link Predicate}. If none
* are found, null is returned.
*
* @param child
* The {@link EObject} from which the "upwards" search shall begin.
* @param pred
* {@link Predicate} to be satisfied by parent elements.
* @return List of parent {EObject} of type <code>T</code>. * @return List of parent {EObject} of type <code>T</code>.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends EObject> T getFirstParentWithType(EObject startElement, public static <T extends EObject> T getFirstParentWith(EObject child, Predicate<EObject> pred) {
Class<T> type) { EObject currentParent = child.eContainer();
EObject currentParent = startElement.eContainer();
while(currentParent != null) { while(currentParent != null) {
if(type.isAssignableFrom(currentParent.getClass())) { if(pred.test(currentParent)) {
return (T)currentParent; return (T)currentParent;
} }
currentParent = currentParent.eContainer(); currentParent = currentParent.eContainer();
...@@ -311,6 +368,21 @@ public class EcoreUtils { ...@@ -311,6 +368,21 @@ public class EcoreUtils {
return null; return null;
} }
/**
* Returns the first parent {@link EObject} that has the type <code>T</code>. If none are
* found, null is returned.
*
* @param child
* The {@link EObject} from which the "upwards" search shall begin.
* @param type
* Type of the parent that is searched.
* @return List of parent {EObject} of type <code>T</code>.
*/
public static <T extends EObject> T getFirstParentWithType(EObject child, Class<T> type) {
Predicate<EObject> isAssignable = element -> type.isAssignableFrom(element.getClass());
return getFirstParentWith(child, isAssignable);
}
/** /**
* Returns true if <code>candidateAncestor</code> is an ancestor of <code>startElement</code>. * Returns true if <code>candidateAncestor</code> is an ancestor of <code>startElement</code>.
* *
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment