Skip to content

Commit 1580aba

Browse files
committed
add support for property references in the value of blueprint's ConfigProperty annotation
1 parent e950c08 commit 1580aba

File tree

8 files changed

+180
-12
lines changed

8 files changed

+180
-12
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.github.cameltooling.idea.reference.blueprint;
2+
3+
import com.github.cameltooling.idea.reference.CamelPsiReferenceProvider;
4+
import com.intellij.lang.properties.references.PropertyReference;
5+
import com.intellij.openapi.util.TextRange;
6+
import com.intellij.openapi.util.text.StringUtil;
7+
import com.intellij.patterns.PsiJavaElementPattern;
8+
import com.intellij.patterns.PsiJavaPatterns;
9+
import com.intellij.patterns.StandardPatterns;
10+
import com.intellij.psi.*;
11+
import com.intellij.util.ProcessingContext;
12+
import org.jetbrains.annotations.NotNull;
13+
import org.jetbrains.annotations.Nullable;
14+
15+
public class ConfigPropertyPlaceholderReferenceContributor extends PsiReferenceContributor {
16+
17+
private static final String ANNOTATION_BLUEPRINT_CONFIG_PROPERTY = "org.apache.aries.blueprint.annotation.config.ConfigProperty";
18+
private static final PsiJavaElementPattern.Capture<PsiLiteralExpression> PATTERN = PsiJavaPatterns.literalExpression()
19+
.insideAnnotationParam(StandardPatterns.string()
20+
.equalTo(ANNOTATION_BLUEPRINT_CONFIG_PROPERTY),
21+
"value");
22+
23+
@Override
24+
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
25+
registrar.registerReferenceProvider(PATTERN, new CamelPsiReferenceProvider() {
26+
27+
@Override
28+
protected PsiReference[] getCamelReferencesByElement(PsiElement element, ProcessingContext context) {
29+
String origText = element.getText();
30+
String value = StringUtil.unquoteString(origText);
31+
if (value.startsWith("${") && value.endsWith("}")) {
32+
int startOffset = origText.startsWith("\"") ? 3 : 2;
33+
String propertyKey = value.substring(2, value.length() - 1);
34+
var textRange = new TextRange(startOffset, startOffset + propertyKey.length());
35+
return new PsiReference[] {
36+
new PropertyReference(propertyKey, element, null, true, textRange)
37+
};
38+
} else {
39+
// we do not want the default PropertyReference IDEA places on all string literals to be present,
40+
// because it would work and could lead user to think it's the proper syntax. So let's place
41+
// a fake reference that is not resolvable.
42+
return new PsiReference[] {
43+
new NonResolvableReference(element)
44+
};
45+
}
46+
}
47+
}, PsiReferenceRegistrar.HIGHER_PRIORITY); // IDEA offers its own placeholder reference to the whole string, including ${ and }, so we make our more important
48+
}
49+
50+
private static class NonResolvableReference extends PsiReferenceBase<PsiElement> {
51+
52+
private NonResolvableReference(PsiElement element) {
53+
super(element);
54+
}
55+
56+
@Override
57+
public @Nullable PsiElement resolve() {
58+
return null;
59+
}
60+
61+
}
62+
63+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
<psi.referenceContributor implementation="com.github.cameltooling.idea.reference.blueprint.BlueprintReferenceContributor"/>
149149
<psi.referenceContributor implementation="com.github.cameltooling.idea.reference.CamelBeanInjectReferenceContributor"/>
150150
<psi.referenceContributor implementation="com.github.cameltooling.idea.reference.CamelPropertyPlaceholderReferenceContributor"/>
151+
<psi.referenceContributor implementation="com.github.cameltooling.idea.reference.blueprint.ConfigPropertyPlaceholderReferenceContributor" language="JAVA"/>
151152
<renameHandler implementation="com.github.cameltooling.idea.reference.CamelBeanReferenceRenameHandler"/>
152153
<postFormatProcessor implementation="com.github.cameltooling.idea.formatter.CamelPostFormatProcessor"/>
153154

src/test/java/com/github/cameltooling/idea/reference/CamelPropertyPlaceholderReferenceContributorTest.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@
2222
import com.intellij.psi.PsiElement;
2323
import com.intellij.psi.PsiReference;
2424

25-
import java.util.Arrays;
2625
import java.util.List;
2726

27+
import static com.github.cameltooling.idea.reference.TestReferenceUtil.getPropertyReferences;
28+
2829
public class CamelPropertyPlaceholderReferenceContributorTest extends CamelLightCodeInsightFixtureTestCaseIT {
2930

3031
public void testNoReferencesForIncompletePlaceholders() {
@@ -133,13 +134,4 @@ private void assertContainsPropertyReference(PsiElement caretElement, String pro
133134
assertEquals(new TextRange(refStartOffset, refStartOffset + propertyName.length()), myPropRef.getRangeInElement());
134135
}
135136

136-
private static List<PropertyReference> getPropertyReferences(PsiElement caretElement) {
137-
PsiReference[] refs = caretElement.getReferences();
138-
return Arrays.stream(refs)
139-
.filter(ref -> ref instanceof PropertyReference)
140-
.map(ref -> (PropertyReference) ref)
141-
.toList();
142-
}
143-
144-
145137
}

src/test/java/com/github/cameltooling/idea/reference/TestReferenceUtil.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package com.github.cameltooling.idea.reference;
22

3+
import com.intellij.lang.properties.references.PropertyReference;
34
import com.intellij.psi.PsiElement;
45
import com.intellij.psi.PsiPolyVariantReference;
56
import com.intellij.psi.PsiReference;
67
import com.intellij.psi.ResolveResult;
78
import com.intellij.psi.util.PsiTreeUtil;
89
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture;
9-
import org.jetbrains.annotations.NotNull;
1010
import org.junit.Assert;
1111

1212
import java.util.Arrays;
13-
import java.util.Collections;
1413
import java.util.List;
1514
import java.util.Objects;
1615
import java.util.stream.Collectors;
@@ -64,4 +63,16 @@ private static PsiElement getPsiElement(PsiElement element) {
6463
}
6564
}
6665

66+
public static List<PropertyReference> getPropertyReferences(PsiElement caretElement) {
67+
return getReferencesOfType(caretElement, PropertyReference.class);
68+
}
69+
70+
public static <T extends PsiReference> List<T> getReferencesOfType(PsiElement caretElement, Class<T> refType) {
71+
PsiReference[] refs = caretElement.getReferences();
72+
return Arrays.stream(refs)
73+
.filter(refType::isInstance)
74+
.map(refType::cast)
75+
.toList();
76+
}
77+
6778
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.github.cameltooling.idea.reference.blueprint;
2+
3+
import com.github.cameltooling.idea.CamelLightCodeInsightFixtureTestCaseIT;
4+
import com.github.cameltooling.idea.reference.TestReferenceUtil;
5+
import com.intellij.lang.properties.psi.Property;
6+
import com.intellij.lang.properties.references.PropertyReference;
7+
import com.intellij.openapi.util.TextRange;
8+
import com.intellij.psi.PsiElement;
9+
import org.jetbrains.annotations.Nullable;
10+
11+
import java.util.List;
12+
13+
import static com.github.cameltooling.idea.reference.TestReferenceUtil.getPropertyReferences;
14+
15+
public class ConfigPropertyPlaceholderReferenceContributorIT extends CamelLightCodeInsightFixtureTestCaseIT {
16+
17+
@Override
18+
protected @Nullable String[] getMavenDependencies() {
19+
return new String[] { CAMEL_CORE_MODEL_MAVEN_ARTIFACT, "org.apache.aries.blueprint:blueprint-maven-plugin-annotation:1.3.0" };
20+
}
21+
22+
public void testNotAppliedWithIncorrectAnnotation() {
23+
myFixture.configureByFiles("reference/blueprint/config-property/IncorrectConfigPropertyAnnotation.java", "CompleteJavaPropertyTestData.properties");
24+
25+
PsiElement property = getPropertyRefAtCaret().resolve();
26+
assertNull(property);
27+
}
28+
29+
public void testNormalBehavior() {
30+
myFixture.configureByFiles("reference/blueprint/config-property/TestClass1.java", "CompleteJavaPropertyTestData.properties");
31+
32+
PropertyReference ref = getPropertyRefAtCaret();
33+
assertEquals(new TextRange(3, 13), ref.getRangeInElement());
34+
Property property = (Property) ref.resolve();
35+
assertNotNull(property);
36+
assertEquals("ftp.client", property.getKey());
37+
}
38+
39+
public void testDefaultPropertyReferenceNotAppliedForRawValue() {
40+
myFixture.configureByFiles("reference/blueprint/config-property/DefaultPropertyReferenceNotAppliedForRawValue.java", "CompleteJavaPropertyTestData.properties");
41+
PsiElement element = TestReferenceUtil.getParentElementAtCaret(myFixture);
42+
List<PropertyReference> refs = getPropertyReferences(element);
43+
assertTrue(refs.isEmpty());
44+
}
45+
46+
private PropertyReference getPropertyRefAtCaret() {
47+
PsiElement element = TestReferenceUtil.getParentElementAtCaret(myFixture);
48+
List<PropertyReference> refs = getPropertyReferences(element);
49+
assertFalse(refs.isEmpty());
50+
return refs.getFirst();
51+
}
52+
53+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import org.apache.camel.builder.RouteBuilder;
2+
3+
import org.apache.aries.blueprint.annotation.config.ConfigProperty;
4+
5+
public final class TestClass1 extends RouteBuilder {
6+
7+
@ConfigProperty("ftp.clie<caret>nt")
8+
private String ftpClient;
9+
10+
@Override
11+
public void configure() {
12+
from("file:inbox")
13+
.bean(CompleteJavaBeanTestData.class, "letsDoThis")
14+
.to("log:out");
15+
}
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import org.apache.camel.builder.RouteBuilder;
2+
import org.apache.camel.main.Main;
3+
4+
import my.custom.ConfigProperty;
5+
6+
public final class IncorrectConfigPropertyAnnotation extends RouteBuilder {
7+
8+
@ConfigProperty("${ftp.clie<caret>nt}")
9+
private String ftpClient;
10+
11+
@Override
12+
public void configure() {
13+
from("file:inbox")
14+
.bean(CompleteJavaBeanTestData.class, "letsDoThis")
15+
.to("log:out");
16+
}
17+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import org.apache.aries.blueprint.annotation.config.ConfigProperty;
2+
import org.apache.camel.builder.RouteBuilder;
3+
4+
public final class TestClass1 extends RouteBuilder {
5+
6+
@ConfigProperty(value = "${ftp.clie<caret>nt}")
7+
private String ftpClient;
8+
9+
@Override
10+
public void configure() {
11+
from("file:inbox")
12+
.bean(CompleteJavaBeanTestData.class, "letsDoThis")
13+
.to("log:out");
14+
}
15+
}

0 commit comments

Comments
 (0)