Skip to content

Commit b839f1e

Browse files
authored
ux - display maven and gradle dependencies with pattern 'groupId:artifactId:version ' (#859)
1 parent 6ee1c6b commit b839f1e

File tree

13 files changed

+133
-21
lines changed

13 files changed

+133
-21
lines changed

.vscode/launch.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
{
1919
"type": "java",
2020
"name": "Attach to Plugin",
21+
"projectName": "com.microsoft.jdtls.ext.core",
2122
"request": "attach",
2223
"hostName": "localhost",
2324
"port": 1044

CONTRIBUTING.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# How to Contribute
2+
3+
We greatly appreciate contributions to the vscode-java-dependency project. Your efforts help us maintain and improve this extension. To ensure a smooth contribution process, please follow these guidelines.
4+
5+
## Prerequisites
6+
- [JDK](https://www.oracle.com/java/technologies/downloads/?er=221886)
7+
- [Node.JS](https://nodejs.org/en/)
8+
- [VSCode](https://code.visualstudio.com/)
9+
10+
## Build and Run
11+
12+
To set up the vscode-java-dependency project, follow these steps:
13+
14+
1. **Build the Server JAR**:
15+
- The server JAR (Java application) is located in the [jdtls.ext](./jdtls.ext) directory.
16+
- Run the following command to build the server:
17+
```shell
18+
npm run build-server
19+
```
20+
21+
2. **Install Dependencies**:
22+
- Execute the following command to install the necessary dependencies:
23+
```shell
24+
npm install
25+
```
26+
27+
3. **Run/Debug the Extension**:
28+
- Open the "Run and Debug" view in Visual Studio Code.
29+
- Run the "Run Extension" task.
30+
31+
4. **Attach to Plugin[Debug Java]**:
32+
- Prerequisite: Ensure that the extension is activated, meaning the Java process is already launched. This is required for the task to run properly.
33+
- Open the "Run and Debug" view in Visual Studio Code.
34+
- Run the "Attach to Plugin" task.
35+
- Note: This task is required only if you want to debug Java code [jdtls.ext](./jdtls.ext). It requires the [vscode-pde](https://marketplace.visualstudio.com/items?itemName=yaozheng.vscode-pde) extension to be installed.
36+
37+
Thank you for your contributions and support!

jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.ArrayList;
1515
import java.util.Arrays;
1616
import java.util.Collections;
17+
import java.util.EnumMap;
1718
import java.util.HashMap;
1819
import java.util.LinkedList;
1920
import java.util.List;
@@ -78,7 +79,7 @@ public class PackageCommand {
7879
private static final Map<NodeKind, BiFunction<PackageParams, IProgressMonitor, List<PackageNode>>> commands;
7980

8081
static {
81-
commands = new HashMap<>();
82+
commands = new EnumMap<>(NodeKind.class);
8283
commands.put(NodeKind.PROJECT, PackageCommand::getProjectChildren);
8384
commands.put(NodeKind.CONTAINER, PackageCommand::getContainerChildren);
8485
commands.put(NodeKind.PACKAGEROOT, PackageCommand::getPackageRootChildren);

jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Map;
2020
import java.util.Objects;
2121

22+
import org.apache.commons.lang3.StringUtils;
2223
import org.eclipse.core.resources.IFile;
2324
import org.eclipse.core.resources.IFolder;
2425
import org.eclipse.core.resources.IProject;
@@ -273,11 +274,32 @@ public static PackageRootNode createNodeForPackageFragmentRoot(IPackageFragmentR
273274
for (IClasspathAttribute attribute : resolvedClasspathEntry.getExtraAttributes()) {
274275
node.setMetaDataValue(attribute.getName(), attribute.getValue());
275276
}
277+
278+
String computedDisplayName = computeDisplayName(node);
279+
if (StringUtils.isNotBlank(computedDisplayName)) {
280+
node.setDisplayName(computedDisplayName);
281+
}
276282
}
277283

278284
return node;
279285
}
280286

287+
private static String computeDisplayName(PackageRootNode node) {
288+
if (node.getMetaData() == null || node.getMetaData().isEmpty()) {
289+
return node.getName();
290+
}
291+
292+
String version = (String) node.getMetaData().get("maven.version");
293+
String groupId = (String) node.getMetaData().get("maven.groupId");
294+
String artifactId = (String) node.getMetaData().get("maven.artifactId");
295+
296+
if (StringUtils.isBlank(version) || StringUtils.isBlank(groupId) || StringUtils.isBlank(artifactId)) {
297+
return node.getName();
298+
}
299+
300+
return groupId + ":" + artifactId + ":" + version;
301+
}
302+
281303
/**
282304
* Get the correspond node of classpath, it may be container or a package root.
283305
*

src/views/PrimaryTypeNode.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ export class PrimaryTypeNode extends DataNode {
3434
return "";
3535
}
3636

37+
public getLabel(): string {
38+
return this._nodeData.displayName ?? this._nodeData.name;
39+
}
40+
3741
protected async loadData(): Promise<SymbolInformation[] | DocumentSymbol[] | undefined> {
3842
if (!this.hasChildren() || !this.nodeData.uri) {
3943
return undefined;

src/views/containerNode.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,36 @@ export class ContainerNode extends DataNode {
1515
super(nodeData, parent);
1616
}
1717

18+
private _containerType: ContainerType;
19+
1820
public get projectBasePath() {
1921
return this._project.uri && Uri.parse(this._project.uri).fsPath;
2022
}
2123

22-
public getContainerType(): string {
24+
public getContainerType(): ContainerType {
25+
if (this._containerType) {
26+
return this._containerType;
27+
}
28+
2329
const containerPath: string = this._nodeData.path || "";
2430
if (containerPath.startsWith(ContainerPath.JRE)) {
25-
return ContainerType.JRE;
31+
this._containerType = ContainerType.JRE;
2632
} else if (containerPath.startsWith(ContainerPath.Maven)) {
27-
return ContainerType.Maven;
33+
this._containerType = ContainerType.Maven;
2834
} else if (containerPath.startsWith(ContainerPath.Gradle)) {
29-
return ContainerType.Gradle;
35+
this._containerType = ContainerType.Gradle;
3036
} else if (containerPath.startsWith(ContainerPath.ReferencedLibrary) && this._project.isUnmanagedFolder()) {
3137
// currently, we only support editing referenced libraries in unmanaged folders
32-
return ContainerType.ReferencedLibrary;
38+
this._containerType = ContainerType.ReferencedLibrary;
39+
} else {
40+
this._containerType = ContainerType.Unknown;
3341
}
34-
return ContainerType.Unknown;
42+
43+
return this._containerType;
44+
}
45+
46+
public isMavenType(): boolean {
47+
return this._containerType === ContainerType.Maven;
3548
}
3649

3750
protected async loadData(): Promise<INodeData[]> {

src/views/dataNode.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export abstract class DataNode extends ExplorerNode {
4242
return item;
4343
}
4444

45+
public getDisplayName(): string {
46+
return this._nodeData.displayName || this._nodeData.name;
47+
}
48+
4549
public get nodeData(): INodeData {
4650
return this._nodeData;
4751
}

src/views/dependencyDataProvider.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
RelativePattern, TreeDataProvider, TreeItem, Uri, window, workspace,
88
} from "vscode";
99
import { instrumentOperationAsVsCodeCommand, sendError } from "vscode-extension-telemetry-wrapper";
10-
import { contextManager } from "../../extension.bundle";
10+
import { ContainerNode, contextManager } from "../../extension.bundle";
1111
import { Commands } from "../commands";
1212
import { Context } from "../constants";
1313
import { appendOutput, executeExportJarTask } from "../tasks/buildArtifact/BuildArtifactTaskProvider";
@@ -124,6 +124,14 @@ export class DependencyDataProvider implements TreeDataProvider<ExplorerNode> {
124124
const children = (!this._rootItems || !element) ?
125125
await this.getRootNodes() : await element.getChildren();
126126

127+
if (children && element instanceof ContainerNode) {
128+
if (element.isMavenType()) {
129+
children.sort((a, b) => {
130+
return a.getDisplayName().localeCompare(b.getDisplayName());
131+
});
132+
}
133+
}
134+
127135
explorerNodeCache.saveNodes(children || []);
128136
return children;
129137
}

src/views/documentSymbolNode.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export class DocumentSymbolNode extends ExplorerNode {
2828
super(parent);
2929
}
3030

31+
public getDisplayName(): string {
32+
return this.symbolInfo.name;
33+
}
34+
3135
public getChildren(): ExplorerNode[] | Promise<ExplorerNode[]> {
3236
const res: ExplorerNode[] = [];
3337
if (this.symbolInfo?.children?.length) {
@@ -39,7 +43,7 @@ export class DocumentSymbolNode extends ExplorerNode {
3943
}
4044

4145
public getTreeItem(): TreeItem | Promise<TreeItem> {
42-
const item = new TreeItem(this.symbolInfo.name,
46+
const item = new TreeItem(this.getDisplayName(),
4347
this.symbolInfo?.children?.length ? TreeItemCollapsibleState.Collapsed
4448
: TreeItemCollapsibleState.None);
4549
item.iconPath = this.iconPath;

src/views/explorerNode.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,6 @@ export abstract class ExplorerNode {
3333
public abstract getTreeItem(): TreeItem | Promise<TreeItem>;
3434

3535
public abstract computeContextValue(): string | undefined;
36+
37+
public abstract getDisplayName(): string;
3638
}

test/gradle-suite/projectView.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33

44
import * as assert from "assert";
55
import { ContainerNode, contextManager, DataNode, DependencyExplorer,
6+
languageServerApiManager,
67
PackageRootNode, PrimaryTypeNode, ProjectNode } from "../../extension.bundle";
78
import { fsPath, setupTestEnv, Uris } from "../shared";
89

910
// tslint:disable: only-arrow-functions
1011
suite("Gradle Project View Tests", () => {
1112

12-
suiteSetup(setupTestEnv);
13+
suiteSetup(async () => {
14+
await setupTestEnv();
15+
await languageServerApiManager.ready();
16+
});
1317

1418
test("Can node render correctly", async function() {
1519
const explorer = DependencyExplorer.getInstance(contextManager.context);

test/invisible-suite/projectView.test.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,21 @@
33

44
import * as assert from "assert";
55
import * as fse from "fs-extra";
6-
import { platform } from "os";
76
import * as path from "path";
87
import * as vscode from "vscode";
9-
import { Commands, contextManager, DependencyExplorer, PackageNode, PackageRootNode, ProjectNode } from "../../extension.bundle";
8+
import { Commands, contextManager, DependencyExplorer, languageServerApiManager, PackageNode, PackageRootNode, ProjectNode } from "../../extension.bundle";
109
import { setupTestEnv } from "../shared";
1110
import { sleep } from "../util";
1211

1312
// tslint:disable: only-arrow-functions
1413
suite("Invisible Project View Tests", () => {
1514

16-
suiteSetup(setupTestEnv);
15+
suiteSetup(async () => {
16+
await setupTestEnv();
17+
await languageServerApiManager.ready();
18+
});
1719

1820
test("Can execute command java.project.refreshLibraries correctly", async function() {
19-
if (platform() === "darwin") {
20-
this.skip();
21-
}
2221
const explorer = DependencyExplorer.getInstance(contextManager.context);
2322

2423
let projectNode = (await explorer.dataProvider.getChildren())![0] as ProjectNode;
@@ -37,9 +36,6 @@ suite("Invisible Project View Tests", () => {
3736
});
3837

3938
test("Can execute command java.project.removeLibrary correctly", async function() {
40-
if (platform() === "darwin") {
41-
this.skip();
42-
}
4339
const explorer = DependencyExplorer.getInstance(contextManager.context);
4440

4541
let projectNode = (await explorer.dataProvider.getChildren())![0] as ProjectNode;

test/maven-suite/projectView.test.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
import * as assert from "assert";
55
import * as vscode from "vscode";
66
import { Commands, ContainerNode, contextManager, DataNode, DependencyExplorer, FileNode,
7-
INodeData, Jdtls, NodeKind, PackageNode, PackageRootNode, PrimaryTypeNode, ProjectNode } from "../../extension.bundle";
7+
INodeData, Jdtls, languageServerApiManager, NodeKind, PackageNode, PackageRootNode, PrimaryTypeNode, ProjectNode } from "../../extension.bundle";
88
import { fsPath, printNodes, setupTestEnv, Uris } from "../shared";
99

1010
// tslint:disable: only-arrow-functions
1111
suite("Maven Project View Tests", () => {
1212

13-
suiteSetup(setupTestEnv);
13+
suiteSetup(async () => {
14+
await setupTestEnv();
15+
await languageServerApiManager.ready();
16+
});
1417

1518
test("Can node render correctly in hierarchical view", async function() {
1619
await vscode.workspace.getConfiguration("java.dependency").update("packagePresentation", "hierarchical");
@@ -253,6 +256,19 @@ suite("Maven Project View Tests", () => {
253256
assert.equal(projectChildren.length, 4);
254257
});
255258

259+
test("Can maven dependency nodes display in correct groupId:artifactId:version format", async function() {
260+
const explorer = DependencyExplorer.getInstance(contextManager.context);
261+
262+
const roots = await explorer.dataProvider.getChildren();
263+
const projectNode = roots![0] as ProjectNode;
264+
const projectChildren = await projectNode.getChildren();
265+
const mavenDependency = projectChildren[3] as ContainerNode;
266+
const mavenChildren = await mavenDependency.getChildren();
267+
268+
assert.equal(mavenChildren[0].getDisplayName(), "org.hamcrest:hamcrest-core:1.3");
269+
assert.equal(mavenChildren[1].getDisplayName(), "junit:junit:4.13.1");
270+
});
271+
256272
teardown(async () => {
257273
// Restore default settings. Some tests might alter them and others depend on a specific setting.
258274
// Not resetting to the default settings will also show the file as changed in the source control view.

0 commit comments

Comments
 (0)