Skip to content

Commit 010ba9b

Browse files
committed
further steps towards jmolecules support
1 parent 4852d66 commit 010ba9b

File tree

7 files changed

+355
-43
lines changed

7 files changed

+355
-43
lines changed

headless-services/spring-boot-language-server/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@
163163
<dependency>
164164
<groupId>org.jmolecules.integrations</groupId>
165165
<artifactId>jmolecules-stereotype</artifactId>
166-
<version>0.27.0-STEREOTYPE-SNAPSHOT</version>
166+
<version>0.29.0-STEREOTYPE-SNAPSHOT</version>
167167
</dependency>
168168

169169

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/stereotypes/StereotypesIndexer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.eclipse.jdt.core.dom.IAnnotationBinding;
2525
import org.eclipse.jdt.core.dom.IPackageBinding;
2626
import org.eclipse.jdt.core.dom.ITypeBinding;
27+
import org.eclipse.jdt.core.dom.MethodDeclaration;
2728
import org.eclipse.jdt.core.dom.PackageDeclaration;
2829
import org.eclipse.jdt.core.dom.TypeDeclaration;
2930
import org.jmolecules.stereotype.catalog.StereotypeDefinition.Assignment.Type;
@@ -65,6 +66,12 @@ public void addSymbols(Annotation node, ITypeBinding typeBinding, Collection<ITy
6566
}
6667
}
6768

69+
@Override
70+
public void addSymbols(MethodDeclaration methodDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
71+
// TODO Auto-generated method stub
72+
SymbolProvider.super.addSymbols(methodDeclaration, context, doc);
73+
}
74+
6875
@Override
6976
public void addSymbols(PackageDeclaration packageDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
7077
if (!context.getDocURI().endsWith("package-info.java")) {

headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/stereotypes/StereotypesIndexerTest.java

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
import java.util.Optional;
2020
import java.util.concurrent.CompletableFuture;
2121
import java.util.concurrent.TimeUnit;
22+
import java.util.function.BiConsumer;
2223

2324
import org.eclipse.lsp4j.TextDocumentIdentifier;
2425
import org.jmolecules.stereotype.api.Stereotype;
2526
import org.jmolecules.stereotype.catalog.StereotypeDefinition;
2627
import org.jmolecules.stereotype.tooling.AsciiArtNodeHandler;
28+
import org.jmolecules.stereotype.tooling.HierarchicalNodeHandler;
2729
import org.jmolecules.stereotype.tooling.ProjectTree;
2830
import org.jmolecules.stereotype.tooling.SimpleLabelProvider;
2931
import org.jmolecules.stereotype.tooling.StructureProvider.SimpleStructureProvider;
@@ -36,6 +38,7 @@
3638
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
3739
import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf;
3840
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
41+
import org.springframework.ide.vscode.boot.java.stereotypes.ToolsJsonNodeHandler.Node;
3942
import org.springframework.ide.vscode.commons.java.IJavaProject;
4043
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
4144
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
@@ -187,45 +190,61 @@ void testTree() {
187190
var labels = SimpleLabelProvider.forPackage(StereotypePackageElement::getPackageName, StereotypeClassElement::getType,
188191
(StereotypeMethodElement m, StereotypeClassElement __) -> m.getMethodName(), Object::toString);
189192

190-
var handler = new AsciiArtNodeHandler<>(labels);
191-
192-
var tree = new ProjectTree<>(factory, catalog, handler)
193-
.withStructureProvider(new SimpleStructureProvider<StereotypePackageElement, StereotypePackageElement, StereotypeClassElement, StereotypeMethodElement>() {
194-
195-
@Override
196-
public Collection<StereotypePackageElement> extractPackages(StereotypePackageElement pkg) {
197-
return getAllPackageElements().stream()
198-
.filter(packageElement -> packageElement.getPackageName().startsWith(pkg.getPackageName()))
199-
.toList();
200-
201-
// return extractTypes(pkg).stream()
202-
// .map(Class::getPackage)
203-
// .distinct()
204-
// .toList();
205-
}
206-
207-
@Override
208-
public Collection<StereotypeMethodElement> extractMethods(StereotypeClassElement type) {
209-
return List.of();
210-
}
211-
212-
@Override
213-
public Collection<StereotypeClassElement> extractTypes(StereotypePackageElement pkg) {
214-
return getAllClassElements().stream()
215-
.filter(element -> element.getType().startsWith(pkg.getPackageName()))
216-
.toList();
217-
}
218-
})
219-
// .withGrouper("spring", "org.jmolecules.ddd")
220-
.withGrouper("spring", "org.jmolecules.architecture")
221-
// .withGrouper("org.jmolecules.architecture")
222-
// .withGrouper("spring")
223-
// .withGrouper("org.jmolecules.ddd")
224-
;
225-
226-
tree.process(new StereotypePackageElement("example", null));
227-
228-
System.out.println(handler.getWriter().toString());
193+
SimpleStructureProvider<StereotypePackageElement, StereotypePackageElement, StereotypeClassElement, StereotypeMethodElement> structureProvider =
194+
new SimpleStructureProvider<StereotypePackageElement, StereotypePackageElement, StereotypeClassElement, StereotypeMethodElement>() {
195+
196+
@Override
197+
public Collection<StereotypePackageElement> extractPackages(StereotypePackageElement pkg) {
198+
return getAllPackageElements().stream()
199+
.filter(packageElement -> packageElement.getPackageName().startsWith(pkg.getPackageName()))
200+
.toList();
201+
202+
// return extractTypes(pkg).stream()
203+
// .map(Class::getPackage)
204+
// .distinct()
205+
// .toList();
206+
}
207+
208+
@Override
209+
public Collection<StereotypeMethodElement> extractMethods(StereotypeClassElement type) {
210+
return List.of();
211+
}
212+
213+
@Override
214+
public Collection<StereotypeClassElement> extractTypes(StereotypePackageElement pkg) {
215+
return getAllClassElements().stream()
216+
.filter(element -> element.getType().startsWith(pkg.getPackageName()))
217+
.toList();
218+
}
219+
};
220+
221+
// ascii art output
222+
var asciiHandler = new AsciiArtNodeHandler<>(labels);
223+
var tree = new ProjectTree<>(factory, catalog, asciiHandler)
224+
.withStructureProvider(structureProvider)
225+
.withGrouper("org.jmolecules.architecture")
226+
.withGrouper("org.jmolecules.ddd", "org.jmolecules.event", "spring", "jpa", "java");
227+
228+
tree.process(new StereotypePackageElement("example.application", null));
229+
System.out.println(asciiHandler.getWriter().toString());
230+
231+
// json output
232+
BiConsumer<Node, Object> consumer = (node, c) -> {
233+
node.withAttribute(HierarchicalNodeHandler.TEXT, labels.getCustomLabel(c))
234+
.withAttribute("icon", "fa-named-interface");
235+
};
236+
237+
var jsonHandler = new ToolsJsonNodeHandler(labels, consumer);
238+
239+
var jsonTree = new ProjectTree<>(factory, catalog, jsonHandler)
240+
.withStructureProvider(structureProvider)
241+
.withGrouper("org.jmolecules.architecture")
242+
.withGrouper("org.jmolecules.ddd", "org.jmolecules.event", "spring", "jpa", "java");
243+
244+
jsonTree.process(new StereotypePackageElement("example.application", null));
245+
246+
tree.process(new StereotypePackageElement("example.application", null));
247+
System.out.println(jsonHandler.toString());
229248
}
230249

231250
private List<StereotypeClassElement> getAllClassElements() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ide.vscode.boot.java.stereotypes;
18+
19+
import net.minidev.json.JSONObject;
20+
21+
import java.util.ArrayList;
22+
import java.util.LinkedHashMap;
23+
import java.util.List;
24+
import java.util.Map;
25+
import java.util.function.BiConsumer;
26+
import java.util.function.Consumer;
27+
28+
import org.eclipse.lsp4j.Location;
29+
import org.eclipse.lsp4j.Range;
30+
import org.jmolecules.stereotype.api.Stereotype;
31+
import org.jmolecules.stereotype.tooling.LabelProvider;
32+
import org.jmolecules.stereotype.tooling.MethodNodeContext;
33+
import org.jmolecules.stereotype.tooling.NodeContext;
34+
import org.jmolecules.stereotype.tooling.NodeHandler;
35+
36+
/**
37+
* @author Oliver Drotbohm
38+
* @author Martin Lippert
39+
*/
40+
public class ToolsJsonNodeHandler implements NodeHandler<StereotypePackageElement, StereotypePackageElement, StereotypeClassElement, StereotypeMethodElement, Object> {
41+
42+
public static final String ICON = "icon";
43+
public static final String TEXT = "text";
44+
45+
private final Node root;
46+
private final LabelProvider<StereotypePackageElement, StereotypePackageElement, StereotypeClassElement, StereotypeMethodElement, Object> labels;
47+
private final BiConsumer<Node, Object> customHandler;
48+
private Node current;
49+
50+
public ToolsJsonNodeHandler(LabelProvider<StereotypePackageElement, StereotypePackageElement, StereotypeClassElement, StereotypeMethodElement, Object> labels, BiConsumer<Node, Object> customHandler) {
51+
this.labels = labels;
52+
this.root = new Node(null);
53+
this.customHandler = customHandler;
54+
this.current = root;
55+
}
56+
57+
/*
58+
* (non-Javadoc)
59+
* @see org.jmolecules.stereotype.tooling.NodeHandler#handleApplication(java.lang.Object)
60+
*/
61+
@Override
62+
public void handleApplication(StereotypePackageElement application) {
63+
this.root.withAttribute(TEXT, labels.getApplicationLabel(application));
64+
}
65+
66+
/*
67+
* (non-Javadoc)
68+
* @see org.jmolecules.stereotype.tooling.NodeHandler#handlePackage(java.lang.Object, org.jmolecules.stereotype.tooling.NodeContext)
69+
*/
70+
@Override
71+
public void handlePackage(StereotypePackageElement pkg, NodeContext context) {
72+
73+
addChild(node -> node
74+
.withAttribute(ICON, "fa-package")
75+
.withAttribute(TEXT, labels.getPackageLabel(pkg)));
76+
}
77+
78+
/*
79+
* (non-Javadoc)
80+
* @see org.jmolecules.stereotype.tooling.NodeHandler#handleStereotype(org.jmolecules.stereotype.api.Stereotype, org.jmolecules.stereotype.tooling.NestingLevel)
81+
*/
82+
@Override
83+
public void handleStereotype(Stereotype stereotype, NodeContext context) {
84+
85+
addChild(node -> node.withAttribute(ICON, "fa-stereotype")
86+
.withAttribute(TEXT, labels.getSterotypeLabel(stereotype)));
87+
}
88+
89+
/*
90+
* (non-Javadoc)
91+
* @see org.jmolecules.stereotype.tooling.NodeHandler#handleType(java.lang.Object, org.jmolecules.stereotype.tooling.NestingLevel)
92+
*/
93+
@Override
94+
public void handleType(StereotypeClassElement type, NodeContext context) {
95+
addChild(node -> node
96+
.withAttribute(TEXT, labels.getTypeLabel(type))
97+
.withAttribute("location", new Location("sampleUri", new Range()))
98+
);
99+
}
100+
101+
public Node createNested() {
102+
return new Node(this.current);
103+
}
104+
105+
/*
106+
* (non-Javadoc)
107+
* @see org.jmolecules.stereotype.tooling.NodeHandler#handleMethod(java.lang.Object, org.jmolecules.stereotype.tooling.NestingLevel, boolean)
108+
*/
109+
@Override
110+
public void handleMethod(StereotypeMethodElement method, MethodNodeContext<StereotypeClassElement> context) {
111+
addChildFoo(node -> node.withAttribute("title", labels.getMethodLabel(method, context.getContextualType())));
112+
}
113+
114+
/*
115+
* (non-Javadoc)
116+
* @see org.jmolecules.stereotype.tooling.NodeHandler#handleCustom(java.lang.Object, org.jmolecules.stereotype.tooling.NodeContext)
117+
*/
118+
@Override
119+
public void handleCustom(Object custom, NodeContext context) {
120+
addChild(node -> customHandler.accept(node, custom));
121+
}
122+
123+
/*
124+
* (non-Javadoc)
125+
* @see org.jmolecules.stereotype.tooling.NodeHandler#postGroup()
126+
*/
127+
@Override
128+
public void postGroup() {
129+
this.current = this.current.parent;
130+
}
131+
132+
private void addChild(Consumer<Node> consumer) {
133+
this.current = addChildFoo(consumer);
134+
}
135+
136+
private Node addChildFoo(Consumer<Node> consumer) {
137+
138+
var node = new Node(this.current);
139+
consumer.accept(node);
140+
141+
this.current.children.add(node);
142+
143+
return node;
144+
}
145+
146+
/*
147+
* (non-Javadoc)
148+
* @see java.lang.Object#toString()
149+
*/
150+
@Override
151+
public String toString() {
152+
return render(root).toJSONString();
153+
}
154+
155+
private JSONObject render(Node node) {
156+
157+
var object = new JSONObject();
158+
159+
object.putAll(node.attributes);
160+
161+
if (!node.children.isEmpty()) {
162+
object.put("children", node.children.stream().map(this::render).toList());
163+
}
164+
165+
return object;
166+
}
167+
168+
public static class Node {
169+
170+
private final Node parent;
171+
private final Map<String, Object> attributes;
172+
private final List<Node> children;
173+
174+
Node(Node parent) {
175+
this.parent = parent;
176+
this.attributes = new LinkedHashMap<>();
177+
this.children = new ArrayList<>();
178+
}
179+
180+
public Node withAttribute(String key, Object value) {
181+
this.attributes.put(key, value);
182+
return this;
183+
}
184+
}
185+
}

0 commit comments

Comments
 (0)