Problem with PsiReferenceContributor in Java annotation strings

Hi,

 

I am trying to write a IntelliJ IDEA plugin for http://mapstruct.org/ the plugin should provide support for auto-completion and referencing the properties from the @Mapping annotation to the appropriate classes. In order to do that I am writing my own PsiReferenceContributor and implementing a resolve method appropriately. To better describe my problem, I'll write some code (the plugin will be open source in any case).

 

We have the following class:

 

public class Something { 
private String field;

public String getField() {
return field;
}

public void setField(String field) {
this.field = field;
}
}

public class SomethingElse { 
private String anotherField;

public String getAnotherField() {
return field;
}

public void setAnotherField(String anotherField) {
this.anotherField = anotherField;
}
}

 

I have the following Mapper 

public interface MyMapper {

@Mapping(target = "field", source = "anotherField")
Something map(SomethingElse source);
}

The value "field" resolves to the getField() method from Something and "anotherField` resolves to the method setAnotherField(String anotherField) from SomethingElse. Go To Declaration works correctly. However, when I want to Find Usages from the referenced methods the strings are not found, when I want to rename the methods in my PsiReferenceBase is not invoked, the strings are also not highlighted.

 

 

The resolve method for target looks like:

public PsiElement resolve() {
PsiClass returnClass = getRelevantClass();
String value = getValue();
if ( returnClass == null || value.isEmpty() ) {
return null;
}
PsiMethod[] methods = returnClass.findMethodsByName( "set" + Strings.capitalize( value ), true );

return methods.length == 0 ? null : methods[0];
}

And for the source it looks like:

public PsiElement resolve() {
PsiClass sourceClass = getRelevantClass();
String value = getValue();
if ( sourceClass == null || value.isEmpty()) {
return null;
}
PsiMethod[] methods = sourceClass.findMethodsByName( "get" + Strings.capitalize( value ), true );

return methods.length == 0 ? null : methods[0];
}

However, if I change resolve methods to (similar as the resolve for the TestNg DataProvider and the JUnit 5 MethodSource):

public PsiElement resolve() {
PsiClass sourceClass = getRelevantClass();
String value = getValue();
if ( sourceClass == null || value.isEmpty()) {
return null;
}
PsiMethod[] methods = sourceClass.findMethodsByName( value, true );

return methods.length == 0 ? null : methods[0];
}

And the mapping to (this is not a valid MapStruct mapping):

public interface MyMapper {

@Mapping(target = "setField", source = "getAnotherField")
Something map(SomethingElse source);
}

Then everything works correctly. When I do Find Usages on the methods, then they are found, renaming works as well and the strings are highlighted. 

I really do not understand what I am doing wrong. Why is the first approach not working?

 

0
4 comments
Avatar
Permanently deleted user
Official comment

By default IDEA searches for references which contains the exact text as the element they are reference to. E.g. "setField", not "field". It looks like IDEA doesn't know there can be usages in annotations argument strings in this abbreviated form. To tell the indexing subsystem of these usages you can write your specialized reference searcher which will add these occurrences to the scope. See for example com.intellij.psi.impl.search.SimpleAccessorReferenceSearcher. Note that you'll need to register this searcher in your plugin.xml like this: 

<referencesSearch implementation="com.intellij.psi.impl.search.SimpleAccessorReferenceSearcher"/>
Avatar
Permanently deleted user

I have also pushed a repository to github. You can find it here: https://github.com/mapstruct/mapstruct-idea 

0
Avatar
Permanently deleted user

In order to test it you can clone the https://github.com/mapstruct/mapstruct-examples repo. And from there you can use the EmployeeMapper

0
Avatar
Permanently deleted user

Thanks for the answer. I will try with what you are suggesting.

A followup: Will this referencesSearch be used for renaming as well (both sides, from the annotation and the renaming of the methods)?

0

Please sign in to leave a comment.