diff --git a/src/main/java/com/github/cameltooling/idea/annotator/CamelJSonPathAnnotator.java b/src/main/java/com/github/cameltooling/idea/annotator/CamelLanguageAnnotator.java similarity index 79% rename from src/main/java/com/github/cameltooling/idea/annotator/CamelJSonPathAnnotator.java rename to src/main/java/com/github/cameltooling/idea/annotator/CamelLanguageAnnotator.java index 9c78e654..2428d601 100644 --- a/src/main/java/com/github/cameltooling/idea/annotator/CamelJSonPathAnnotator.java +++ b/src/main/java/com/github/cameltooling/idea/annotator/CamelLanguageAnnotator.java @@ -33,49 +33,51 @@ import org.jetbrains.annotations.NotNull; /** - * Validate JSonPath expression and annotated the specific jsonpath expression to highlight the error in the editor + * Validate language expression such as JSonPath/JQ to highlight the error in the editor */ -public class CamelJSonPathAnnotator extends AbstractCamelAnnotator { +public class CamelLanguageAnnotator extends AbstractCamelAnnotator { private static final Logger LOG = Logger.getInstance(CamelEndpointAnnotator.class); @Override boolean isEnabled() { - return CamelPreferenceService.getService().isRealTimeJSonPathValidation(); + return CamelPreferenceService.getService().isRealTimeJSonPathValidation() || CamelPreferenceService.getService().isRealTimeJQValidation(); } /** - * Validate jsonpath expression. eg jsonpath("$.store.book[?(@.price < 10)]") - * if the expression is not valid a error annotation is created and highlight the invalid value. + * Validate language expression, such as jsonpath("$.store.book[?(@.price < 10)]") + * if the expression is not valid an error annotation is created and highlight the invalid value. */ void validateText(@NotNull PsiElement element, @NotNull AnnotationHolder holder, @NotNull String text) { - final CamelIdeaUtils camelIdeaUtils = CamelIdeaUtils.getService(); - // only validate if the element is jsonpath element - if (camelIdeaUtils.isCamelExpression(element, "jsonpath")) { + + boolean json = CamelPreferenceService.getService().isRealTimeJSonPathValidation() && camelIdeaUtils.isCamelExpression(element, "jsonpath"); + boolean jq = CamelPreferenceService.getService().isRealTimeJQValidation() && camelIdeaUtils.isCamelExpression(element, "jq"); + if (json || jq) { Project project = element.getProject(); CamelCatalog catalogService = project.getService(CamelCatalogService.class).get(); CamelService camelService = project.getService(CamelService.class); - // must have camel-json library - boolean jsonLib = camelService.containsLibrary("camel-jsonpath", false); - if (!jsonLib) { - camelService.showMissingJSonPathJarNotification(); + // must have the supporting library + String lib = json ? "camel-jsonpath" : "camel-jq"; + if (!camelService.containsLibrary(lib, false)) { + camelService.showMissingLanguageJarNotification(lib); return; } + String lan = json ? "jsonpath" : "jq"; try { // need to use the classloader that can load classes from the project ClassLoader loader = camelService.getProjectClassloader(); if (loader != null) { LanguageValidationResult result; - boolean predicate = camelIdeaUtils.isCamelExpressionUsedAsPredicate(element, "jsonpath"); + boolean predicate = camelIdeaUtils.isCamelExpressionUsedAsPredicate(element, lan); if (predicate) { - LOG.debug("Inspecting jsonpath predicate: " + text); - result = catalogService.validateLanguagePredicate(loader, "jsonpath", text); + LOG.debug("Inspecting " + lan + " predicate: " + text); + result = catalogService.validateLanguagePredicate(loader, lan, text); } else { - LOG.debug("Inspecting jsonpath expression: " + text); - result = catalogService.validateLanguageExpression(loader, "jsonpath", text); + LOG.debug("Inspecting " + lan + " expression: " + text); + result = catalogService.validateLanguageExpression(loader, lan, text); } if (!result.isSuccess()) { String error = result.getShortError(); @@ -95,7 +97,7 @@ void validateText(@NotNull PsiElement element, @NotNull AnnotationHolder holder, } } } catch (Throwable e) { - LOG.warn("Error inspecting Camel jsonpath: " + text, e); + LOG.warn("Error inspecting Camel " + lan + ": " + text, e); } } } diff --git a/src/main/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPage.java b/src/main/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPage.java index 840571f9..0e34ccfc 100644 --- a/src/main/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPage.java +++ b/src/main/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPage.java @@ -37,6 +37,7 @@ public class CamelAnnotatorPage implements SearchableConfigurable, Configurable. private JBCheckBox highlightCustomOptionsCheckBox; private JBCheckBox realTimeSimpleValidationCatalogCheckBox; private JBCheckBox realTimeJSonPathValidationCatalogCheckBox; + private JBCheckBox realTimeJQValidationCatalogCheckBox; private JBCheckBox realTimeIdReferenceTypeValidationCheckBox; private JBCheckBox realTimeBeanMethodValidationCheckBox; private JPanel result; @@ -52,6 +53,7 @@ public JComponent createComponent() { highlightCustomOptionsCheckBox = new JBCheckBox("Highlight custom endpoint options as warnings in editor"); realTimeSimpleValidationCatalogCheckBox = new JBCheckBox("Real time validation of Camel simple language in editor"); realTimeJSonPathValidationCatalogCheckBox = new JBCheckBox("Real time validation of Camel JSonPath language in editor"); + realTimeJQValidationCatalogCheckBox = new JBCheckBox("Real time validation of Camel JQ language in editor"); realTimeIdReferenceTypeValidationCheckBox = new JBCheckBox("Real time type validation when referencing beans"); realTimeBeanMethodValidationCheckBox = new JBCheckBox("Real time validation of call bean method in editor"); @@ -63,6 +65,7 @@ public JComponent createComponent() { jPanel.add(highlightCustomOptionsCheckBox, "span 2"); jPanel.add(realTimeSimpleValidationCatalogCheckBox, "span 2"); jPanel.add(realTimeJSonPathValidationCatalogCheckBox, "span 2"); + jPanel.add(realTimeJQValidationCatalogCheckBox, "span 2"); jPanel.add(realTimeIdReferenceTypeValidationCheckBox, "span 2"); jPanel.add(realTimeBeanMethodValidationCheckBox, "span 2"); @@ -79,6 +82,7 @@ public void apply() { camelPreferenceService.setHighlightCustomOptions(highlightCustomOptionsCheckBox.isSelected()); camelPreferenceService.setRealTimeSimpleValidation(realTimeSimpleValidationCatalogCheckBox.isSelected()); camelPreferenceService.setRealTimeJSonPathValidation(realTimeJSonPathValidationCatalogCheckBox.isSelected()); + camelPreferenceService.setRealTimeJQValidation(realTimeJQValidationCatalogCheckBox.isSelected()); camelPreferenceService.setRealTimeIdReferenceTypeValidation(realTimeIdReferenceTypeValidationCheckBox.isSelected()); camelPreferenceService.setRealTimeBeanMethodValidationCheckBox(realTimeBeanMethodValidationCheckBox.isSelected()); } @@ -91,6 +95,7 @@ public boolean isModified() { || camelPreferenceService.isHighlightCustomOptions() != highlightCustomOptionsCheckBox.isSelected() || camelPreferenceService.isRealTimeSimpleValidation() != realTimeSimpleValidationCatalogCheckBox.isSelected() || camelPreferenceService.isRealTimeJSonPathValidation() != realTimeJSonPathValidationCatalogCheckBox.isSelected() + || camelPreferenceService.isRealTimeJQValidation() != realTimeJQValidationCatalogCheckBox.isSelected() || camelPreferenceService.isRealTimeIdReferenceTypeValidation() != realTimeIdReferenceTypeValidationCheckBox.isSelected() || camelPreferenceService.isRealTimeBeanMethodValidationCheckBox() != realTimeBeanMethodValidationCheckBox.isSelected(); return b1; @@ -103,6 +108,7 @@ public void reset() { highlightCustomOptionsCheckBox.setSelected(camelPreferenceService.isHighlightCustomOptions()); realTimeSimpleValidationCatalogCheckBox.setSelected(camelPreferenceService.isRealTimeSimpleValidation()); realTimeJSonPathValidationCatalogCheckBox.setSelected(camelPreferenceService.isRealTimeJSonPathValidation()); + realTimeJQValidationCatalogCheckBox.setSelected(camelPreferenceService.isRealTimeJQValidation()); realTimeIdReferenceTypeValidationCheckBox.setSelected(camelPreferenceService.isRealTimeIdReferenceTypeValidation()); realTimeBeanMethodValidationCheckBox.setSelected(camelPreferenceService.isRealTimeBeanMethodValidationCheckBox()); } @@ -113,6 +119,7 @@ public void disposeUIResources() { highlightCustomOptionsCheckBox = null; realTimeSimpleValidationCatalogCheckBox = null; realTimeJSonPathValidationCatalogCheckBox = null; + realTimeJQValidationCatalogCheckBox = null; realTimeIdReferenceTypeValidationCheckBox = null; realTimeBeanMethodValidationCheckBox = null; @@ -150,6 +157,10 @@ JBCheckBox getRealTimeJSonPathValidationCatalogCheckBox() { return realTimeJSonPathValidationCatalogCheckBox; } + public JBCheckBox getRealTimeJQValidationCatalogCheckBox() { + return realTimeJQValidationCatalogCheckBox; + } + JBCheckBox getRealTimeIdReferenceTypeValidationCheckBox() { return realTimeIdReferenceTypeValidationCheckBox; } diff --git a/src/main/java/com/github/cameltooling/idea/service/CamelPreferenceService.java b/src/main/java/com/github/cameltooling/idea/service/CamelPreferenceService.java index f918b839..4b71ba84 100644 --- a/src/main/java/com/github/cameltooling/idea/service/CamelPreferenceService.java +++ b/src/main/java/com/github/cameltooling/idea/service/CamelPreferenceService.java @@ -62,6 +62,7 @@ public class CamelPreferenceService implements PersistentStateComponent - - - - + + + + @@ -135,7 +135,7 @@ - + diff --git a/src/test/java/com/github/cameltooling/idea/annotator/CamelJQAnnotatorTestIT.java b/src/test/java/com/github/cameltooling/idea/annotator/CamelJQAnnotatorTestIT.java new file mode 100644 index 00000000..68271bf2 --- /dev/null +++ b/src/test/java/com/github/cameltooling/idea/annotator/CamelJQAnnotatorTestIT.java @@ -0,0 +1,106 @@ +/* + * 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 com.github.cameltooling.idea.annotator; + +import com.github.cameltooling.idea.CamelLightCodeInsightFixtureTestCaseIT; +import com.github.cameltooling.idea.service.CamelCatalogService; +import com.github.cameltooling.idea.service.CamelService; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.roots.ModuleRootModificationUtil; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import org.jboss.shrinkwrap.resolver.api.maven.Maven; + +import java.io.File; +import java.io.IOException; + +/** + * Test Camel JQ validation and the expected value is highlighted + * + * @see CamelSimpleAnnotatorTestIT + */ +public class CamelJQAnnotatorTestIT extends CamelLightCodeInsightFixtureTestCaseIT { + + public static final String CAMEL_JQ_MAVEN_ARTIFACT = "org.apache.camel:camel-jq:4.14.0"; + + public CamelJQAnnotatorTestIT() { + setIgnoreCamelCoreLib(true); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + File[] mavenArtifacts = getMavenArtifacts(CAMEL_JQ_MAVEN_ARTIFACT); + for (File file : mavenArtifacts) { + final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); + final LibraryTable projectLibraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(getModule().getProject()); + ApplicationManager.getApplication().runWriteAction(() -> { + String name = file.getName(); + Library library = projectLibraryTable.createLibrary("maven: " + name); + final Library.ModifiableModel libraryModifiableModel = library.getModifiableModel(); + libraryModifiableModel.addRoot(virtualFile, OrderRootType.CLASSES); + libraryModifiableModel.commit(); + ModuleRootModificationUtil.addDependency(getModule(), library); + }); + } + + disposeOnTearDown(getModule().getProject().getService(CamelCatalogService.class)); + disposeOnTearDown(getModule().getProject().getService(CamelService.class)); + getModule().getProject().getService(CamelService.class).setCamelPresent(true); + } + + @Override + protected void tearDown() throws Exception { + try { + super.tearDown(); + } catch (Throwable e) { + // ignore + } + } + + protected static File[] getMavenArtifacts(String... mavenAritfiact) throws IOException { + File[] libs = Maven.resolver().resolve(mavenAritfiact).withTransitivity().asFile(); + return libs; + } + + @Override + protected String getTestDataPath() { + return "src/test/resources/testData/annotator"; + } + + public void testAnnotatorJQValidation() { + myFixture.configureByText("AnnotatorTestData.java", getJavaWithJQ()); + myFixture.checkHighlighting(false, false, true, true); + } + + private String getJavaWithJQ() { + return """ + import org.apache.camel.builder.RouteBuilder; + public class MyRouteBuilder extends RouteBuilder { + public void configure() throws Exception { + from("direct:start") + .transform() + .jq(" at line 1, column 13>".store.book[a"); + } + }"""; + } + +} diff --git a/src/test/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPageTest.java b/src/test/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPageTest.java index d16d9e48..5a207ab1 100644 --- a/src/test/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPageTest.java +++ b/src/test/java/com/github/cameltooling/idea/preference/annotator/CamelAnnotatorPageTest.java @@ -150,6 +150,17 @@ public void testShouldChangeStateOfRealTimeJSonPathValidationCatalogCheckBox() { assertFalse(preferenceService.isRealTimeJSonPathValidation()); } + public void testShouldChangeStateOfRealTimeJQValidationCatalogCheckBox() { + JBCheckBox checkBox = annotatorPage.getRealTimeJQValidationCatalogCheckBox(); + assertTrue(checkBox.isSelected()); + final CamelPreferenceService preferenceService = CamelPreferenceService.getService(); + assertTrue(preferenceService.isRealTimeJQValidation()); + checkBox.setSelected(false); + annotatorPage.apply(); + assertFalse(checkBox.isSelected()); + assertFalse(preferenceService.isRealTimeJQValidation()); + } + public void testShouldChangeStateOfRealTimeBeanMethodValidationCheckBox() { JBCheckBox checkBox = annotatorPage.getRealTimeBeanMethodValidationCheckBox(); assertTrue(checkBox.isSelected());