本文配合 [[扩展你的lombok-2.0]] 所更新。在 [[扩展你的lombok]] 里面有旧版插件开发。

环境准备

克隆仓库

git clone https://github.com/mplushnikov/lombok-intellij-plugin.git

下载完成后使用idea打开该项目。之前需要修改大量的配置,现在不需要了。

修改gradle.properties,修改插件版本号 pluginVersion和平台版本号platformVersion(也就是对应的idea版本):

pluginVersion=999.1.1

#platformVersion = LATEST-EAP-SNAPSHOT
platformVersion = 2023.3.8

LATEST-EAP-SNAPSHOT会获取最新社区版,但是项目使用了几个旧版本的API。这边就不改原代码了,直接使用旧版本。

修改build.gradle,添加本地仓库和

repositories {  
  mavenCentral()  
  // 添加本地仓库,用来获取我们开发的lombok
  maven{  
    url "file://c://repo"  
  }  
}

dependencies {  
//  lombok group: 'org.projectlombok', name: 'lombok', version: '1.18.30', classifier: 'sources', ext: 'jar'  
  // 我们自己开发的插件
  lombok group: 'org.projectlombok', name: 'lombok', version: '1.18.29-bro', classifier: 'sources', ext: 'jar'  
  
  testImplementation("junit:junit:4.13.2")  
  testImplementation("org.mockito:mockito-core:5.8.0")  
  testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.10.1")  
}

执行准备环境task

prepareUiTestingSandbox

开发功能

LombokClassNames添加TO_JSON_STRING

package de.plushnikov.intellij.plugin;

public interface LombokClassNames {  
  // 添加ToJsonString注解全限定类名  
  @NonNls String TO_JSON_STRING = "lombok.extern.json.ToJsonString";
}

添加ToJsonStringProcessor

package de.plushnikov.intellij.plugin.processor.clazz;  
  
import com.intellij.psi.*;  
import com.intellij.psi.search.GlobalSearchScope;  
import de.plushnikov.intellij.plugin.LombokClassNames;  
import de.plushnikov.intellij.plugin.problem.ProblemSink;  
import de.plushnikov.intellij.plugin.psi.LombokLightMethodBuilder;  
import de.plushnikov.intellij.plugin.thirdparty.LombokAddNullAnnotations;  
import de.plushnikov.intellij.plugin.util.PsiClassUtil;  
import de.plushnikov.intellij.plugin.util.PsiMethodUtil;  
import org.jetbrains.annotations.NotNull;  
import org.jetbrains.annotations.Nullable;  
  
import java.util.Collection;  
import java.util.Collections;  
import java.util.List;  
  
public class ToJsonStringProcessor extends AbstractClassProcessor {  
  
  public static final String TO_JSON_STRING_METHOD_NAME = "toJsonString";  
  
  public ToJsonStringProcessor() {  
    super(PsiMethod.class, LombokClassNames.TO_JSON_STRING);  
  }  
  
  @Override  
  protected boolean possibleToGenerateElementNamed(@Nullable String nameHint, @NotNull PsiClass psiClass,  
                                                   @NotNull PsiAnnotation psiAnnotation) {  
    return nameHint == null || nameHint.equals(TO_JSON_STRING_METHOD_NAME);  
  }  
  
  @Override  
  protected boolean validate(@NotNull PsiAnnotation psiAnnotation, @NotNull PsiClass psiClass, @NotNull ProblemSink builder) {  
    boolean result = true;  
    if (psiClass.isAnnotationType() || psiClass.isInterface()) {  
      result = false;  
    }  
    if (result) {  
      if (hasToJsonStringMethodDefined(psiClass)) {  
        builder.addWarningMessage("inspection.message.not.generated.s.method.with.same.name.already.exists", TO_JSON_STRING_METHOD_NAME);  
      }  
    }  
    return result;  
  }  
  
  @Override  
  protected void generatePsiElements(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation, @NotNull List<? super PsiElement> target, @Nullable String nameHint) {  
    target.addAll(createToJsonStringMethod4All(psiClass, psiAnnotation));  
  }  
  
  
  private boolean hasToJsonStringMethodDefined(@NotNull PsiClass psiClass) {  
    final Collection<PsiMethod> classMethods = PsiClassUtil.collectClassMethodsIntern(psiClass);  
    return PsiMethodUtil.hasMethodByName(classMethods, TO_JSON_STRING_METHOD_NAME, 0);  
  }  
  
  @NotNull  
  Collection<PsiMethod> createToJsonStringMethod4All(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation) {  
    if (hasToJsonStringMethodDefined(psiClass)) {  
      return Collections.emptyList();  
    }  
  
    final PsiMethod stringMethod = createToJsonStringMethod(psiClass, psiAnnotation);  
    return Collections.singletonList(stringMethod);  
  }  
  
  
  @NotNull  
  public PsiMethod createToJsonStringMethod(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation) {  
    final PsiManager psiManager = psiClass.getManager();  
    // 直接生成对应的string  
    final String body = "com.alibaba.fastjson.JSON.toJSONString(this)";  
    final String blockText = String.format("return %s;", body);  
  
    final LombokLightMethodBuilder methodBuilder = new LombokLightMethodBuilder(psiManager, TO_JSON_STRING_METHOD_NAME)  
      .withMethodReturnType(PsiType.getJavaLangString(psiManager, GlobalSearchScope.allScope(psiClass.getProject())))  
      .withContainingClass(psiClass)  
      .withNavigationElement(psiAnnotation)  
      .withModifier(PsiModifier.PUBLIC)  
      .withBodyText(blockText);  
  
    LombokAddNullAnnotations.createRelevantNonNullAnnotation(psiClass, methodBuilder);  
  
    return methodBuilder;  
  }  
  
}

添加LombokToJsonStringHandler

package de.plushnikov.intellij.plugin.action.lombok;  
  
import com.intellij.psi.*;  
import de.plushnikov.intellij.plugin.LombokClassNames;  
import org.jetbrains.annotations.NotNull;  
  
public class LombokToJsonStringHandler extends BaseLombokHandler {  
  
  @Override  
  protected void processClass(@NotNull PsiClass psiClass) {  
    final PsiElementFactory factory = JavaPsiFacade.getElementFactory(psiClass.getProject());  
    final PsiClassType stringClassType = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, psiClass.getResolveScope());  
  
    final PsiMethod toStringMethod = findPublicNonStaticMethod(psiClass, "toJsonString", stringClassType);  
    if (null != toStringMethod) {  
      toStringMethod.delete();  
    }  
    addAnnotation(psiClass, LombokClassNames.TO_JSON_STRING);  
  }  
  
  
}

添加LombokToJsonStringAction

package de.plushnikov.intellij.plugin.action.lombok;  
  
public class LombokToJsonStringAction extends BaseLombokAction {  
  
  public LombokToJsonStringAction() {  
    super(new LombokToJsonStringHandler());  
  }  
  
}

修改LombokProcessorManager

package de.plushnikov.intellij.plugin.processor;  
  
  
@Service  
public final class LombokProcessorManager {
    // json  
    private final ToJsonStringProcessor myToJsonStringProcessor = new ToJsonStringProcessor();

    public ToJsonStringProcessor getToJsonStringProcessor() {  
      return myToJsonStringProcessor;  
    }

    @NotNull  
    private Collection<Processor> getAllProcessors() {
        return Arrays.asList(
        // 添加
        myToJsonStringProcessor,
        ....
        )
    }
}

添加DelombokToJsonStringAction

package de.plushnikov.intellij.plugin.action.delombok;  
  
import de.plushnikov.intellij.plugin.processor.LombokProcessorManager;  
import org.jetbrains.annotations.NotNull;  
  
public class DelombokToJsonStringAction extends AbstractDelombokAction {  
  @Override  
  @NotNull  protected DelombokHandler createHandler() {  
    return new DelombokHandler(LombokProcessorManager.getInstance().getToJsonStringProcessor());  
  }  
}

修改LombokBundle.properties

  
# tojsonstring  
action.defaultLombokToJsonString.text=Default @ToJsonString  
action.defaultLombokToJsonString.description=Action to replace toString method with lombok @ToJsonString annotation

# 添加相关msg  
action.delombokToJsonString.text=@ToJsonString  
action.delombokToJsonString.description=Action to replace lombok @ToJsonString annotation with vanilla java methods

修改plugin.xml

<actions>  
  <group id="LombokActionGroup" class="de.plushnikov.intellij.plugin.action.LombokMenuGroup" icon="LombokIcons.Lombok" popup="true">  
    <!-- 添加Action -->  
    <action id="defaultLombokToJsonString" class="de.plushnikov.intellij.plugin.action.lombok.LombokToJsonStringAction"/>  

    <add-to-group group-id="RefactoringMenu" anchor="last"/>  
  </group>  
  <group id="DelombokActionGroup" class="de.plushnikov.intellij.plugin.action.LombokMenuGroup" icon="LombokIcons.Lombok" popup="true">  
  
    <action id="delombokToJsonString" class="de.plushnikov.intellij.plugin.action.delombok.DelombokToJsonStringAction"/> 
    <!-- 添加Action -->  
    <add-to-group group-id="RefactoringMenu" anchor="last"/>  
  </group>
</actions>

测试

执行测试task

runIdeForUiTests

会启动一个idea供我们调试,我们在这个idea测试环境创建我们的测试项目

添加我们的lombok依赖

<dependency>  
    <groupId>com.alibaba</groupId>  
    <artifactId>fastjson</artifactId>  
    <version>2.0.31</version>  
</dependency>  
<dependency>  
    <groupId>org.projectlombok</groupId>  
    <artifactId>lombok</artifactId>  
    <version>1.18.29-bro</version>  
    <scope>provided</scope>  
</dependency>

使用新开发的注解

package com.bigbrotherlee;  
  
import lombok.extern.json.ToJsonString;  
  
@ToJsonString  
@lombok.Data  
public class Data {  
    private String name;  
    private int id = 1;  
}

使用:

package com.bigbrotherlee;  
  
public class Main {  
    public static void main(String[] args) {  
        Data data = new Data();  
        System.out.println(data.toJsonString());  
        data.setName("bro");  
        System.out.println(data.toJsonString());  
    }  
}

如果我们的psi无法处理,toJsonString会报红。但是运行不会有错误,因为运行使用的是javac。如果psi正确,那么我们也可以在Structure卡查看到toJsonString。

打包与发布

运行buildPlugin task,打包完成后可以使用build/distributions/目录下面的插件发布到你公司内部的Idea插件仓库,或者直接提供zip从硬盘安装使用。如果build/distributions/目录没有,则在gradle界面执行buildPlugin task打包插件。

标签: lombok

添加新评论