From 9e0852cd6798447b274c1375020dda744975431a Mon Sep 17 00:00:00 2001 From: Hannes Wellmann Date: Fri, 20 Sep 2024 18:38:20 +0200 Subject: [PATCH 1/4] Version bumps for 4.34 stream --- bundles/org.eclipse.e4.ui.model.workbench/META-INF/MANIFEST.MF | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.eclipse.e4.ui.model.workbench/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.model.workbench/META-INF/MANIFEST.MF index e5ee3efa821..5bae0a2e538 100644 --- a/bundles/org.eclipse.e4.ui.model.workbench/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.e4.ui.model.workbench/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.e4.ui.model.workbench;singleton:=true -Bundle-Version: 2.4.300.qualifier +Bundle-Version: 2.4.400.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 From d4f741b086cb31336ab547cd4c5ddffd39ec5857 Mon Sep 17 00:00:00 2001 From: Hannes Wellmann Date: Tue, 17 Sep 2024 23:22:03 +0200 Subject: [PATCH 2/4] [E4 Xpath] Unify and clean-up definitions of generic type arguments --- .../xpath/JXPathContextFactoryImpl.java | 9 +++--- .../emf/internal/xpath/JXPathContextImpl.java | 2 +- .../eclipse/e4/emf/xpath/XPathContext.java | 14 ++++----- .../e4/emf/xpath/XPathContextFactory.java | 31 ++++++++----------- 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextFactoryImpl.java b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextFactoryImpl.java index 7d533fbffdb..a07e323ea7c 100644 --- a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextFactoryImpl.java +++ b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextFactoryImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2015 BestSolution.at and others. + * Copyright (c) 2010, 2024 BestSolution.at and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -20,10 +20,9 @@ /** * Factory creating context using JXPath * - * @param - * the object the XPath is created for + * @param the object the XPath is created for */ -public class JXPathContextFactoryImpl extends XPathContextFactory { +public class JXPathContextFactoryImpl extends XPathContextFactory { @Override public XPathContext newContext(XPathContext parentContext, Object contextBean) { @@ -31,7 +30,7 @@ public XPathContext newContext(XPathContext parentContext, Object contextBean) { } @Override - public XPathContext newContext(Type contextBean) { + public XPathContext newContext(T contextBean) { return new JXPathContextImpl(contextBean); } diff --git a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextImpl.java b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextImpl.java index d00443ff6c6..a5b6225d9bf 100644 --- a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextImpl.java +++ b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextImpl.java @@ -89,7 +89,7 @@ public Object getValue(String xpath, Class requiredType) { } @Override - public Iterator iterate(String xpath) { + public Iterator iterate(String xpath) { return context.iterate(xpath); } diff --git a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContext.java b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContext.java index b0347132093..a14160ed31c 100644 --- a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContext.java +++ b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContext.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2015 BestSolution.at and others. + * Copyright (c) 2010, 2024 BestSolution.at and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -46,15 +46,13 @@ public interface XPathContext { /** * Traverses the xpath and returns an Iterator of all results found for the - * path. If the xpath matches no properties in the graph, the Iterator will - * be empty, but not null. + * path. If the xpath matches no properties in the graph, the Iterator will be + * empty, but not null. * - * @param - * the expected object type + * @param the expected object type * - * @param xpath - * to iterate + * @param xpath to iterate * @return Iterator<Object> */ - Iterator iterate(String xpath); + Iterator iterate(String xpath); } diff --git a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContextFactory.java b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContextFactory.java index d120c199701..5689f782614 100644 --- a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContextFactory.java +++ b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContextFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2015 BestSolution.at and others. + * Copyright (c) 2010, 2024 BestSolution.at and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -18,39 +18,34 @@ /** * Factory responsible to create an XPath-Context * - * @param - * the object type the XPath is created for + * @param the object type the XPath is created for */ -public abstract class XPathContextFactory { +public abstract class XPathContextFactory { /** * Creates a new XPathContext with the specified object as the root node. * - * @param contextBean - * Object + * @param contextBean Object * @return XPathContext */ - public abstract XPathContext newContext(Type contextBean); + public abstract XPathContext newContext(T contextBean); /** - * Creates a new XPathContext with the specified bean as the root node and - * the specified parent context. Variables defined in a parent context can - * be referenced in XPaths passed to the child context. + * Creates a new XPathContext with the specified bean as the root node and the + * specified parent context. Variables defined in a parent context can be + * referenced in XPaths passed to the child context. * - * @param parentContext - * parent context - * @param contextBean - * Object + * @param parentContext parent context + * @param contextBean Object * @return XPathContext */ - public abstract XPathContext newContext(XPathContext parentContext, Type contextBean); + public abstract XPathContext newContext(XPathContext parentContext, T contextBean); /** - * @param - * the object type the xpath is created for + * @param the object type the xpath is created for * @return Create a new XPath-Factory */ - public static XPathContextFactory newInstance() { + public static XPathContextFactory newInstance() { return new JXPathContextFactoryImpl<>(); } } From 21144e3de2ece0264a3b57cc93c6f7f6152f7eb1 Mon Sep 17 00:00:00 2001 From: Hannes Wellmann Date: Tue, 17 Sep 2024 23:50:18 +0200 Subject: [PATCH 3/4] [E4 Xpath] Import org.apache.commons.jxpath packages instead of requiring the bundle 'org.apache.commons.jxpath'. This allows interested parties to supply alternative providers than the old and problematic 'org.apache.commons.jxpath'. Helps for https://github.com/eclipse-platform/eclipse.platform.ui/issues/423 --- bundles/org.eclipse.e4.emf.xpath/META-INF/MANIFEST.MF | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bundles/org.eclipse.e4.emf.xpath/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.emf.xpath/META-INF/MANIFEST.MF index 34efac90f62..1290213bb2e 100644 --- a/bundles/org.eclipse.e4.emf.xpath/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.e4.emf.xpath/META-INF/MANIFEST.MF @@ -4,11 +4,15 @@ Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.e4.emf.xpath Bundle-Version: 0.4.300.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 -Require-Bundle: org.apache.commons.jxpath;bundle-version="1.2.0", - org.eclipse.emf.ecore;bundle-version="2.35.0", +Require-Bundle: org.eclipse.emf.ecore;bundle-version="2.35.0", org.eclipse.core.runtime;bundle-version="3.29.0" Export-Package: org.eclipse.e4.emf.internal.xpath;x-internal:=true, org.eclipse.e4.emf.internal.xpath.helper;x-friends:="org.eclipse.e4.emf.xpath.test,org.eclipse.e4.ui.model.workbench,org.eclipse.e4.ui.workbench", org.eclipse.e4.emf.xpath +Import-Package: org.apache.commons.jxpath;version="[1.3.0,2.0.0)", + org.apache.commons.jxpath.ri;version="[1.3.0,2.0.0)", + org.apache.commons.jxpath.ri.compiler;version="[1.3.0,2.0.0)", + org.apache.commons.jxpath.ri.model;version="[1.3.0,2.0.0)", + org.apache.commons.jxpath.util;version="[1.3.0,2.0.0)" Bundle-Vendor: %Bundle-Vendor Automatic-Module-Name: org.eclipse.e4.emf.xpath From b9fe8443ce6f324a5e31d8a4952f3bc654764a92 Mon Sep 17 00:00:00 2001 From: Hannes Wellmann Date: Tue, 17 Sep 2024 23:37:59 +0200 Subject: [PATCH 4/4] Add XPathContext.stream() and strengthen type of getValue(String, Class) --- .../.settings/.api_filters | 11 ++++++++ .../META-INF/MANIFEST.MF | 2 +- .../emf/internal/xpath/JXPathContextImpl.java | 8 ++++-- .../eclipse/e4/emf/xpath/XPathContext.java | 26 ++++++++++++++++++- .../impl/StringModelFragmentImpl.java | 19 +++----------- .../test/ExampleQueriesApplicationTest.java | 3 +++ .../xpath/test/ExampleQueriesTestCase.java | 17 +++++++++--- 7 files changed, 64 insertions(+), 22 deletions(-) create mode 100644 bundles/org.eclipse.e4.emf.xpath/.settings/.api_filters diff --git a/bundles/org.eclipse.e4.emf.xpath/.settings/.api_filters b/bundles/org.eclipse.e4.emf.xpath/.settings/.api_filters new file mode 100644 index 00000000000..8c85f39506c --- /dev/null +++ b/bundles/org.eclipse.e4.emf.xpath/.settings/.api_filters @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bundles/org.eclipse.e4.emf.xpath/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.emf.xpath/META-INF/MANIFEST.MF index 1290213bb2e..74cc46b7049 100644 --- a/bundles/org.eclipse.e4.emf.xpath/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.e4.emf.xpath/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.e4.emf.xpath -Bundle-Version: 0.4.300.qualifier +Bundle-Version: 0.5.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Require-Bundle: org.eclipse.emf.ecore;bundle-version="2.35.0", org.eclipse.core.runtime;bundle-version="3.29.0" diff --git a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextImpl.java b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextImpl.java index a5b6225d9bf..bb35950e263 100644 --- a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextImpl.java +++ b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/internal/xpath/JXPathContextImpl.java @@ -21,6 +21,7 @@ import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.NodeSet; import org.apache.commons.jxpath.Pointer; +import org.apache.commons.jxpath.util.TypeUtils; import org.eclipse.e4.emf.xpath.XPathContext; import org.eclipse.emf.ecore.EObject; @@ -84,8 +85,11 @@ public Object getValue(String xpath) { } @Override - public Object getValue(String xpath, Class requiredType) { - return context.getValue(xpath, requiredType); + public T getValue(String xpath, Class requiredType) { + Object value = context.getValue(xpath, requiredType); + @SuppressWarnings("unchecked") + T typedValue = (T) TypeUtils.convert(value, requiredType); + return typedValue; } @Override diff --git a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContext.java b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContext.java index a14160ed31c..41ead7162c3 100644 --- a/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContext.java +++ b/bundles/org.eclipse.e4.emf.xpath/src/org/eclipse/e4/emf/xpath/XPathContext.java @@ -14,6 +14,12 @@ package org.eclipse.e4.emf.xpath; import java.util.Iterator; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.apache.commons.jxpath.util.TypeUtils; /** * Context in which the xpath is executed @@ -42,7 +48,7 @@ public interface XPathContext { * required type * @return Object found */ - Object getValue(String xpath, Class requiredType); + T getValue(String xpath, Class requiredType); /** * Traverses the xpath and returns an Iterator of all results found for the @@ -55,4 +61,22 @@ public interface XPathContext { * @return Iterator<Object> */ Iterator iterate(String xpath); + + /** + * Traverses the xpath and returns an {@link Stream} of all results found for + * the path. If the xpath matches no properties in the graph, the stream will be + * empty. + * + * @param the expected object type + * @param xpath the xpath expression to iterate + * @param type the type of elements in the returned stream + * @return a stream of elements matching the specified xpath and of the given + * type + * @since 0.5 + */ + default Stream stream(String xpath, Class type) { + Iterator iterator = iterate(xpath); + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false) + .filter(e -> TypeUtils.canConvert(e, type)).map(e -> TypeUtils.convert(e, type)).map(type::cast); + } } diff --git a/bundles/org.eclipse.e4.ui.model.workbench/src/org/eclipse/e4/ui/model/fragment/impl/StringModelFragmentImpl.java b/bundles/org.eclipse.e4.ui.model.workbench/src/org/eclipse/e4/ui/model/fragment/impl/StringModelFragmentImpl.java index 895d3b0663a..fe5007880e1 100644 --- a/bundles/org.eclipse.e4.ui.model.workbench/src/org/eclipse/e4/ui/model/fragment/impl/StringModelFragmentImpl.java +++ b/bundles/org.eclipse.e4.ui.model.workbench/src/org/eclipse/e4/ui/model/fragment/impl/StringModelFragmentImpl.java @@ -16,8 +16,6 @@ package org.eclipse.e4.ui.model.fragment.impl; import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import org.eclipse.e4.emf.xpath.EcoreXPathContextFactory; @@ -355,22 +353,14 @@ private void mergeIdList(MApplication application, List ret private void mergeXPath(MApplication application, List ret, String xPath) { List targetElements; if ("/".equals(xPath)) { - targetElements = Collections.singletonList(application); + targetElements = List.of(application); } else { XPathContextFactory f = EcoreXPathContextFactory.newInstance(); XPathContext xpathContext = f.newContext((EObject) application); - Iterator i = xpathContext.iterate(xPath); - - targetElements = new ArrayList<>(); try { - while (i.hasNext()) { - Object obj = i.next(); - if (obj instanceof MApplicationElement) { - MApplicationElement o = (MApplicationElement) obj; - targetElements.add(o); - } - } + targetElements = xpathContext.stream(xPath, MApplicationElement.class).toList(); } catch (Exception ex) { + targetElements = List.of(); // custom xpath functions will throw exceptions ex.printStackTrace(); } @@ -378,8 +368,7 @@ private void mergeXPath(MApplication application, List ret, for (MApplicationElement targetElement : targetElements) { EStructuralFeature feature = ((EObject) targetElement).eClass().getEStructuralFeature(getFeaturename()); if (feature != null) { - List elements; - elements = new ArrayList<>(); + List elements = new ArrayList<>(); for (MApplicationElement element : getElements()) { elements.add((MApplicationElement) EcoreUtil.copy((EObject) element)); } diff --git a/tests/org.eclipse.e4.emf.xpath.test/src/org/eclipse/e4/emf/xpath/test/ExampleQueriesApplicationTest.java b/tests/org.eclipse.e4.emf.xpath.test/src/org/eclipse/e4/emf/xpath/test/ExampleQueriesApplicationTest.java index c0233f0261e..0fb975b0713 100644 --- a/tests/org.eclipse.e4.emf.xpath.test/src/org/eclipse/e4/emf/xpath/test/ExampleQueriesApplicationTest.java +++ b/tests/org.eclipse.e4.emf.xpath.test/src/org/eclipse/e4/emf/xpath/test/ExampleQueriesApplicationTest.java @@ -85,6 +85,9 @@ public void testAccessingTheMainMenu() { Object menu = xpathContext.getValue("//mainMenu"); assertNotNull(menu); assertTrue(menu instanceof MMenu); + + MMenu mMenu = xpathContext.getValue("//mainMenu", MMenu.class); + assertNotNull(mMenu); } @Test diff --git a/tests/org.eclipse.e4.emf.xpath.test/src/org/eclipse/e4/emf/xpath/test/ExampleQueriesTestCase.java b/tests/org.eclipse.e4.emf.xpath.test/src/org/eclipse/e4/emf/xpath/test/ExampleQueriesTestCase.java index f9c58359915..b6a5d552e2f 100644 --- a/tests/org.eclipse.e4.emf.xpath.test/src/org/eclipse/e4/emf/xpath/test/ExampleQueriesTestCase.java +++ b/tests/org.eclipse.e4.emf.xpath.test/src/org/eclipse/e4/emf/xpath/test/ExampleQueriesTestCase.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue; import java.util.Iterator; +import java.util.List; import org.apache.commons.jxpath.JXPathNotFoundException; import org.eclipse.e4.emf.xpath.EcoreXPathContextFactory; @@ -75,6 +76,9 @@ public void testSimpleQuery() { assertNotNull(application); assertSame(RootImpl.class, application.getClass()); + RootImpl rootApplication = xpathContext.getValue("/", RootImpl.class); + assertNotNull(rootApplication); + application = xpathContext.getValue("."); assertNotNull(application); assertSame(RootImpl.class, application.getClass()); @@ -85,14 +89,19 @@ public void testSimpleQuery() { assertNotNull(application); assertSame(RootImpl.class, application.getClass()); + rootApplication = xpathContext.getValue(".[@id='root']", RootImpl.class); + assertNotNull(rootApplication); + assertEquals("element1",xpathContext.getValue("nodes[1]/@id")); assertEquals(NodeImpl.class, xpathContext.getValue("//.[@id='element2.2']").getClass()); assertEquals(ExtendedNodeImpl.class,xpathContext.getValue("//.[ecore:eClassName(.)='ExtendedNode']").getClass()); + ExtendedNodeImpl extendedNode = xpathContext.getValue("//.[ecore:eClassName(.)='ExtendedNode']", + ExtendedNodeImpl.class); + assertNotNull(extendedNode); } - @Test public void testMenuQuery() { Object application = xpathContext.getValue("/"); @@ -109,8 +118,10 @@ public void testMenuQuery() { assertSame(MenuImpl.class, i.next().getClass()); // EMF model has a loop in it, it just goes back to the top //assertFalse(i.hasNext()); - } - + List list = xpathContext.stream("//.[@id='menu.1']", MenuImpl.class).toList(); + // EMF model has a loop in it, it just goes back to the top + assertEquals(26, list.size()); + } }