Skip to content

Commit 77c6004

Browse files
authored
#1171: add real time xpath validation (#1196)
1 parent 144ffff commit 77c6004

File tree

9 files changed

+159
-5
lines changed

9 files changed

+159
-5
lines changed

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ dependencies {
126126
testImplementation 'org.hamcrest:hamcrest-all:1.3'
127127
testImplementation 'org.opentest4j:opentest4j:1.3.0'
128128
testImplementation "org.apache.camel:camel-jsonpath:${camelVersion}"
129+
testImplementation "org.apache.camel:camel-jq:${camelVersion}"
130+
testImplementation "org.apache.camel:camel-xpath:${camelVersion}"
129131
testImplementation 'junit:junit:4.13.2'
130132
}
131133

src/main/java/com/github/cameltooling/idea/annotator/CamelLanguageAnnotator.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class CamelLanguageAnnotator extends AbstractCamelAnnotator {
4141

4242
@Override
4343
boolean isEnabled() {
44-
return CamelPreferenceService.getService().isRealTimeJSonPathValidation() || CamelPreferenceService.getService().isRealTimeJQValidation();
44+
return CamelPreferenceService.getService().isRealTimeJSonPathValidation() || CamelPreferenceService.getService().isRealTimeJQValidation() || CamelPreferenceService.getService().isRealTimeXPathValidation();
4545
}
4646

4747
/**
@@ -53,19 +53,30 @@ void validateText(@NotNull PsiElement element, @NotNull AnnotationHolder holder,
5353

5454
boolean json = CamelPreferenceService.getService().isRealTimeJSonPathValidation() && camelIdeaUtils.isCamelExpression(element, "jsonpath");
5555
boolean jq = CamelPreferenceService.getService().isRealTimeJQValidation() && camelIdeaUtils.isCamelExpression(element, "jq");
56-
if (json || jq) {
56+
boolean xpath = CamelPreferenceService.getService().isRealTimeXPathValidation() && camelIdeaUtils.isCamelExpression(element, "xpath");
57+
if (json || jq || xpath) {
5758
Project project = element.getProject();
5859
CamelCatalog catalogService = project.getService(CamelCatalogService.class).get();
5960
CamelService camelService = project.getService(CamelService.class);
6061

6162
// must have the supporting library
62-
String lib = json ? "camel-jsonpath" : "camel-jq";
63+
String lib = null;
64+
String lan = null;
65+
if (json) {
66+
lib = "camel-jsonpath";
67+
lan = "jsonpath";
68+
} else if (jq) {
69+
lib = "camel-jq";
70+
lan = "jq";
71+
} else if (xpath) {
72+
lib = "camel-xpath";
73+
lan = "xpath";
74+
}
6375
if (!camelService.containsLibrary(lib, false)) {
6476
camelService.showMissingLanguageJarNotification(lib);
6577
return;
6678
}
6779

68-
String lan = json ? "jsonpath" : "jq";
6980
try {
7081
// need to use the classloader that can load classes from the project
7182
ClassLoader loader = camelService.getProjectClassloader();

src/main/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPage.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class CamelAnnotatorPage implements SearchableConfigurable, Configurable.
3838
private JBCheckBox realTimeSimpleValidationCatalogCheckBox;
3939
private JBCheckBox realTimeJSonPathValidationCatalogCheckBox;
4040
private JBCheckBox realTimeJQValidationCatalogCheckBox;
41+
private JBCheckBox realTimeXPathValidationCatalogCheckBox;
4142
private JBCheckBox realTimeIdReferenceTypeValidationCheckBox;
4243
private JBCheckBox realTimeBeanMethodValidationCheckBox;
4344
private JPanel result;
@@ -54,6 +55,7 @@ public JComponent createComponent() {
5455
realTimeSimpleValidationCatalogCheckBox = new JBCheckBox("Real time validation of Camel simple language in editor");
5556
realTimeJSonPathValidationCatalogCheckBox = new JBCheckBox("Real time validation of Camel JSonPath language in editor");
5657
realTimeJQValidationCatalogCheckBox = new JBCheckBox("Real time validation of Camel JQ language in editor");
58+
realTimeXPathValidationCatalogCheckBox = new JBCheckBox("Real time validation of Camel XPath language in editor");
5759
realTimeIdReferenceTypeValidationCheckBox = new JBCheckBox("Real time type validation when referencing beans");
5860
realTimeBeanMethodValidationCheckBox = new JBCheckBox("Real time validation of call bean method in editor");
5961

@@ -66,6 +68,7 @@ public JComponent createComponent() {
6668
jPanel.add(realTimeSimpleValidationCatalogCheckBox, "span 2");
6769
jPanel.add(realTimeJSonPathValidationCatalogCheckBox, "span 2");
6870
jPanel.add(realTimeJQValidationCatalogCheckBox, "span 2");
71+
jPanel.add(realTimeXPathValidationCatalogCheckBox, "span 2");
6972
jPanel.add(realTimeIdReferenceTypeValidationCheckBox, "span 2");
7073
jPanel.add(realTimeBeanMethodValidationCheckBox, "span 2");
7174

@@ -83,6 +86,7 @@ public void apply() {
8386
camelPreferenceService.setRealTimeSimpleValidation(realTimeSimpleValidationCatalogCheckBox.isSelected());
8487
camelPreferenceService.setRealTimeJSonPathValidation(realTimeJSonPathValidationCatalogCheckBox.isSelected());
8588
camelPreferenceService.setRealTimeJQValidation(realTimeJQValidationCatalogCheckBox.isSelected());
89+
camelPreferenceService.setRealTimeXPathValidation(realTimeXPathValidationCatalogCheckBox.isSelected());
8690
camelPreferenceService.setRealTimeIdReferenceTypeValidation(realTimeIdReferenceTypeValidationCheckBox.isSelected());
8791
camelPreferenceService.setRealTimeBeanMethodValidationCheckBox(realTimeBeanMethodValidationCheckBox.isSelected());
8892
}
@@ -96,6 +100,7 @@ public boolean isModified() {
96100
|| camelPreferenceService.isRealTimeSimpleValidation() != realTimeSimpleValidationCatalogCheckBox.isSelected()
97101
|| camelPreferenceService.isRealTimeJSonPathValidation() != realTimeJSonPathValidationCatalogCheckBox.isSelected()
98102
|| camelPreferenceService.isRealTimeJQValidation() != realTimeJQValidationCatalogCheckBox.isSelected()
103+
|| camelPreferenceService.isRealTimeXPathValidation() != realTimeXPathValidationCatalogCheckBox.isSelected()
99104
|| camelPreferenceService.isRealTimeIdReferenceTypeValidation() != realTimeIdReferenceTypeValidationCheckBox.isSelected()
100105
|| camelPreferenceService.isRealTimeBeanMethodValidationCheckBox() != realTimeBeanMethodValidationCheckBox.isSelected();
101106
return b1;
@@ -109,6 +114,7 @@ public void reset() {
109114
realTimeSimpleValidationCatalogCheckBox.setSelected(camelPreferenceService.isRealTimeSimpleValidation());
110115
realTimeJSonPathValidationCatalogCheckBox.setSelected(camelPreferenceService.isRealTimeJSonPathValidation());
111116
realTimeJQValidationCatalogCheckBox.setSelected(camelPreferenceService.isRealTimeJQValidation());
117+
realTimeXPathValidationCatalogCheckBox.setSelected(camelPreferenceService.isRealTimeXPathValidation());
112118
realTimeIdReferenceTypeValidationCheckBox.setSelected(camelPreferenceService.isRealTimeIdReferenceTypeValidation());
113119
realTimeBeanMethodValidationCheckBox.setSelected(camelPreferenceService.isRealTimeBeanMethodValidationCheckBox());
114120
}
@@ -120,6 +126,7 @@ public void disposeUIResources() {
120126
realTimeSimpleValidationCatalogCheckBox = null;
121127
realTimeJSonPathValidationCatalogCheckBox = null;
122128
realTimeJQValidationCatalogCheckBox = null;
129+
realTimeXPathValidationCatalogCheckBox = null;
123130
realTimeIdReferenceTypeValidationCheckBox = null;
124131
realTimeBeanMethodValidationCheckBox = null;
125132

@@ -161,6 +168,10 @@ public JBCheckBox getRealTimeJQValidationCatalogCheckBox() {
161168
return realTimeJQValidationCatalogCheckBox;
162169
}
163170

171+
public JBCheckBox getRealTimeXPathValidationCatalogCheckBox() {
172+
return realTimeXPathValidationCatalogCheckBox;
173+
}
174+
164175
JBCheckBox getRealTimeIdReferenceTypeValidationCheckBox() {
165176
return realTimeIdReferenceTypeValidationCheckBox;
166177
}

src/main/java/com/github/cameltooling/idea/service/CamelPreferenceService.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public class CamelPreferenceService implements PersistentStateComponent<CamelPre
6767
private boolean realTimeSimpleValidation = true;
6868
private boolean realTimeJSonPathValidation = true;
6969
private boolean realTimeJQValidation = true;
70+
private boolean realTimeXPathValidation = true;
7071
private boolean realTimeIdReferenceTypeValidation = true;
7172
private boolean realTimeBeanMethodValidationCheckBox = true;
7273
private boolean highlightCustomOptions = true;
@@ -133,6 +134,14 @@ public void setRealTimeJQValidation(boolean realTimeJQValidation) {
133134
this.realTimeJQValidation = realTimeJQValidation;
134135
}
135136

137+
public boolean isRealTimeXPathValidation() {
138+
return realTimeXPathValidation;
139+
}
140+
141+
public void setRealTimeXPathValidation(boolean realTimeXPathValidation) {
142+
this.realTimeXPathValidation = realTimeXPathValidation;
143+
}
144+
136145
public boolean isRealTimeIdReferenceTypeValidation() {
137146
return realTimeIdReferenceTypeValidation;
138147
}

src/main/java/com/github/cameltooling/idea/service/CamelService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ public synchronized boolean containsLibrary(String lib, boolean quickCheck) {
247247
boolean answer = processedLibraries.contains(lib);
248248
if (!answer && !quickCheck) {
249249
for (ArtifactCoordinates coordinates : projectLibraries.values()) {
250-
if (coordinates.getArtifactId().equals(lib)) {
250+
if (coordinates.getArtifactId().contains(lib)) {
251251
answer = true;
252252
break;
253253
}

src/main/java/com/github/cameltooling/idea/service/extension/camel/JavaCamelIdeaUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ public boolean isCamelExpression(PsiElement element, String language) {
248248
methods = new String[]{"jsonpath"};
249249
} else if ("jq".equals(language)) {
250250
methods = new String[]{"jq"};
251+
} else if ("xpath".equals(language)) {
252+
methods = new String[]{"xpath"};
251253
}
252254
if (methods != null) {
253255
return IdeaUtils.getService().isFromJavaMethodCall(element, true, methods);

src/main/resources/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
v.1.4.5
1313
<ul>
1414
<li>Only IDEA 2025 onwards is supported</li>
15+
<li>Added real-time validation of XPath expressions<li>
1516
</ul>
1617
]]>
1718
</change-notes>
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.github.cameltooling.idea.annotator;
18+
19+
import com.github.cameltooling.idea.CamelLightCodeInsightFixtureTestCaseIT;
20+
import com.github.cameltooling.idea.service.CamelCatalogService;
21+
import com.github.cameltooling.idea.service.CamelService;
22+
import com.intellij.openapi.application.ApplicationManager;
23+
import com.intellij.openapi.roots.ModuleRootModificationUtil;
24+
import com.intellij.openapi.roots.OrderRootType;
25+
import com.intellij.openapi.roots.libraries.Library;
26+
import com.intellij.openapi.roots.libraries.LibraryTable;
27+
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
28+
import com.intellij.openapi.vfs.LocalFileSystem;
29+
import com.intellij.openapi.vfs.VirtualFile;
30+
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
31+
32+
import java.io.File;
33+
import java.io.IOException;
34+
35+
/**
36+
* Test Camel XPath validation and the expected value is highlighted
37+
*
38+
* @see CamelSimpleAnnotatorTestIT
39+
*/
40+
public class CamelXPathAnnotatorTestIT extends CamelLightCodeInsightFixtureTestCaseIT {
41+
42+
public static final String CAMEL_XPATH_MAVEN_ARTIFACT = "org.apache.camel:camel-xpath:4.14.1";
43+
44+
public CamelXPathAnnotatorTestIT() {
45+
setIgnoreCamelCoreLib(true);
46+
}
47+
48+
@Override
49+
protected void setUp() throws Exception {
50+
super.setUp();
51+
File[] mavenArtifacts = getMavenArtifacts(CAMEL_XPATH_MAVEN_ARTIFACT);
52+
for (File file : mavenArtifacts) {
53+
final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
54+
final LibraryTable projectLibraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(getModule().getProject());
55+
ApplicationManager.getApplication().runWriteAction(() -> {
56+
String name = file.getName();
57+
Library library = projectLibraryTable.createLibrary("maven: " + name);
58+
final Library.ModifiableModel libraryModifiableModel = library.getModifiableModel();
59+
libraryModifiableModel.addRoot(virtualFile, OrderRootType.CLASSES);
60+
libraryModifiableModel.commit();
61+
ModuleRootModificationUtil.addDependency(getModule(), library);
62+
});
63+
}
64+
65+
disposeOnTearDown(getModule().getProject().getService(CamelCatalogService.class));
66+
disposeOnTearDown(getModule().getProject().getService(CamelService.class));
67+
getModule().getProject().getService(CamelService.class).setCamelPresent(true);
68+
}
69+
70+
@Override
71+
protected void tearDown() throws Exception {
72+
try {
73+
super.tearDown();
74+
} catch (Throwable e) {
75+
// ignore
76+
}
77+
}
78+
79+
protected static File[] getMavenArtifacts(String... mavenAritfiact) throws IOException {
80+
File[] libs = Maven.resolver().resolve(mavenAritfiact).withTransitivity().asFile();
81+
return libs;
82+
}
83+
84+
@Override
85+
protected String getTestDataPath() {
86+
return "src/test/resources/testData/annotator";
87+
}
88+
89+
public void testAnnotatorXPathValidation() {
90+
myFixture.configureByText("AnnotatorTestData.java", getJavaWithXPath());
91+
myFixture.checkHighlighting(false, false, true, true);
92+
}
93+
94+
private String getJavaWithXPath() {
95+
return """
96+
import org.apache.camel.builder.RouteBuilder;
97+
public class MyRouteBuilder extends RouteBuilder {
98+
public void configure() throws Exception {
99+
from("direct:start")
100+
.filter(xpath("\\/path/to"))
101+
.to("mock:match")
102+
.end();
103+
}
104+
}""";
105+
}
106+
107+
}

src/test/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPageTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,17 @@ public void testShouldChangeStateOfRealTimeJQValidationCatalogCheckBox() {
161161
assertFalse(preferenceService.isRealTimeJQValidation());
162162
}
163163

164+
public void testShouldChangeStateOfRealTimeXPathValidationCatalogCheckBox() {
165+
JBCheckBox checkBox = annotatorPage.getRealTimeXPathValidationCatalogCheckBox();
166+
assertTrue(checkBox.isSelected());
167+
final CamelPreferenceService preferenceService = CamelPreferenceService.getService();
168+
assertTrue(preferenceService.isRealTimeXPathValidation());
169+
checkBox.setSelected(false);
170+
annotatorPage.apply();
171+
assertFalse(checkBox.isSelected());
172+
assertFalse(preferenceService.isRealTimeXPathValidation());
173+
}
174+
164175
public void testShouldChangeStateOfRealTimeBeanMethodValidationCheckBox() {
165176
JBCheckBox checkBox = annotatorPage.getRealTimeBeanMethodValidationCheckBox();
166177
assertTrue(checkBox.isSelected());

0 commit comments

Comments
 (0)