Merge pull request #4118 from apache/delivery
Sync delivery to release140 for 14-rc4
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/LspTreeViewServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/LspTreeViewServiceImpl.java
index f554c0a..288a2e3 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/LspTreeViewServiceImpl.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/LspTreeViewServiceImpl.java
@@ -28,6 +28,8 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import org.eclipse.lsp4j.jsonrpc.services.JsonSegment;
import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.services.LanguageClientAware;
@@ -48,6 +50,8 @@
*/
@JsonSegment("nodes")
public class LspTreeViewServiceImpl implements TreeViewService, LanguageClientAware {
+ private static final Logger LOG = Logger.getLogger(LspTreeViewServiceImpl.class.getName());
+
private final Lookup sessionLookup;
/**
* The delegate tree service.
@@ -62,6 +66,7 @@
@Override
protected void notifyItemChanged(NodeChangedParams itemId) {
if (langClient != null) {
+ LOG.log(Level.FINER, "Firing item {0} changed", itemId);
langClient.notifyNodeChange(itemId);
}
}
@@ -127,6 +132,7 @@
// export const info = new ProtocolRequestType<NodeOperationParams, Data, never,void, void>('nodes/info');
public CompletableFuture<TreeItem> info(NodeOperationParams params) {
int nodeId = params.getNodeId();
+ LOG.log(Level.FINER, "> info({0})", nodeId);
TreeViewProvider tvp = treeService.providerOf(nodeId);
return tvp.getTreeItem(nodeId).toCompletableFuture();
}
@@ -141,6 +147,7 @@
@Override
public CompletableFuture<int[]> getChildren(NodeOperationParams params) {
int id = params.getNodeId();
+ LOG.log(Level.FINER, "> children({0})", id);
TreeViewProvider tvp = treeService.providerOf(id);
return tvp.getChildren(id).toCompletableFuture();
}
@@ -154,6 +161,7 @@
@Override
public CompletableFuture<Boolean> delete(NodeOperationParams params) {
int id = params.getNodeId();
+ LOG.log(Level.FINER, "> delete({0})", id);
TreeViewProvider tvp = treeService.providerOf(id);
if (tvp != null) {
Node n = tvp.findNode(id);
@@ -186,6 +194,7 @@
@Override
public CompletableFuture<int[]> findPath(FindPathParams params) {
Object toSelect = params.getSelectData();
+ LOG.log(Level.FINER, "> findPath(fromId = {0}, select = {1})", new Object[] { params.getRootNodeId(), toSelect });
TreeViewProvider tvp = treeService.providerOf(params.getRootNodeId());
if (tvp == null) {
return null;
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/TreeItem.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/TreeItem.java
index 0c06aa7..5c43ef2 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/TreeItem.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/TreeItem.java
@@ -109,4 +109,11 @@
this.resourceUri = URLMapper.findURL(fo, URLMapper.EXTERNAL).toString();
}
}
+
+ public String toString() {
+ return String.format(
+ "TreeItem[%s, id = %d, resource = %s, context = %s",
+ name, id, resourceUri, contextValue
+ );
+ }
}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/TreeViewProvider.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/TreeViewProvider.java
index 7171331..4f67ccc 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/TreeViewProvider.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/TreeViewProvider.java
@@ -34,14 +34,12 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
-import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.logging.Level;
@@ -137,46 +135,56 @@
private SortedMap<Integer, NodeHolder> holdChildren = new TreeMap<>();
/**
- * Node > identity map.
+ * Node > identity map. Note that FilterNodes equals compare the original node, so
+ * IdentityHashMap-style map must be used.
*/
// @GuardedBy(this)
- private Map<Node, Integer> idMap = new WeakHashMap<>();
+ private WeakIdentityMap<Node, Integer> idMap = WeakIdentityMap.newHashMap();
protected TreeViewProvider(String treeId, ExplorerManager manager, TreeNodeRegistry registry, Lookup context) {
this.treeId = treeId;
this.context = context;
this.manager = manager;
+
+ Node n;
this.nodeRegistry = registry;
this.nodeListener = new NodeListener() {
@Override
public void childrenAdded(NodeMemberEvent ev) {
+ LOG.log(Level.FINER, "tree {0} children of node {2} added: {1}", new Object[] { treeId, ev, ev.getNode() });
notifyChange(ev.getNode());
}
@Override
public void childrenRemoved(NodeMemberEvent ev) {
+ LOG.log(Level.FINER, "tree {0} children of node {2} removed: {1}", new Object[] { treeId, ev, ev.getNode() });
notifyChange(ev.getNode());
}
@Override
public void childrenReordered(NodeReorderEvent ev) {
+ LOG.log(Level.FINER, "tree {0} children of node {2} reordered: {1}", new Object[] { treeId, ev, ev.getNode() });
notifyChange(ev.getNode());
}
@Override
public void nodeDestroyed(NodeEvent ev) {
+ LOG.log(Level.FINER, "tree {0} children of node {2} destroyed: {1}", new Object[] { treeId, ev, ev.getNode() });
removeNode(ev.getNode());
notifyChange(ev.getNode());
}
@Override
public void propertyChange(PropertyChangeEvent ev) {
+ LOG.log(Level.FINER, "tree {0} property of node {2} changed: {1}", new Object[] { treeId, ev, ev.getSource()});
notifyChange((Node) ev.getSource());
}
private void notifyChange(Node src) {
- onDidChangeTreeData(src, findId(src));
+ int id = findId(src);
+ LOG.log(Level.FINER, "tree {0} tree item changed: {1}", new Object[] { treeId, id});
+ onDidChangeTreeData(src, id);
}
};
factories = context.lookupResult(TreeDataProvider.Factory.class);
@@ -368,6 +376,7 @@
* @return a TreeItem suitable for LSP transmit
*/
public TreeItem findTreeItem(Node n) {
+ LOG.log(Level.FINER, "Finding tree item for node {0}", n);
TreeDataProvider[] pa = this.providers;
String v;
boolean expanded;
@@ -411,7 +420,7 @@
if (data.getResourceURI() != null) {
ti.resourceUri = data.getResourceURI().toString();
}
-
+ LOG.log(Level.FINER, "Finding tree item for node {0} => {1} ", new Object[] { n, ti });
return ti;
}
@@ -444,7 +453,7 @@
nh.id2Child = newId2Node;
}
if (LOG.isLoggable(Level.FINER)) {
- LOG.log(Level.FINER, "Children of id {0}: {1}", new Object[] { parentId, Arrays.asList(ids) });
+ LOG.log(Level.FINER, "Children of id {0}: {1}", new Object[] { parentId, Arrays.toString(ids) });
}
if (obsolete != null) {
synchronized (this) {
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/WeakIdentityMap.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/WeakIdentityMap.java
new file mode 100644
index 0000000..f061a03
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/WeakIdentityMap.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.explorer;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Implements a combination of {@link java.util.WeakHashMap} and {@link java.util.IdentityHashMap}.
+ * Useful for caches that need to key off of a {@code ==} comparison instead of a {@code .equals}.
+ *
+ * The code was originally part of Apache Lucene
+ */
+public final class WeakIdentityMap<K, V> {
+ private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
+ private final Map<IdentityWeakReference, V> backingStore;
+ private final boolean reapOnRead;
+
+ /**
+ * Creates a new {@code WeakIdentityMap} based on a non-synchronized {@link HashMap}. The map <a
+ * href="#reapInfo">cleans up the reference queue on every read operation</a>.
+ */
+ public static <K, V> WeakIdentityMap<K, V> newHashMap() {
+ return newHashMap(true);
+ }
+
+ /**
+ * Creates a new {@code WeakIdentityMap} based on a non-synchronized {@link HashMap}.
+ *
+ * @param reapOnRead controls if the map <a href="#reapInfo">cleans up the reference queue on
+ * every read operation</a>.
+ */
+ public static <K, V> WeakIdentityMap<K, V> newHashMap(boolean reapOnRead) {
+ return new WeakIdentityMap<>(new HashMap<IdentityWeakReference, V>(), reapOnRead);
+ }
+
+ /**
+ * Creates a new {@code WeakIdentityMap} based on a {@link ConcurrentHashMap}. The map <a
+ * href="#reapInfo">cleans up the reference queue on every read operation</a>.
+ */
+ public static <K, V> WeakIdentityMap<K, V> newConcurrentHashMap() {
+ return newConcurrentHashMap(true);
+ }
+
+ /**
+ * Creates a new {@code WeakIdentityMap} based on a {@link ConcurrentHashMap}.
+ *
+ * @param reapOnRead controls if the map <a href="#reapInfo">cleans up the reference queue on
+ * every read operation</a>.
+ */
+ public static <K, V> WeakIdentityMap<K, V> newConcurrentHashMap(boolean reapOnRead) {
+ return new WeakIdentityMap<>(new ConcurrentHashMap<IdentityWeakReference, V>(), reapOnRead);
+ }
+
+ /** Private only constructor, to create use the static factory methods. */
+ private WeakIdentityMap(Map<IdentityWeakReference, V> backingStore, boolean reapOnRead) {
+ this.backingStore = backingStore;
+ this.reapOnRead = reapOnRead;
+ }
+
+ /** Removes all of the mappings from this map. */
+ public void clear() {
+ backingStore.clear();
+ reap();
+ }
+
+ /** Returns {@code true} if this map contains a mapping for the specified key. */
+ public boolean containsKey(Object key) {
+ if (reapOnRead) reap();
+ return backingStore.containsKey(new IdentityWeakReference(key, null));
+ }
+
+ /** Returns the value to which the specified key is mapped. */
+ public V get(Object key) {
+ if (reapOnRead) reap();
+ return backingStore.get(new IdentityWeakReference(key, null));
+ }
+
+ /**
+ * Associates the specified value with the specified key in this map. If the map previously
+ * contained a mapping for this key, the old value is replaced.
+ */
+ public V put(K key, V value) {
+ reap();
+ return backingStore.put(new IdentityWeakReference(key, queue), value);
+ }
+
+ /** Returns {@code true} if this map contains no key-value mappings. */
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ /**
+ * Removes the mapping for a key from this weak hash map if it is present. Returns the value to
+ * which this map previously associated the key, or {@code null} if the map contained no mapping
+ * for the key. A return value of {@code null} does not necessarily indicate that the map
+ * contained.
+ */
+ public V remove(Object key) {
+ reap();
+ return backingStore.remove(new IdentityWeakReference(key, null));
+ }
+
+ /**
+ * Returns the number of key-value mappings in this map. This result is a snapshot, and may not
+ * reflect unprocessed entries that will be removed before next attempted access because they are
+ * no longer referenced.
+ */
+ public int size() {
+ if (backingStore.isEmpty()) return 0;
+ if (reapOnRead) reap();
+ return backingStore.size();
+ }
+
+ /**
+ * Returns an iterator over all weak keys of this map. Keys already garbage collected will not be
+ * returned. This Iterator does not support removals.
+ */
+ public Iterator<K> keyIterator() {
+ reap();
+ final Iterator<IdentityWeakReference> iterator = backingStore.keySet().iterator();
+ // IMPORTANT: Don't use oal.util.FilterIterator here:
+ // We need *strong* reference to current key after setNext()!!!
+ return new Iterator<K>() {
+ // holds strong reference to next element in backing iterator:
+ private Object next = null;
+ // the backing iterator was already consumed:
+ private boolean nextIsSet = false;
+
+ @Override
+ public boolean hasNext() {
+ return nextIsSet || setNext();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public K next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ assert nextIsSet;
+ try {
+ return (K) next;
+ } finally {
+ // release strong reference and invalidate current value:
+ nextIsSet = false;
+ next = null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ private boolean setNext() {
+ assert !nextIsSet;
+ while (iterator.hasNext()) {
+ next = iterator.next().get();
+ if (next == null) {
+ // the key was already GCed, we can remove it from backing map:
+ iterator.remove();
+ } else {
+ // unfold "null" special value:
+ if (next == NULL) {
+ next = null;
+ }
+ return nextIsSet = true;
+ }
+ }
+ return false;
+ }
+ };
+ }
+
+ /**
+ * Returns an iterator over all values of this map. This iterator may return values whose key is
+ * already garbage collected while iterator is consumed, especially if {@code reapOnRead} is
+ * {@code false}.
+ */
+ public Iterator<V> valueIterator() {
+ if (reapOnRead) reap();
+ return backingStore.values().iterator();
+ }
+
+ /**
+ * This method manually cleans up the reference queue to remove all garbage collected key/value
+ * pairs from the map. Calling this method is not needed if {@code reapOnRead = true}. Otherwise
+ * it might be a good idea to call this method when there is spare time (e.g. from a background
+ * thread).
+ *
+ * @see <a href="#reapInfo">Information about the <code>reapOnRead</code> setting</a>
+ */
+ public void reap() {
+ Reference<?> zombie;
+ while ((zombie = queue.poll()) != null) {
+ backingStore.remove(zombie);
+ }
+ }
+
+ // we keep a hard reference to our NULL key, so map supports null keys that never get GCed:
+ static final Object NULL = new Object();
+
+ private static final class IdentityWeakReference extends WeakReference<Object> {
+ private final int hash;
+
+ IdentityWeakReference(Object obj, ReferenceQueue<Object> queue) {
+ super(obj == null ? NULL : obj, queue);
+ hash = System.identityHashCode(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o instanceof IdentityWeakReference) {
+ final IdentityWeakReference ref = (IdentityWeakReference) o;
+ if (this.get() == ref.get()) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/java.lsp.server/vscode/CHANGELOG.md b/java/java.lsp.server/vscode/CHANGELOG.md
index 11b842e..c3e8b2d 100644
--- a/java/java.lsp.server/vscode/CHANGELOG.md
+++ b/java/java.lsp.server/vscode/CHANGELOG.md
@@ -20,6 +20,11 @@
under the License.
-->
+## Version 14.0
+* Workaround for VSCode 1.67 error which breaks Projects explorer icon
+* Remove HTML tags from project problem messages
+* Fixes for Gradle projects and LSP
+
## Version 13.0.301
* Added base code completion for Spock test framework
* Spock Block Names are offered inside methods if the class extends Spock Specification
diff --git a/java/java.lsp.server/vscode/src/explorer.ts b/java/java.lsp.server/vscode/src/explorer.ts
index 45307bd..ac99bfb 100644
--- a/java/java.lsp.server/vscode/src/explorer.ts
+++ b/java/java.lsp.server/vscode/src/explorer.ts
@@ -198,11 +198,11 @@
public findProductIcon(res : vscode.Uri, ...values: string[]) : string | ThemeIcon | undefined {
const s : string = res.toString();
outer: for (let e of this.entries) {
- if (e.uriRegexp.exec(s)) {
+ if (e.uriRegexp.test(s)) {
if (e.valueRegexps) {
let s : string = " " + values.join(" ") + " ";
for (let vr of e.valueRegexps) {
- if (!vr.exec(s)) {
+ if (!vr.test(s)) {
continue outer;
}
}
@@ -402,9 +402,10 @@
return this.wrap(async (arr) => {
const pn : number = Number(element.parent?.id) || -1;
let fetched = await this.queryVisualizer(element, arr, () => this.fetchItem(pn, n));
+ let origin : vscode.TreeItem;
if (fetched) {
element.update(fetched);
- return self.getTreeItem2(fetched);
+ origin = await self.getTreeItem2(fetched);
} else {
// fire a change, this was unexpected
const pn : number = Number(element.parent?.id) || -1;
@@ -412,8 +413,27 @@
if (pv) {
this.fireItemChange(pv);
}
- return element;
+ origin = element;
}
+ let ti : vscode.TreeItem = new vscode.TreeItem(origin.label || "", origin.collapsibleState);
+
+ // See #4113 -- vscode broke icons display, if resourceUri is defined in TreeItem. We're OK with files,
+ // but folders can have a semantic icon, so let hide resourceUri from vscode for folders.
+ ti.command = origin.command;
+ ti.contextValue = origin.contextValue;
+ ti.description = origin.description;
+ ti.iconPath = origin.iconPath;
+ ti.id = origin.id;
+ ti.label = origin.label;
+ ti.tooltip = origin.tooltip;
+ ti.accessibilityInformation = origin.accessibilityInformation;
+
+ if (origin.resourceUri) {
+ if (!origin.resourceUri.toString().endsWith("/")) {
+ ti.resourceUri = origin.resourceUri;
+ }
+ }
+ return ti;
});
}
diff --git a/java/libs.javacapi/external/binaries-list b/java/libs.javacapi/external/binaries-list
index a6c5b19..cb152e0 100644
--- a/java/libs.javacapi/external/binaries-list
+++ b/java/libs.javacapi/external/binaries-list
@@ -14,5 +14,5 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-2449F4A630A5493F55CC013CF452632AE93007CA com.dukescript.nbjavac:nb-javac:jdk-18+36:api
-DC722E7A5691677C02F315A7E669BE20C47E70B1 com.dukescript.nbjavac:nb-javac:jdk-18+36
+ECA15E615777CE6E7550F71EF312B8CEEBCBE0BD com.dukescript.nbjavac:nb-javac:jdk-18.0.1+10:api
+3AD512FBC8830D89AC70D0CA59397C4868789DCC com.dukescript.nbjavac:nb-javac:jdk-18.0.1+10
diff --git a/java/libs.javacapi/external/nb-javac-jdk-18+36-license.txt b/java/libs.javacapi/external/nb-javac-jdk-18.0.1+10-license.txt
similarity index 99%
rename from java/libs.javacapi/external/nb-javac-jdk-18+36-license.txt
rename to java/libs.javacapi/external/nb-javac-jdk-18.0.1+10-license.txt
index 6b27fab..2329bc0 100644
--- a/java/libs.javacapi/external/nb-javac-jdk-18+36-license.txt
+++ b/java/libs.javacapi/external/nb-javac-jdk-18.0.1+10-license.txt
@@ -1,7 +1,7 @@
Name: Javac Compiler Implementation
Description: Javac Compiler Implementation
-Version: jdk-18+36
-Files: nb-javac-jdk-18+36-api.jar nb-javac-jdk-18+36.jar
+Version: 18.0.1+10
+Files: nb-javac-jdk-18.0.1+10-api.jar nb-javac-jdk-18.0.1+10.jar
License: GPL-2-CP
Origin: OpenJDK (https://github.com/openjdk/jdk18)
Source: https://github.com/openjdk/jdk18
diff --git a/java/libs.javacapi/nbproject/project.xml b/java/libs.javacapi/nbproject/project.xml
index da8430a..905d81b 100644
--- a/java/libs.javacapi/nbproject/project.xml
+++ b/java/libs.javacapi/nbproject/project.xml
@@ -40,11 +40,11 @@
</public-packages>
<class-path-extension>
<runtime-relative-path />
- <binary-origin>external/nb-javac-jdk-18+36-api.jar</binary-origin>
+ <binary-origin>external/nb-javac-jdk-18.0.1+10-api.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path />
- <binary-origin>external/nb-javac-jdk-18+36.jar</binary-origin>
+ <binary-origin>external/nb-javac-jdk-18.0.1+10.jar</binary-origin>
</class-path-extension>
</data>
</configuration>
diff --git a/java/libs.nbjavacapi/external/binaries-list b/java/libs.nbjavacapi/external/binaries-list
index a6c5b19..cb152e0 100644
--- a/java/libs.nbjavacapi/external/binaries-list
+++ b/java/libs.nbjavacapi/external/binaries-list
@@ -14,5 +14,5 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-2449F4A630A5493F55CC013CF452632AE93007CA com.dukescript.nbjavac:nb-javac:jdk-18+36:api
-DC722E7A5691677C02F315A7E669BE20C47E70B1 com.dukescript.nbjavac:nb-javac:jdk-18+36
+ECA15E615777CE6E7550F71EF312B8CEEBCBE0BD com.dukescript.nbjavac:nb-javac:jdk-18.0.1+10:api
+3AD512FBC8830D89AC70D0CA59397C4868789DCC com.dukescript.nbjavac:nb-javac:jdk-18.0.1+10
diff --git a/java/libs.nbjavacapi/external/nb-javac-jdk-18+36-license.txt b/java/libs.nbjavacapi/external/nb-javac-jdk-18.0.1+10-license.txt
similarity index 99%
rename from java/libs.nbjavacapi/external/nb-javac-jdk-18+36-license.txt
rename to java/libs.nbjavacapi/external/nb-javac-jdk-18.0.1+10-license.txt
index f4b2392..6d324e9 100644
--- a/java/libs.nbjavacapi/external/nb-javac-jdk-18+36-license.txt
+++ b/java/libs.nbjavacapi/external/nb-javac-jdk-18.0.1+10-license.txt
@@ -1,7 +1,7 @@
Name: Javac Compiler Implementation
Description: Javac Compiler Implementation
-Files: nb-javac-jdk-18+36-api.jar nb-javac-jdk-18+36.jar
-Version: jdk-18+36
+Files: nb-javac-jdk-18.0.1+10-api.jar nb-javac-jdk-18.0.1+10.jar
+Version: jdk-18.0.1+10
License: GPL-2-CP
Origin: OpenJDK (https://github.com/openjdk/jdk18)
Source: https://github.com/openjdk/jdk18
diff --git a/java/libs.nbjavacapi/nbproject/project.properties b/java/libs.nbjavacapi/nbproject/project.properties
index eb02b90..1bd61ee 100644
--- a/java/libs.nbjavacapi/nbproject/project.properties
+++ b/java/libs.nbjavacapi/nbproject/project.properties
@@ -18,5 +18,5 @@
javac.source=1.7
javac.compilerargs=-Xlint -Xlint:-serial
license.file.override=${nb_all}/nbbuild/licenses/GPL-2-CP
-release.external/nb-javac-jdk-18+36-api.jar=modules/ext/nb-javac-jdk-18-api.jar
-release.external/nb-javac-jdk-18+36.jar=modules/ext/nb-javac-jdk-18.jar
+release.external/nb-javac-jdk-18.0.1+10-api.jar=modules/ext/nb-javac-jdk-18-api.jar
+release.external/nb-javac-jdk-18.0.1+10.jar=modules/ext/nb-javac-jdk-18.jar
diff --git a/java/libs.nbjavacapi/nbproject/project.xml b/java/libs.nbjavacapi/nbproject/project.xml
index d52072e..7dc8a08 100644
--- a/java/libs.nbjavacapi/nbproject/project.xml
+++ b/java/libs.nbjavacapi/nbproject/project.xml
@@ -37,11 +37,11 @@
<public-packages/>
<class-path-extension>
<runtime-relative-path>ext/nb-javac-jdk-18-api.jar</runtime-relative-path>
- <binary-origin>external/nb-javac-jdk-18+36-api.jar</binary-origin>
+ <binary-origin>external/nb-javac-jdk-18.0.1+10-api.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/nb-javac-jdk-18.jar</runtime-relative-path>
- <binary-origin>external/nb-javac-jdk-18+36.jar</binary-origin>
+ <binary-origin>external/nb-javac-jdk-18.0.1+10.jar</binary-origin>
</class-path-extension>
</data>
</configuration>
diff --git a/java/maven/src/org/netbeans/modules/maven/execute/defaultActionMappings.xml b/java/maven/src/org/netbeans/modules/maven/execute/defaultActionMappings.xml
index a830f62..6c1769c 100644
--- a/java/maven/src/org/netbeans/modules/maven/execute/defaultActionMappings.xml
+++ b/java/maven/src/org/netbeans/modules/maven/execute/defaultActionMappings.xml
@@ -98,7 +98,8 @@
<packaging>*</packaging>
</packagings>
<goals>
- <goal>integration-test</goal>
+ <goal>pre-integration-test</goal>
+ <goal>failsafe:integration-test</goal>
</goals>
<properties>
<test>DummyToSkipUnitTests</test>
@@ -202,7 +203,8 @@
<packaging>*</packaging>
</packagings>
<goals>
- <goal>integration-test</goal>
+ <goal>pre-integration-test</goal>
+ <goal>failsafe:integration-test</goal>
</goals>
<properties>
<test>DummyToSkipUnitTests</test>
diff --git a/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/ignored-overlaps b/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/ignored-overlaps
index 0e830f6..47bbed8 100644
--- a/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/ignored-overlaps
+++ b/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/ignored-overlaps
@@ -39,10 +39,6 @@
# Used to parse data during build, but need to as a lib for ide cluster
nbbuild/external/json-simple-1.1.1.jar ide/libs.json_simple/external/json-simple-1.1.1.jar
-# Compile only nb-javac
-java/libs.nbjavacapi/external/nb-javac-jdk-18+36-api.jar nbbuild/external/nb-javac-jdk-17+36-api.jar
-java/libs.nbjavacapi/external/nb-javac-jdk-18+36.jar nbbuild/external/nb-javac-jdk-17+36.jar
-
# JFlex is used by multiple modules.
webcommon/javascript2.jade/external/jflex-1.4.3.jar webcommon/javascript2.lexer/external/jflex-1.4.3.jar
@@ -121,8 +117,8 @@
harness/apisupport.harness/external/launcher-12.5-distribution.zip platform/o.n.bootstrap/external/launcher-12.5-distribution.zip
# only one is part of the product:
-java/libs.javacapi/external/nb-javac-jdk-18+36-api.jar java/libs.nbjavacapi/external/nb-javac-jdk-18+36-api.jar
-java/libs.javacapi/external/nb-javac-jdk-18+36.jar java/libs.nbjavacapi/external/nb-javac-jdk-18+36.jar
+java/libs.javacapi/external/nb-javac-jdk-18.0.1+10-api.jar java/libs.nbjavacapi/external/nb-javac-jdk-18.0.1+10-api.jar
+java/libs.javacapi/external/nb-javac-jdk-18.0.1+10.jar java/libs.nbjavacapi/external/nb-javac-jdk-18.0.1+10.jar
# Maven and Gradle are self-contained distributions - ignoring overlaps
platform/o.apache.commons.lang3/external/commons-lang3-3.8.1.jar java/maven.embedder/external/apache-maven-3.8.5-bin.zip
diff --git a/platform/openide.nodes/src/org/openide/nodes/AsynchChildren.java b/platform/openide.nodes/src/org/openide/nodes/AsynchChildren.java
index 93af978..52fe246 100644
--- a/platform/openide.nodes/src/org/openide/nodes/AsynchChildren.java
+++ b/platform/openide.nodes/src/org/openide/nodes/AsynchChildren.java
@@ -154,7 +154,18 @@
setKeys (Collections.<T>emptyList());
return;
}
- final int minimalCount = getNodesCount();
+ final List<Entry> entries = entrySupport().getEntries();
+ // use entries count rather than node count, as some keys may result in no
+ // nodes, but they're still add()ed.
+
+ // TODO: the refresh is not completely correct: if the ChildFactory inserts a (really!) new
+ // key into the list of existing ones, the count-based detection causes setKeys()
+ // to be callled and the node(s) for the yet-not-reported keys will be formally deleted
+ // and later re-created. But if content is only added or unchanged, the refresh won't
+ // cause nodes to be deleted + recreated.
+ // Implementation detail: there's one extra fixed Entry (Children.AE)
+ // that represents this dynamic node array.
+ final int minimalCount = Math.max(entries.size() - 1, 0);
List <T> keys = new LinkedList <T> () {
@Override public boolean add(T e) {
if (cancelled || Thread.interrupted()) {
@@ -163,6 +174,7 @@
super.add(e);
LinkedList<Object> newKeys = new LinkedList<Object>(this);
Node n = factory.getWaitNode();
+
if (n != null) {
newKeys.add(n);
}
diff --git a/platform/openide.nodes/src/org/openide/nodes/Children.java b/platform/openide.nodes/src/org/openide/nodes/Children.java
index a59cbe7..1b9b218 100644
--- a/platform/openide.nodes/src/org/openide/nodes/Children.java
+++ b/platform/openide.nodes/src/org/openide/nodes/Children.java
@@ -1679,7 +1679,8 @@
* added to the collection and if the same object is added
* more than once it is indexed by a number.
*/
- private abstract static class Dupl<T> implements Cloneable, Entry {
+ // package-private for tests only!
+ abstract static class Dupl<T> implements Cloneable, Entry {
/** the key either real value or Dupl (Dupl (Dupl (... value ...)))*/
protected Object key;
diff --git a/platform/openide.nodes/test/unit/src/org/openide/nodes/ChildFactoryTest.java b/platform/openide.nodes/test/unit/src/org/openide/nodes/ChildFactoryTest.java
index 124ba76..362de83 100644
--- a/platform/openide.nodes/test/unit/src/org/openide/nodes/ChildFactoryTest.java
+++ b/platform/openide.nodes/test/unit/src/org/openide/nodes/ChildFactoryTest.java
@@ -403,6 +403,61 @@
assertEquals(4, root.getChildren().getNodes(true).length);
assertEquals("[1, 2, 3, 4]", nodesCreated.toString());
}
+
+ /**
+ * Checks that if the same (equal) keys are added for the 2nd time, the nodes
+ * are not re-created.
+ * @throws Exception
+ */
+ public void testIncrementalRefreshSameNodes() throws Exception {
+ // negative key will not be mapped to a Node.
+ List<Integer> nodeKeys = Arrays.asList(1, 2, -1, 3, -2, 4, 5);
+ class F extends ChildFactory<Integer> {
+ Semaphore sem = new Semaphore(0);
+
+ @Override
+ protected boolean createKeys(List<Integer> toPopulate) {
+ for (Integer i : nodeKeys) {
+ toPopulate.add(i);
+ }
+ sem.release();
+ return true;
+ }
+
+ @Override protected Node createNodeForKey(Integer key) {
+ if (key < 0) {
+ return null;
+ }
+ Node n = new AbstractNode(Children.LEAF);
+ n.setName(key.toString());
+ return n;
+ }
+ void refresh() {
+ refresh(false);
+ }
+ }
+
+ F f = new F();
+
+ Children c = Children.create(f, true);
+ Node[] first = c.getNodes(true);
+ f.sem.acquire();
+ f.sem.drainPermits();
+
+ f.refresh();
+ Node[] second = c.getNodes();
+ // needed so that all keys are refreshed, the above getNodes() has triggered
+ // createKeys() in async thread.
+ f.sem.acquire();
+ // get the result.
+ second = c.getNodes();
+
+ assertEquals(first.length, second.length);
+ // since keys did not change the nodes themselves should not change, too.
+ for (int i = 0; i < first.length; i++) {
+ assertSame(first[i], second[i]);
+ }
+ }
public void testIncrementalNodeRemoval() throws Exception { // #211847
final List<Integer> nodesCreated = new ArrayList<Integer>();