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
ConstraintsUtils.java 0f8be020f2ca4bb08931c32452163c04a28e30ce GREEN
EMFResourceUtils.java 979d0e1f4f66a2b3e715d2da0ebef6493f547fd7 GREEN
EcoreSerializerBase.java 0a0c2969d793d2e68094c55c8f7b0a662ef6e5d5 GREEN
EcoreUtils.java 91087233c50130c4abde858d892c6a1e7991e1bf GREEN
EcoreUtils.java 3a41fa0ff5a0ea30a132eeac11cb04edb40ba4fa YELLOW
ExtensionPointUtils.java 7ce63242b49eb9a7cd4eaadd223f5ebce1dfd75b GREEN
HierarchicalNameComparator.java 6face1b673126701a0721af48ead2f9766c17d46 GREEN
IdentifierUtils.java fff43dc4e84cdd89c3ece4f5d9d89aec4b0749c2 GREEN
......
......@@ -17,6 +17,7 @@ package org.fortiss.tooling.kernel.utils;
import static java.util.stream.Collectors.toList;
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.getRootContainer;
import static org.eclipse.emf.ecore.util.EcoreUtil.replace;
......@@ -29,6 +30,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
......@@ -36,7 +38,6 @@ import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.NotificationImpl;
import org.eclipse.emf.common.util.AbstractEList;
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.TreeIterator;
import org.eclipse.emf.ecore.EClass;
......@@ -108,27 +109,41 @@ public class EcoreUtils {
/**
* 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
* unmodifiable thereby it represents only a view over the source list.
* {@link EList} whose elements satisfy the given predicate.
*
* @param target
* a class representing type <code>T</code>.
* @param pred
* {@link Predicate} to test each element of the given list against.
* @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.
*/
@SuppressWarnings("unchecked")
public static <T> EList<T> pickInstanceOf(Class<T> target, List<?> srcList) {
public static <S> EList<?> pickInstanceOf(Predicate<S> pred, List<S> srcList) {
if(srcList == null) {
return null;
}
EList<T> result = new BasicEList<T>();
for(Object sourceElement : srcList) {
if(target.isAssignableFrom(sourceElement.getClass())) {
result.add((T)sourceElement);
EList<S> result = new BasicEList<>();
for(S sourceElement : srcList) {
if(pred.test(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 {
*
* @param targetClasses
* a collection of classes representing types of elements to be picked.
* @param sourceList
* @param srcList
* an EList with objects of type <code>S</code>.
* @return an unmodifiable EList of objects of type <code>S</code> containing only the
* targetClasses instances.
*/
public static <S> EList<S> pickInstanceOf(Collection<Class<?>> targetClasses,
List<S> sourceList) {
if(sourceList == null) {
return null;
}
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);
@SuppressWarnings("unchecked")
public static <S> EList<S> pickInstanceOf(Collection<Class<?>> targetClasses, List<S> srcList) {
Predicate<S> isAssignableFromAny = element -> targetClasses.stream()
.anyMatch(t -> t.isAssignableFrom(element.getClass()));
return (EList<S>)pickInstanceOf(isAssignableFromAny, srcList);
}
/**
......@@ -171,23 +175,38 @@ public class EcoreUtils {
*
* @param targetClass
* a class representing types of elements to be picked.
* @param sourceList
* @param srcList
* 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
* <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) {
return null;
}
EList<S> result = new BasicEList<S>();
for(S sourceElement : sourceList) {
Class<?> sourceClass = sourceElement.getClass();
if(!targetClass.isAssignableFrom(sourceClass)) {
result.add(sourceElement);
if(pred.test(sourceElement)) {
return (T)sourceElement;
}
}
return ECollections.unmodifiableEList(result);
return null;
}
/**
......@@ -200,37 +219,29 @@ public class EcoreUtils {
* 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(Class<T> targetClass, List<S> sourceList) {
if(sourceList == null) {
return null;
}
for(S sourceElement : sourceList) {
if(targetClass.isAssignableFrom(sourceElement.getClass())) {
return (T)sourceElement;
}
}
return null;
Predicate<S> isAssignable = element -> targetClass.isAssignableFrom(element.getClass());
return pickFirstInstanceOf(isAssignable, sourceList);
}
/**
* For a given {@link EObject} recursively returns all its children that have a
* certain type.
* For a given {@link EObject} recursively returns all its children that satisfy the given
* {@link Predicate}.
*
* @param parent
* the parent {@link EObject}.
* @param type
* the type.
* @param pred
* {@link Predicate} to be satisfied by the children.
* @return a list of children.
*/
@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>();
TreeIterator<EObject> content = EcoreUtil.getAllContents(parent, true);
TreeIterator<EObject> content = getAllContents(parent, true);
while(content.hasNext()) {
EObject child = content.next();
if(type.isAssignableFrom(child.getClass())) {
if(pred.test(child)) {
children.add((S)child);
}
}
......@@ -238,49 +249,81 @@ public class EcoreUtils {
}
/**
* 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
* For a given {@link EObject} recursively returns all its children that have the given type.
*
* @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)}.
*
* @param parent
* the parent {@link EObject}
* @param type
* the type
* @param pred
* {@link Predicate} to be satisfied by child elements.
*
* @return the first child of the given type.
*/
@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);
while(content.hasNext()) {
EObject child = content.next();
if(type.isAssignableFrom(child.getClass())) {
if(pred.test(child)) {
return (S)child;
}
}
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
* are found, an empty list is returned.
*
* @param startElement
* @param child
* The {@link EObject} from which the "upwards" search shall begin.
* @param type
* The class type which is used to filter the search.
* @param pred
* {@link Predicate} to be satisfied by parent elements.
* @return List of parent {@link EObject}s of type <code>type</code>.
*/
@SuppressWarnings("unchecked")
public static <T extends EObject> EList<T> getParentsWithType(EObject startElement,
Class<T> type) {
public static <T extends EObject> EList<T> getParentsWith(EObject child,
Predicate<EObject> pred) {
EList<T> parentElements = new BasicEList<T>();
EObject currentParent = startElement.eContainer();
EObject currentParent = child.eContainer();
while(currentParent != null) {
if(type.isAssignableFrom(currentParent.getClass())) {
if(pred.test(currentParent)) {
parentElements.add((T)currentParent);
}
currentParent = currentParent.eContainer();
......@@ -289,21 +332,35 @@ public class EcoreUtils {
}
/**
* Returns the first parent {@link EObject} that has the type <code>T</code>. If none are
* found, null is returned.
* 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.
*
* @param startElement
* @param child
* The {@link EObject} from which the "upwards" search shall begin.
* @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>.
*/
@SuppressWarnings("unchecked")
public static <T extends EObject> T getFirstParentWithType(EObject startElement,
Class<T> type) {
EObject currentParent = startElement.eContainer();
public static <T extends EObject> T getFirstParentWith(EObject child, Predicate<EObject> pred) {
EObject currentParent = child.eContainer();
while(currentParent != null) {
if(type.isAssignableFrom(currentParent.getClass())) {
if(pred.test(currentParent)) {
return (T)currentParent;
}
currentParent = currentParent.eContainer();
......@@ -311,6 +368,21 @@ public class EcoreUtils {
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>.
*
......
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