From d836812f736237438eeca89dafc9564a7844c181 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 27 Nov 2021 20:31:31 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E4=BF=AE=E6=94=B9IDL=E4=B8=BAThrift=20ID?= =?UTF-8?q?L?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/META-INF/plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index 78bf8fb..77ac543 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -42,7 +42,7 @@ From 7969d1383b05b658569b6e7643097c91743fd8b5 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 25 Dec 2021 12:13:49 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8F=92=E4=BB=B6BUG:?= =?UTF-8?q?=201.=20=E5=B0=86Class=20To=20IDL=E6=9B=B4=E5=90=8D=E4=B8=BACla?= =?UTF-8?q?ss=20To=20Thrift=20IDL=202.=20=E4=BF=AE=E5=A4=8DClass=20To=20Th?= =?UTF-8?q?rift=20IDL=E5=8A=9F=E8=83=BD=E5=AF=B9BigDecimal=E7=B1=BB?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E5=BC=82=E5=B8=B8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 ++++----- object-helper.jar | Bin 31706 -> 31824 bytes resources/META-INF/plugin.xml | 14 +++++++------ ...ction.java => ClassToThriftIDLAction.java} | 6 +++--- .../common/constant/JavaClassName.java | 1 + .../objecthelper/common/util/IDLUtils.java | 19 ++++++++---------- .../common/util/PsiTypeUtils.java | 3 ++- ...Generator.java => ThriftIDLGenerator.java} | 14 ++++++++----- 8 files changed, 36 insertions(+), 31 deletions(-) rename src/cn/bigcoder/plugin/objecthelper/action/{ClassToIDLAction.java => ClassToThriftIDLAction.java} (87%) rename src/cn/bigcoder/plugin/objecthelper/generator/idl/{IDLGenerator.java => ThriftIDLGenerator.java} (94%) diff --git a/README.md b/README.md index ccf3df9..6da371d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # object-helper-plugin -![](https://img.shields.io/badge/version-v1.2.0-blue) +![](https://img.shields.io/badge/version-v1.2.1-blue) ![](https://img.shields.io/badge/license-Apache%202-red) -![](https://img.shields.io/badge/size-36.43%20kB-yellowgreen) -![](https://img.shields.io/badge/download-500%2B-green) +![](https://img.shields.io/badge/size-36.54%20kB-yellowgreen) +![](https://img.shields.io/badge/download-1.1k-green) 插件地址:[https://plugins.jetbrains.com/plugin/15788-objecthelper](https://plugins.jetbrains.com/plugin/15788-objecthelper) @@ -16,14 +16,14 @@ JetBrains Intellij IDEA ObjectHelper插件,包含以下功能: ![](https://image.bigcoder.cn/20210227223302.gif) -- Java类转IDL +- Java类转Thrift IDL ![](https://image.bigcoder.cn/6eee7a02-8e4e-4f11-9b8c-81d661a920c5.gif) ## 未来功能支持计划 object-helper插件未来功能支持计划: -- [x] Class转IDL(Class To IDL) +- [x] Class转IDL(Class To Thrift IDL) - [ ] Class转XML(Class To XML) - [ ] JSON转Class(JSON TO Class) - [ ] All Setter diff --git a/object-helper.jar b/object-helper.jar index 79aa4588bcd543ab7b438dd77d2266748b971a3c..d9beb5e35ddc8c1f85956455ad334d32b4aa82cd 100644 GIT binary patch delta 20504 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%0D(=84E`XSAe^d>wiw)Qf+u|ja7UhuM;XKb{{fU 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 piJsKac}ZHOE&sjsNuuRr9_4^(tOf-$z!xP cn.bigcoder.plugin.objecthelper ObjectHelper - 1.2.0 + 1.2.1 HearingSmile New feature:Added the ability to quickly convert Java classes to IDL +

  • Fix:rename "Class To IDL" to "Class To Thrift IDL"
  • +
  • Fix bug:fix "Class To Thrift IDL" BigDecimal conversion exception
  • ]]> @@ -39,12 +40,13 @@ class="cn.bigcoder.plugin.objecthelper.action.ClassToFormatJsonAction" text="Class To JSON" description="Converts the Java class to a JSON string"> - + - + + diff --git a/src/cn/bigcoder/plugin/objecthelper/action/ClassToIDLAction.java b/src/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java similarity index 87% rename from src/cn/bigcoder/plugin/objecthelper/action/ClassToIDLAction.java rename to src/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java index aff3631..95a7e61 100644 --- a/src/cn/bigcoder/plugin/objecthelper/action/ClassToIDLAction.java +++ b/src/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java @@ -1,7 +1,7 @@ package cn.bigcoder.plugin.objecthelper.action; import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; -import cn.bigcoder.plugin.objecthelper.generator.idl.IDLGenerator; +import cn.bigcoder.plugin.objecthelper.generator.idl.ThriftIDLGenerator; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.ide.CopyPasteManager; @@ -17,14 +17,14 @@ * @author: Jindong.Tian * @date: 2021-08-21 **/ -public class ClassToIDLAction extends AnAction { +public class ClassToThriftIDLAction extends AnAction { @Override public void actionPerformed(@NotNull AnActionEvent anActionEvent) { PsiClass psiClass = getOperatePsiClass(anActionEvent); if (psiClass == null) { return; } - String idl = IDLGenerator.getInstance(psiClass).generate(); + String idl = ThriftIDLGenerator.getInstance(psiClass).generate(); CopyPasteManager.getInstance().setContents(new StringSelection(idl)); NotificationUtils.notifyInfo(anActionEvent.getProject(), "IDL代码成功置入剪贴板:
    " + idl); } diff --git a/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java b/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java index 9f18611..8360806 100644 --- a/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java +++ b/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java @@ -15,6 +15,7 @@ public class JavaClassName { public static final String DATE_TYPE = "java.util.Date"; public static final String LOCAL_DATE_TYPE = "java.time.LocalDate"; public static final String LOCAL_DATE_TIME_TYPE = "java.time.LocalDateTime"; + public static final String BIG_DECIMAL = "java.math.BigDecimal"; public static final String COLLECTION_TYPE = "java.util.Collection"; public static final String MAP_TYPE = "java.util.Map"; diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java b/src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java index 3264f6b..a519651 100644 --- a/src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java +++ b/src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java @@ -20,25 +20,22 @@ public static String convertJavaTypeToIDLType(String canonicalText){ } switch (canonicalText) { case STRING_TYPE: + case BIG_DECIMAL: return STRING; + case BYTE_TYPE: + return BYTE; + case SHORT_TYPE: + return I16; case INTEGER_TYPE: return I32; case LONG_TYPE: + case LOCAL_DATE_TYPE: + case DATE_TYPE: + case LOCAL_DATE_TIME_TYPE: return I64; - case SHORT_TYPE: - return I16; - case BYTE_TYPE: - return BYTE; case DOUBLE_TYPE: - return DOUBLE; case FLOAT_TYPE: return DOUBLE; - case DATE_TYPE: - return I64; - case LOCAL_DATE_TYPE: - return I64; - case LOCAL_DATE_TIME_TYPE: - return I64; default: return null; } diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java index 9286362..0f00f1a 100644 --- a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java +++ b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java @@ -72,7 +72,8 @@ public static boolean isDataType(PsiType psiType) { || FLOAT_TYPE.equals(canonicalName) || DATE_TYPE.equals(canonicalName) || LOCAL_DATE_TYPE.equals(canonicalName) - || LOCAL_DATE_TIME_TYPE.equals(canonicalName)) { + || LOCAL_DATE_TIME_TYPE.equals(canonicalName) + || BIG_DECIMAL.equals(canonicalName)) { return true; } return false; diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/idl/IDLGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java similarity index 94% rename from src/cn/bigcoder/plugin/objecthelper/generator/idl/IDLGenerator.java rename to src/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java index bfad7d2..6ab6a57 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/idl/IDLGenerator.java +++ b/src/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java @@ -3,6 +3,7 @@ import cn.bigcoder.plugin.objecthelper.common.util.IDLUtils; import cn.bigcoder.plugin.objecthelper.common.util.PsiTypeUtils; import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; +import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; import cn.bigcoder.plugin.objecthelper.generator.Generator; import com.intellij.psi.PsiArrayType; import com.intellij.psi.PsiClass; @@ -20,7 +21,7 @@ * @author: Jindong.Tian * @date: 2021-08-20 **/ -public class IDLGenerator implements Generator { +public class ThriftIDLGenerator implements Generator { private PsiClass psiClass; @@ -29,7 +30,7 @@ public class IDLGenerator implements Generator { */ private Set recursiveCache = Sets.newHashSet(); - private IDLGenerator(PsiClass psiClass) { + private ThriftIDLGenerator(PsiClass psiClass) { this.psiClass = psiClass; } @@ -54,7 +55,10 @@ private StringBuilder generateStructCode(PsiClass psiClass) { StringBuilder code = new StringBuilder(); for (PsiField allPsiField : allPsiFields) { code = processAssociateClass(allPsiField.getType(), code); - fields.add(processPsiField(allPsiField)); + String field = processPsiField(allPsiField); + if (StringUtils.isNotEmpty(field)) { + fields.add(field); + } } return code.append(generateStructCode(psiClass.getName(), fields)); } @@ -179,7 +183,7 @@ private String processType(PsiType psiType) { return null; } - public static IDLGenerator getInstance(PsiClass psiClass) { - return new IDLGenerator(psiClass); + public static ThriftIDLGenerator getInstance(PsiClass psiClass) { + return new ThriftIDLGenerator(psiClass); } } From b0e6d2469ee88054b1e9310c06b1722994d204db Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Fri, 26 Aug 2022 16:43:21 +0800 Subject: [PATCH 03/10] =?UTF-8?q?1.3.0=E7=89=88=E6=9C=AC=EF=BC=9A=20=201.?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E5=8F=AF=E9=85=8D=E7=BD=AE=E5=8C=96=EF=BC=8C?= =?UTF-8?q?=E5=8F=AF=E8=87=AA=E5=AE=9A=E4=B9=89=E5=BC=80=E5=90=AF/?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E6=8F=92=E4=BB=B6=E9=83=A8=E5=88=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=20=202.=E6=96=B0=E5=A2=9E=E2=80=9CClass=20To=20XML?= =?UTF-8?q?=E2=80=9D=E5=8A=9F=E8=83=BD=20=203.=E6=BA=90=E7=A0=81=E7=94=B1?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E6=A8=A1=E6=9D=BF=E9=A1=B9=E7=9B=AE=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E8=87=B3gradle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + README.md | 32 ++- build.gradle | 30 +++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 185 ++++++++++++++++++ gradlew.bat | 89 +++++++++ object-helper.jar | Bin 31824 -> 0 bytes settings.gradle | 2 + .../generator/json/ClassJsonGenerator.java | 105 ---------- .../action/ClassToFormatJsonAction.java | 0 .../action/ClassToJsonAction.java | 7 +- .../action/ClassToThriftIDLAction.java | 9 +- .../objecthelper/action/ClassToXMLAction.java | 48 +++++ .../action/ObjectCopyMethodAction.java | 13 +- .../common/constant/IDLTypeName.java | 0 .../common/constant/JavaClassName.java | 0 .../common/constant/JavaKeyWord.java | 0 .../objecthelper/common/enums/JavaModify.java | 0 .../objecthelper/common/util/IDLUtils.java | 2 +- .../common/util/NotificationUtils.java | 0 .../common/util/PsiTypeUtils.java | 0 .../objecthelper/common/util/PsiUtils.java | 10 +- .../objecthelper/common/util/StringUtils.java | 0 .../objecthelper/common/util/XMLUtils.java | 62 ++++++ .../config/ObjectHelperConfigurable.java | 53 +++++ .../config/PluginConfigModel.java | 71 +++++++ .../config/PluginConfigState.java | 36 ++++ .../objecthelper/config/package-info.java | 7 + .../AbstractDataObjectGenerator.java | 88 +++++++++ .../generator}/AbstractMethodGenerator.java | 4 +- .../objecthelper/generator/Generator.java | 0 .../generator/idl/ThriftIDLGenerator.java | 0 .../generator/json/ClassJsonGenerator.java | 38 ++++ .../method/ObjectCopyMethodGenerator.java | 8 +- .../generator/xml/ClassXMLGenerator.java | 34 ++++ .../plugin/objecthelper/ui/ConfigPage.form | 108 ++++++++++ .../plugin/objecthelper/ui/ConfigPage.java | 58 ++++++ .../main/resources}/META-INF/plugin.xml | 34 ++-- .../main/resources}/META-INF/pluginIcon.svg | 0 40 files changed, 1001 insertions(+), 139 deletions(-) create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat delete mode 100644 object-helper.jar create mode 100644 settings.gradle delete mode 100644 src/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/action/ClassToFormatJsonAction.java (100%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java (83%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java (78%) create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java (76%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/common/constant/IDLTypeName.java (100%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java (100%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/common/constant/JavaKeyWord.java (100%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/common/enums/JavaModify.java (100%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java (100%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java (100%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java (100%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java (95%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/common/util/StringUtils.java (100%) create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/common/util/XMLUtils.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigState.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/config/package-info.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java rename src/{cn/bigcoder/plugin/objecthelper/generator/method => main/java/cn/bigcoder/plugin/objecthelper/generator}/AbstractMethodGenerator.java (95%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/generator/Generator.java (100%) rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java (100%) create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java rename src/{ => main/java}/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java (93%) create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/generator/xml/ClassXMLGenerator.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java rename {resources => src/main/resources}/META-INF/plugin.xml (54%) rename {resources => src/main/resources}/META-INF/pluginIcon.svg (100%) diff --git a/.gitignore b/.gitignore index 154f8bc..15a3152 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ *.class .idea/ out/ +.gradle/ +build/ diff --git a/README.md b/README.md index 6da371d..fbea56a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # object-helper-plugin -![](https://img.shields.io/badge/version-v1.2.1-blue) + +![](https://img.shields.io/badge/version-v1.3.0-blue) ![](https://img.shields.io/badge/license-Apache%202-red) -![](https://img.shields.io/badge/size-36.54%20kB-yellowgreen) -![](https://img.shields.io/badge/download-1.1k-green) +![](https://img.shields.io/badge/size-64%20kB-yellowgreen) +![](https://img.shields.io/badge/download-1.7k-green) -插件地址:[https://plugins.jetbrains.com/plugin/15788-objecthelper](https://plugins.jetbrains.com/plugin/15788-objecthelper) +插件地址:[object-helper-plugin](https://plugins.jetbrains.com/plugin/15788-objecthelper) JetBrains Intellij IDEA ObjectHelper插件,包含以下功能: @@ -12,20 +13,33 @@ JetBrains Intellij IDEA ObjectHelper插件,包含以下功能: ![](https://image.bigcoder.cn/7fce876e-fa94-4780-bb14-584068c35963.gif) + 对象拷贝的快捷键默认是 `Alt+Insert`,如果该快捷键无效,可以在settings->keymap中搜索“Generate”关键字查看具体的快捷键: + + ![](https://image.bigcoder.cn/20220916173117.png) + - Java类转JSON - + ![](https://image.bigcoder.cn/20210227223302.gif) - + - Java类转Thrift IDL ![](https://image.bigcoder.cn/6eee7a02-8e4e-4f11-9b8c-81d661a920c5.gif) - + +- Java类转XML + ![](https://image.bigcoder.cn/20220916170144.gif) + +- 插件配置 + +File->settings->Tools->Object Helper 即可进入插件的配置页面 + +![](https://image.bigcoder.cn/20220916173227.png) + ## 未来功能支持计划 object-helper插件未来功能支持计划: - [x] Class转IDL(Class To Thrift IDL) -- [ ] Class转XML(Class To XML) +- [x] Class转XML(Class To XML) - [ ] JSON转Class(JSON TO Class) - [ ] All Setter - [ ] 菜单分组显示 -- [ ] 个性化配置 \ No newline at end of file +- [x] 个性化配置 \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..f419e84 --- /dev/null +++ b/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'org.jetbrains.intellij' version '1.8.0' + id 'java' +} + +group 'cn.bigcoder.plugin' +version '1.3.0' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' +} + +// See https://github.com/JetBrains/gradle-intellij-plugin/ +intellij { + version = '2021.2.1' + plugins = ['com.intellij.java'] +} +patchPluginXml { + changeNotes = """ + Add change notes here.
    + most HTML tags may be used""" +} +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..69a9715 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..744e882 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..ac1b06f --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/object-helper.jar b/object-helper.jar deleted file mode 100644 index d9beb5e35ddc8c1f85956455ad334d32b4aa82cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31824 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 IRu8}a4_qbgWdHyG diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..66ce9df --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'object-helper-plugin' + diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java deleted file mode 100644 index fc7bb62..0000000 --- a/src/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java +++ /dev/null @@ -1,105 +0,0 @@ -package cn.bigcoder.plugin.objecthelper.generator.json; - -import cn.bigcoder.plugin.objecthelper.common.util.PsiTypeUtils; -import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; -import cn.bigcoder.plugin.objecthelper.generator.Generator; -import com.google.common.collect.Maps; -import com.google.gson.Gson; -import com.intellij.psi.PsiArrayType; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiField; -import com.intellij.psi.PsiType; -import com.intellij.psi.impl.source.PsiClassReferenceType; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.compress.utils.Lists; -import org.apache.commons.compress.utils.Sets; -import org.apache.commons.lang.ArrayUtils; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * @author: Jindong.Tian - * @date: 2021-02-11 - **/ -public class ClassJsonGenerator implements Generator { - - private PsiClass psiClass; - - /** - * 保存已经解析过的自定义类型名称,防止出现递归嵌套的情况 - */ - private Set recursiveCache = Sets.newHashSet(); - - private Gson gson; - - private ClassJsonGenerator(PsiClass psiClass, Gson gson) { - this.psiClass = psiClass; - this.gson = gson; - } - - /** - * 获取ClassJsonGenerator实例 - * - * @param psiClass JSON生成的目标类 - * @param gson Gson对象 - * @return - */ - public static ClassJsonGenerator getInstance(PsiClass psiClass, Gson gson) { - return new ClassJsonGenerator(psiClass, gson); - } - - @Override - public String generate() { - Map jsonMap = processFields(psiClass); - return gson.toJson(jsonMap); - } - - private Map processFields(PsiClass psiClass) { - Map result = Maps.newLinkedHashMap(); - // 当前类所有字段 - List allPsiFields = PsiUtils.getAllPsiFields(psiClass); - if (CollectionUtils.isEmpty(allPsiFields)) { - return result; - } - for (PsiField psiField : allPsiFields) { - result.put(psiField.getName(), processField(psiField.getType())); - } - return result; - } - - private Object processField(PsiType psiType) { - Object defaultValue = null; - if (PsiTypeUtils.isDataType(psiType)) { - //如果是数据类型 - defaultValue = PsiTypeUtils.getDataTypeDefaultValue(psiType.getCanonicalText()); - } else if (PsiTypeUtils.isArrayType(psiType)) { - //如果是数组类型 - List list = Lists.newArrayList(); - PsiClass arrayContentClass = PsiUtils.getPsiClass(((PsiArrayType) psiType).getComponentType(), psiClass.getProject()); - list.add(PsiTypeUtils.getDataTypeDefaultValue(arrayContentClass.getQualifiedName())); - defaultValue = list; - } else if (PsiTypeUtils.isCollectionType(psiType)) { - defaultValue = Lists.newArrayList(); - //如果是集合类型 - PsiType[] parameters = ((PsiClassReferenceType) psiType).getParameters(); - if (ArrayUtils.isEmpty(parameters)) { - return defaultValue; - } - //获取泛型 - PsiType genericType = parameters[0]; - ((List) defaultValue).add(processField(genericType)); - } else if (!PsiTypeUtils.isJavaOfficialType(psiType)) { - //如果是自定义类型 - if (recursiveCache.contains(psiType.getCanonicalText())) { - //出现递归嵌套 - return null; - } - recursiveCache.add(psiType.getCanonicalText()); - //如果是自定义类 - defaultValue = processFields(PsiUtils.getPsiClass(psiType, psiClass.getProject())); - } - return defaultValue; - } -} \ No newline at end of file diff --git a/src/cn/bigcoder/plugin/objecthelper/action/ClassToFormatJsonAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToFormatJsonAction.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/action/ClassToFormatJsonAction.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToFormatJsonAction.java diff --git a/src/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java similarity index 83% rename from src/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java index 7619892..1183e6f 100644 --- a/src/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java @@ -1,6 +1,7 @@ package cn.bigcoder.plugin.objecthelper.action; import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; +import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.generator.Generator; import cn.bigcoder.plugin.objecthelper.generator.json.ClassJsonGenerator; import com.google.gson.Gson; @@ -31,8 +32,10 @@ public void actionPerformed(AnActionEvent anAction) { @Override public void update(@NotNull AnActionEvent anActionEvent) { - // 如果当前光标不在方法中,则不显示ConvertToJson组件 - if (getOperatePsiClass(anActionEvent) == null) { + if (!PluginConfigState.getInstance().isJsonSwitch()) { + setActionInvisible(anActionEvent); + } else if (getOperatePsiClass(anActionEvent) == null) { + // 如果当前光标不在类名上,则不显示ConvertToJson组件 setActionInvisible(anActionEvent); } super.update(anActionEvent); diff --git a/src/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java similarity index 78% rename from src/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java index 95a7e61..6af3f62 100644 --- a/src/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java @@ -1,6 +1,7 @@ package cn.bigcoder.plugin.objecthelper.action; import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; +import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.generator.idl.ThriftIDLGenerator; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -26,13 +27,15 @@ public void actionPerformed(@NotNull AnActionEvent anActionEvent) { } String idl = ThriftIDLGenerator.getInstance(psiClass).generate(); CopyPasteManager.getInstance().setContents(new StringSelection(idl)); - NotificationUtils.notifyInfo(anActionEvent.getProject(), "IDL代码成功置入剪贴板:
    " + idl); + NotificationUtils.notifyInfo(anActionEvent.getProject(), "Thrift IDL代码成功置入剪贴板:
    " + idl); } @Override public void update(@NotNull AnActionEvent anActionEvent) { - // 如果当前光标不在方法中,则不显示ConvertToJson组件 - if (getOperatePsiClass(anActionEvent) == null) { + if (!PluginConfigState.getInstance().isThriftSwitch()) { + setActionInvisible(anActionEvent); + } else if (getOperatePsiClass(anActionEvent) == null) { + // 如果当前光标不在类名上,则不显示ConvertToJson组件 setActionInvisible(anActionEvent); } super.update(anActionEvent); diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java new file mode 100644 index 0000000..5a38a49 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java @@ -0,0 +1,48 @@ +package cn.bigcoder.plugin.objecthelper.action; + +import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; +import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; +import cn.bigcoder.plugin.objecthelper.generator.Generator; +import cn.bigcoder.plugin.objecthelper.generator.json.ClassJsonGenerator; +import cn.bigcoder.plugin.objecthelper.generator.xml.ClassXMLGenerator; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.ide.CopyPasteManager; +import com.intellij.psi.PsiClass; +import org.jetbrains.annotations.NotNull; + +import java.awt.datatransfer.StringSelection; + +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.setActionInvisible; + +public class ClassToXMLAction extends AnAction { + + @Override + public void actionPerformed(AnActionEvent anAction) { + PsiClass psiClass = getOperatePsiClass(anAction); + if (psiClass == null) { + return; + } + String json = getGenerator(psiClass).generate(); + CopyPasteManager.getInstance().setContents(new StringSelection(json)); + NotificationUtils.notifyInfo(anAction.getProject(), "XML字符串成功置入剪贴板:
    " + json); + } + + @Override + public void update(@NotNull AnActionEvent anActionEvent) { + if (!PluginConfigState.getInstance().isXmlSwitch()) { + setActionInvisible(anActionEvent); + } else if (getOperatePsiClass(anActionEvent) == null) { + // 如果当前光标不在类名上,则不显示ConvertToJson组件 + setActionInvisible(anActionEvent); + } + super.update(anActionEvent); + } + + protected Generator getGenerator(PsiClass psiClass) { + return ClassXMLGenerator.getInstance(psiClass); + } +} diff --git a/src/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java similarity index 76% rename from src/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java index 2ab5a9d..9cc5808 100644 --- a/src/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java @@ -2,6 +2,7 @@ import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; +import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.generator.Generator; import cn.bigcoder.plugin.objecthelper.generator.method.ObjectCopyMethodGenerator; import com.intellij.openapi.actionSystem.AnAction; @@ -13,6 +14,8 @@ import org.jetbrains.annotations.NotNull; import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.VOID; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.setActionInvisible; public class ObjectCopyMethodAction extends AnAction { @@ -25,8 +28,10 @@ public void actionPerformed(AnActionEvent anActionEvent) { @Override public void update(@NotNull AnActionEvent anActionEvent) { - // 如果当前光标不在方法中,则不显示Object Copy组件 - if (!check(PsiUtils.getCursorPsiMethod(anActionEvent))) { + if (!PluginConfigState.getInstance().isObjectCopySwitch()) { + PsiUtils.setActionDisabled(anActionEvent); + } else if (!check(PsiUtils.getCursorPsiMethod(anActionEvent))) { + // 如果当前光标不在方法中,则不显示Object Copy组件 PsiUtils.setActionDisabled(anActionEvent); } super.update(anActionEvent); @@ -59,8 +64,8 @@ private void generateO2O(PsiMethod psiMethod) { */ private boolean check(PsiMethod psiMethod) { if (psiMethod == null - || PsiUtils.getPsiParameters(psiMethod).size() == 0 - || VOID.equals(PsiUtils.getMethodReturnClassName(psiMethod))) { + || PsiUtils.getPsiParameters(psiMethod).size() == 0 + || VOID.equals(PsiUtils.getMethodReturnClassName(psiMethod))) { return false; } return true; diff --git a/src/cn/bigcoder/plugin/objecthelper/common/constant/IDLTypeName.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/IDLTypeName.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/common/constant/IDLTypeName.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/IDLTypeName.java diff --git a/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java diff --git a/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaKeyWord.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/JavaKeyWord.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/common/constant/JavaKeyWord.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/JavaKeyWord.java diff --git a/src/cn/bigcoder/plugin/objecthelper/common/enums/JavaModify.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/JavaModify.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/common/enums/JavaModify.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/JavaModify.java diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java index a519651..6e1f698 100644 --- a/src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java @@ -1,7 +1,7 @@ package cn.bigcoder.plugin.objecthelper.common.util; -import static cn.bigcoder.plugin.objecthelper.common.constant.JavaClassName.*; import static cn.bigcoder.plugin.objecthelper.common.constant.IDLTypeName.*; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaClassName.*; /** * @author: Jindong.Tian diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java similarity index 95% rename from src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java index 474adbe..a727e5c 100644 --- a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java @@ -7,7 +7,15 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.psi.*; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifierList; +import com.intellij.psi.PsiParameter; +import com.intellij.psi.PsiType; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import org.apache.commons.compress.utils.Lists; diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/StringUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/StringUtils.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/common/util/StringUtils.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/util/StringUtils.java diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/XMLUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/XMLUtils.java new file mode 100644 index 0000000..d1ec63f --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/XMLUtils.java @@ -0,0 +1,62 @@ +package cn.bigcoder.plugin.objecthelper.common.util; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.IOException; +import java.io.StringWriter; +import java.util.Map; + +/** + * @author: Jindong.Tian + * @date: 2022-08-26 + **/ +public class XMLUtils { + /** + * 将Map转换为XML格式的字符串 + * + * @param data Map类型数据 + * @return XML格式的字符串 + * @throws Exception + */ + public static String mapToXml(Map data) { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + String output = null; //.replaceAll("\n|\r", ""); + try { + DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder(); + org.w3c.dom.Document document = documentBuilder.newDocument(); + org.w3c.dom.Element root = document.createElement("xml"); + document.appendChild(root); + for (String key: data.keySet()) { + String value = data.get(key).toString(); + value = value.trim(); + org.w3c.dom.Element filed = document.createElement(key); + filed.appendChild(document.createTextNode(value)); + root.appendChild(filed); + } + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + DOMSource source = new DOMSource(document); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + transformer.transform(source, result); + output = writer.getBuffer().toString(); + writer.close(); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } catch (TransformerException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return output; + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java b/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java new file mode 100644 index 0000000..7d2b187 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java @@ -0,0 +1,53 @@ +package cn.bigcoder.plugin.objecthelper.config; + +import cn.bigcoder.plugin.objecthelper.ui.ConfigPage; +import com.intellij.openapi.options.SearchableConfigurable; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * 该类是配置页面的入口 + * https://plugins.jetbrains.com/docs/intellij/settings-tutorial.html + * + * @author: Jindong.Tian + * @date: 2022-08-31 + **/ +public class ObjectHelperConfigurable implements SearchableConfigurable { + private ConfigPage configPage = new ConfigPage(); + + @Override + public @NotNull String getId() { + return "cn.bigcoder.plugin.objecthelper.config.SettingFactory"; + } + + @Override + public @Nls(capitalization = Nls.Capitalization.Title) String getDisplayName() { + return "Object Helper"; + } + + @Override + public @Nullable JComponent createComponent() { + return configPage.getMainPanel(); + } + + @Override + public boolean isModified() { + PluginConfigModel instance = PluginConfigState.getInstance(); + PluginConfigModel currentConfigModel = configPage.getCurrentConfigModel(); + return !instance.equals(currentConfigModel); + } + + @Override + public void apply() { + PluginConfigModel instance = PluginConfigState.getInstance(); + PluginConfigModel currentConfigModel = configPage.getCurrentConfigModel(); + instance.setJsonSwitch(currentConfigModel.isJsonSwitch()); + instance.setThriftSwitch(currentConfigModel.isThriftSwitch()); + instance.setXmlSwitch(currentConfigModel.isXmlSwitch()); + instance.setObjectCopySwitch(currentConfigModel.isObjectCopySwitch()); + } + +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java new file mode 100644 index 0000000..ef25e8e --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java @@ -0,0 +1,71 @@ +package cn.bigcoder.plugin.objecthelper.config; + +import java.util.Objects; + +/** + * @author: Jindong.Tian + * @date: 2022-08-31 + **/ +public class PluginConfigModel { + /** + * 是否开启 Class To Json 功能,默认为开启状态 + */ + private boolean jsonSwitch = true; + /** + * 是否开启 Class To Thrift IDL 功能,默认为开启状态 + */ + private boolean thriftSwitch = true; + /** + * 是否开启 Class To XML 功能,默认为开启状态 + */ + private boolean xmlSwitch = true; + /** + * 是否开启 Object Copy Method 功能,默认为开启状态 + */ + private boolean objectCopySwitch = true; + + public boolean isJsonSwitch() { + return jsonSwitch; + } + + public void setJsonSwitch(boolean jsonSwitch) { + this.jsonSwitch = jsonSwitch; + } + + public boolean isThriftSwitch() { + return thriftSwitch; + } + + public void setThriftSwitch(boolean thriftSwitch) { + this.thriftSwitch = thriftSwitch; + } + + public boolean isXmlSwitch() { + return xmlSwitch; + } + + public void setXmlSwitch(boolean xmlSwitch) { + this.xmlSwitch = xmlSwitch; + } + + public boolean isObjectCopySwitch() { + return objectCopySwitch; + } + + public void setObjectCopySwitch(boolean objectCopySwitch) { + this.objectCopySwitch = objectCopySwitch; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PluginConfigModel that = (PluginConfigModel) o; + return jsonSwitch == that.jsonSwitch && thriftSwitch == that.thriftSwitch && xmlSwitch == that.xmlSwitch && objectCopySwitch == that.objectCopySwitch; + } + + @Override + public int hashCode() { + return Objects.hash(jsonSwitch, thriftSwitch, xmlSwitch, objectCopySwitch); + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigState.java b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigState.java new file mode 100644 index 0000000..3f47118 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigState.java @@ -0,0 +1,36 @@ +package cn.bigcoder.plugin.objecthelper.config; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.util.xmlb.XmlSerializerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * 该类用于持久化配置对象,每个想要在IDE重启时保持状态的组件都应该实现 PersistentStateComponent 接口 + * + * @author: Jindong.Tian + * @date: 2022-08-31 + **/ +@State( + name = "cn.bigcoder.plugin.objecthelper.config.PluginConfigState", + storages = @Storage("object-helper.xml") +) +public class PluginConfigState implements PersistentStateComponent { + + @Override + public @Nullable PluginConfigModel getState() { + return new PluginConfigModel(); + } + + @Override + public void loadState(@NotNull PluginConfigModel state) { + XmlSerializerUtil.copyBean(state, this); + } + + public static PluginConfigModel getInstance() { + return ApplicationManager.getApplication().getService(PluginConfigModel.class); + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/config/package-info.java b/src/main/java/cn/bigcoder/plugin/objecthelper/config/package-info.java new file mode 100644 index 0000000..4086cd7 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/package-info.java @@ -0,0 +1,7 @@ +package cn.bigcoder.plugin.objecthelper.config; + +/** + * 该包主要用于插件配置化实现,用户可以根据需求,配置部分功能的 隐藏/展示 + *

    + * 官方文档:https://plugins.jetbrains.com/docs/intellij/settings-tutorial.html + */ \ No newline at end of file diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java new file mode 100644 index 0000000..e7d3384 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java @@ -0,0 +1,88 @@ +package cn.bigcoder.plugin.objecthelper.generator; + +import cn.bigcoder.plugin.objecthelper.common.util.PsiTypeUtils; +import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; +import com.google.common.collect.Maps; +import com.intellij.psi.PsiArrayType; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiType; +import com.intellij.psi.impl.source.PsiClassReferenceType; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.compress.utils.Sets; +import org.apache.commons.lang.ArrayUtils; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author: Jindong.Tian + * @date: 2022-08-26 + **/ +public abstract class AbstractDataObjectGenerator implements Generator { + + private PsiClass psiClass; + + public AbstractDataObjectGenerator(PsiClass psiClass) { + this.psiClass = psiClass; + } + + /** + * 保存已经解析过的自定义类型名称,防止出现递归嵌套的情况 + */ + private Set recursiveCache = Sets.newHashSet(); + + protected Map processFields() { + return processFields(psiClass); + } + + protected Map processFields(PsiClass psiClass) { + Map result = Maps.newLinkedHashMap(); + // 当前类所有字段 + List allPsiFields = PsiUtils.getAllPsiFields(psiClass); + if (CollectionUtils.isEmpty(allPsiFields)) { + return result; + } + for (PsiField psiField : allPsiFields) { + result.put(psiField.getName(), processField(psiField.getType())); + } + return result; + } + + private Object processField(PsiType psiType) { + Object defaultValue = null; + if (PsiTypeUtils.isDataType(psiType)) { + //如果是数据类型 + defaultValue = PsiTypeUtils.getDataTypeDefaultValue(psiType.getCanonicalText()); + } else if (PsiTypeUtils.isArrayType(psiType)) { + //如果是数组类型 + List list = Lists.newArrayList(); + PsiClass arrayContentClass = PsiUtils.getPsiClass(((PsiArrayType) psiType).getComponentType(), + psiClass.getProject()); + list.add(PsiTypeUtils.getDataTypeDefaultValue(arrayContentClass.getQualifiedName())); + defaultValue = list; + } else if (PsiTypeUtils.isCollectionType(psiType)) { + defaultValue = Lists.newArrayList(); + //如果是集合类型 + PsiType[] parameters = ((PsiClassReferenceType) psiType).getParameters(); + if (ArrayUtils.isEmpty(parameters)) { + return defaultValue; + } + //获取泛型 + PsiType genericType = parameters[0]; + ((List) defaultValue).add(processField(genericType)); + } else if (!PsiTypeUtils.isJavaOfficialType(psiType)) { + //如果是自定义类型 + if (recursiveCache.contains(psiType.getCanonicalText())) { + //出现递归嵌套 + return null; + } + recursiveCache.add(psiType.getCanonicalText()); + //如果是自定义类 + defaultValue = processFields(PsiUtils.getPsiClass(psiType, psiClass.getProject())); + } + return defaultValue; + } +} diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractMethodGenerator.java similarity index 95% rename from src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractMethodGenerator.java index a3e08c8..abb3ad1 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractMethodGenerator.java @@ -1,4 +1,4 @@ -package cn.bigcoder.plugin.objecthelper.generator.method; +package cn.bigcoder.plugin.objecthelper.generator; import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; @@ -49,7 +49,7 @@ protected StringBuilder generateMethodFirstLine() { * 生成方法体 * @return */ - abstract String generateMethodBody(); + protected abstract String generateMethodBody(); /** * 检查是否具备生成方法所需要的环境 diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/Generator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/Generator.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/generator/Generator.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/generator/Generator.java diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java similarity index 100% rename from src/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java new file mode 100644 index 0000000..701f494 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java @@ -0,0 +1,38 @@ +package cn.bigcoder.plugin.objecthelper.generator.json; + +import cn.bigcoder.plugin.objecthelper.generator.AbstractDataObjectGenerator; +import com.google.gson.Gson; +import com.intellij.psi.PsiClass; + +import java.util.Map; + +/** + * @author: Jindong.Tian + * @date: 2021-02-11 + **/ +public class ClassJsonGenerator extends AbstractDataObjectGenerator { + + private Gson gson; + + private ClassJsonGenerator(PsiClass psiClass, Gson gson) { + super(psiClass); + this.gson = gson; + } + + /** + * 获取ClassJsonGenerator实例 + * + * @param psiClass JSON生成的目标类 + * @param gson Gson对象 + * @return + */ + public static ClassJsonGenerator getInstance(PsiClass psiClass, Gson gson) { + return new ClassJsonGenerator(psiClass, gson); + } + + @Override + public String generate() { + Map jsonMap = processFields(); + return gson.toJson(jsonMap); + } +} \ No newline at end of file diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java similarity index 93% rename from src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java index 921e9d7..1203fd6 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java @@ -2,7 +2,13 @@ import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; -import com.intellij.psi.*; +import cn.bigcoder.plugin.objecthelper.generator.AbstractMethodGenerator; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiModifierList; +import com.intellij.psi.PsiParameter; import org.jetbrains.annotations.NotNull; import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.*; diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/xml/ClassXMLGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/xml/ClassXMLGenerator.java new file mode 100644 index 0000000..abcdd28 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/xml/ClassXMLGenerator.java @@ -0,0 +1,34 @@ +package cn.bigcoder.plugin.objecthelper.generator.xml; + +import cn.bigcoder.plugin.objecthelper.common.util.XMLUtils; +import cn.bigcoder.plugin.objecthelper.generator.AbstractDataObjectGenerator; +import com.intellij.psi.PsiClass; + +import java.util.Map; + +/** + * @author: Jindong.Tian + * @date: 2021-02-11 + **/ +public class ClassXMLGenerator extends AbstractDataObjectGenerator { + + private ClassXMLGenerator(PsiClass psiClass) { + super(psiClass); + } + + /** + * 获取ClassJsonGenerator实例 + * + * @param psiClass JSON生成的目标类 + * @return + */ + public static ClassXMLGenerator getInstance(PsiClass psiClass) { + return new ClassXMLGenerator(psiClass); + } + + @Override + public String generate() { + Map jsonMap = processFields(); + return XMLUtils.mapToXml(jsonMap); + } +} \ No newline at end of file diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form new file mode 100644 index 0000000..f4c3584 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form @@ -0,0 +1,108 @@ + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java new file mode 100644 index 0000000..8ccee25 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java @@ -0,0 +1,58 @@ +package cn.bigcoder.plugin.objecthelper.ui; + +import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; +import cn.bigcoder.plugin.objecthelper.config.PluginConfigModel; + +import javax.swing.*; + +/** + * @author: Jindong.Tian + * @date: 2022-08-26 + **/ +public class ConfigPage { + + private static final String OPEN_STATUS = "open"; + + private JPanel mainPanel; + private JComboBox classToJsonSwitch; + private JComboBox classToThriftSwitch; + private JComboBox classToXmlSwitch; + private JComboBox objectCopyMethodSwitch; + + public JPanel getMainPanel() { + initField(); + return mainPanel; + } + + /** + * 根据持久化配置,初始化面板 + */ + public void initField() { + PluginConfigModel instance = PluginConfigState.getInstance(); + this.classToJsonSwitch.setSelectedItem(convertComboBoxItem(instance.isJsonSwitch())); + this.classToThriftSwitch.setSelectedItem(convertComboBoxItem(instance.isThriftSwitch())); + this.classToXmlSwitch.setSelectedItem(convertComboBoxItem(instance.isXmlSwitch())); + this.objectCopyMethodSwitch.setSelectedItem(convertComboBoxItem(instance.isObjectCopySwitch())); + } + + /** + * 获取页面当前的配置信息 + * + * @return + */ + public PluginConfigModel getCurrentConfigModel() { + PluginConfigModel pluginConfigModel = new PluginConfigModel(); + pluginConfigModel.setJsonSwitch(this.classToJsonSwitch.getSelectedItem().equals(OPEN_STATUS)); + pluginConfigModel.setThriftSwitch(this.classToThriftSwitch.getSelectedItem().equals(OPEN_STATUS)); + pluginConfigModel.setXmlSwitch(this.classToXmlSwitch.getSelectedItem().equals(OPEN_STATUS)); + pluginConfigModel.setObjectCopySwitch(this.objectCopyMethodSwitch.getSelectedItem().equals(OPEN_STATUS)); + return pluginConfigModel; + } + + private static String convertComboBoxItem(boolean switchTag) { + if (switchTag) { + return "open"; + } + return "close"; + } +} diff --git a/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml similarity index 54% rename from resources/META-INF/plugin.xml rename to src/main/resources/META-INF/plugin.xml index 706c94e..9fcb614 100644 --- a/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -1,22 +1,24 @@ cn.bigcoder.plugin.objecthelper ObjectHelper - 1.2.1 + 1.3.0 HearingSmile GitHub -
  • Copy the object
  • - -
  • Class to JSON
  • - -
  • Class to IDL
  • - + This is a Java object toolset. Using document: GitHub +
  • Copy the object
  • + +
  • Class to JSON
  • + +
  • Class to Thrift IDL
  • + +
  • Class to XML
  • + ]]>
    Fix:rename "Class To IDL" to "Class To Thrift IDL" -
  • Fix bug:fix "Class To Thrift IDL" BigDecimal conversion exception
  • +
  • New feature:Added the ability to quickly convert Java classes to XML
  • +
  • New feature:Customize to enable specified functions
  • ]]>
    @@ -25,11 +27,16 @@ - + com.intellij.modules.java + + + @@ -48,6 +55,11 @@ + + +
    \ No newline at end of file diff --git a/resources/META-INF/pluginIcon.svg b/src/main/resources/META-INF/pluginIcon.svg similarity index 100% rename from resources/META-INF/pluginIcon.svg rename to src/main/resources/META-INF/pluginIcon.svg From 59e0ef0b5311db0e6dcf06dcbb997956ae23df6c Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 23 Dec 2023 10:52:17 +0800 Subject: [PATCH 04/10] =?UTF-8?q?1.3.1=E7=89=88=E6=9C=AC:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 提升插件兼容性,去除新版本客户端废弃API --- README.md | 25 +++++++++++++------ build.gradle | 13 ++++++---- .../action/ClassToJsonAction.java | 2 +- .../common/util/NotificationUtils.java | 5 ++-- .../common/util/PsiTypeUtils.java | 2 +- .../AbstractDataObjectGenerator.java | 4 +-- .../generator/idl/ThriftIDLGenerator.java | 2 +- src/main/resources/META-INF/plugin.xml | 11 +++++--- 8 files changed, 40 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index fbea56a..7e6b309 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,19 @@ # object-helper-plugin -![](https://img.shields.io/badge/version-v1.3.0-blue) -![](https://img.shields.io/badge/license-Apache%202-red) -![](https://img.shields.io/badge/size-64%20kB-yellowgreen) -![](https://img.shields.io/badge/download-1.7k-green) +
    + +
    +
    +
    + + + + +
    -插件地址:[object-helper-plugin](https://plugins.jetbrains.com/plugin/15788-objecthelper) +JetBrains Intellij IDEA ObjectHelper 插件旨在减少开发者重复低效的劳动,使开发者能够更专注于业务逻辑的开发。 -JetBrains Intellij IDEA ObjectHelper插件,包含以下功能: +该插件包含以下功能: - 对象拷贝 @@ -22,14 +28,16 @@ JetBrains Intellij IDEA ObjectHelper插件,包含以下功能: ![](https://image.bigcoder.cn/20210227223302.gif) - Java类转Thrift IDL + ![](https://image.bigcoder.cn/6eee7a02-8e4e-4f11-9b8c-81d661a920c5.gif) - Java类转XML + ![](https://image.bigcoder.cn/20220916170144.gif) - 插件配置 -File->settings->Tools->Object Helper 即可进入插件的配置页面 +File->Settings->Tools->Object Helper 即可进入插件的配置页面 ![](https://image.bigcoder.cn/20220916173227.png) @@ -39,7 +47,8 @@ object-helper插件未来功能支持计划: - [x] Class转IDL(Class To Thrift IDL) - [x] Class转XML(Class To XML) +- [x] 个性化配置 - [ ] JSON转Class(JSON TO Class) +- [ ] Class转Protobuf IDL(JSON TO Class) - [ ] All Setter - [ ] 菜单分组显示 -- [x] 个性化配置 \ No newline at end of file diff --git a/build.gradle b/build.gradle index f419e84..55b4ad7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,11 @@ plugins { - id 'org.jetbrains.intellij' version '1.8.0' + // https://github.com/JetBrains/gradle-intellij-plugin/blob/master/README.md + id 'org.jetbrains.intellij' version '1.16.1' id 'java' } group 'cn.bigcoder.plugin' -version '1.3.0' +version '1.3.1' repositories { mavenCentral() @@ -13,17 +14,19 @@ repositories { dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' + implementation 'org.apache.commons:commons-lang3:3.13.0' } // See https://github.com/JetBrains/gradle-intellij-plugin/ intellij { - version = '2021.2.1' + version = '2023.3.1' plugins = ['com.intellij.java'] } patchPluginXml { + sinceBuild = '211' changeNotes = """ - Add change notes here.
    - most HTML tags may be used""" + 1. fix feature:Resolve version compatibility issues and adapt new versions of the IDE + """ } test { useJUnitPlatform() diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java index 1183e6f..ed31287 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java @@ -27,7 +27,7 @@ public void actionPerformed(AnActionEvent anAction) { } String json = getGenerator(psiClass).generate(); CopyPasteManager.getInstance().setContents(new StringSelection(json)); - NotificationUtils.notifyInfo(anAction.getProject(), "JSON字符串成功置入剪贴板:
    " + json); + NotificationUtils.notifyInfo(anAction.getProject(), "JSON字符串成功置入剪贴板:
    " + json); } @Override diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java index 78b2453..f0b9d48 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java @@ -1,7 +1,7 @@ package cn.bigcoder.plugin.objecthelper.common.util; -import com.intellij.notification.NotificationDisplayType; import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationGroupManager; import com.intellij.notification.NotificationType; import com.intellij.openapi.project.Project; @@ -14,7 +14,8 @@ public class NotificationUtils { /** * 从2020.3版本方式,通知组改由Plugin.xml注册。详见:https://plugins.jetbrains.com/docs/intellij/notifications.html#top-level-notifications */ - private static final NotificationGroup NOTIFICATION_GROUP = new NotificationGroup("ObjectHelper Notification Group", NotificationDisplayType.BALLOON, true); + private static final NotificationGroup NOTIFICATION_GROUP = NotificationGroupManager.getInstance() + .getNotificationGroup("ObjectHelper Notification Group"); public static void notifyInfo(Project project, String content) { NOTIFICATION_GROUP.createNotification(content, NotificationType.INFORMATION).notify(project); diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java index 0f00f1a..c539a76 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java @@ -4,12 +4,12 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClassType; import com.intellij.psi.PsiType; -import org.apache.commons.lang.time.DateFormatUtils; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Date; +import org.apache.commons.lang3.time.DateFormatUtils; import static cn.bigcoder.plugin.objecthelper.common.constant.JavaClassName.*; diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java index e7d3384..d490bfe 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java @@ -11,11 +11,11 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.compress.utils.Lists; import org.apache.commons.compress.utils.Sets; -import org.apache.commons.lang.ArrayUtils; - import java.util.List; import java.util.Map; + import java.util.Set; +import org.apache.commons.lang3.ArrayUtils; /** * @author: Jindong.Tian diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java index 6ab6a57..2ea54f1 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java @@ -12,10 +12,10 @@ import com.intellij.psi.impl.source.PsiClassReferenceType; import org.apache.commons.compress.utils.Lists; import org.apache.commons.compress.utils.Sets; -import org.apache.commons.lang.ArrayUtils; import java.util.List; import java.util.Set; +import org.apache.commons.lang3.ArrayUtils; /** * @author: Jindong.Tian diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 9fcb614..5c2e9be 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -1,7 +1,7 @@ cn.bigcoder.plugin.objecthelper ObjectHelper - 1.3.0 + 1.3.1 HearingSmile New feature:Added the ability to quickly convert Java classes to XML -
  • New feature:Customize to enable specified functions
  • +
  • fix feature:Resolve version compatibility issues and adapt new versions of the IDE
  • ]]>
    - + @@ -37,6 +36,10 @@ instance="cn.bigcoder.plugin.objecthelper.config.ObjectHelperConfigurable"/> + + From d9bdf35e622d6ec74f378eac61fa26fef6f30d39 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 24 Dec 2023 17:22:05 +0800 Subject: [PATCH 05/10] =?UTF-8?q?1.3.2=E7=89=88=E6=9C=AC=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 优化Object Copy Method 功能,新增生成模式配置,以及在字段有差异时以注释的形式生成代码 2. 修复 Class To XML 功能在复杂类结构时生成XML不正确的问题 3. 修复 Class To Thrift-IDL 功能,在一些场景下的NPE问题 --- README.md | 24 +++-- build.gradle | 9 +- .../action/AbstractClassAnAction.java | 28 ++++++ .../action/ClassToJsonAction.java | 17 +--- .../action/ClassToThriftIDLAction.java | 16 +--- .../objecthelper/action/ClassToXMLAction.java | 28 ++---- .../action/ObjectCopyMethodAction.java | 20 ++-- .../objecthelper/common/enums/CommonEnum.java | 11 +++ .../common/enums/FieldGenerateModeEnum.java | 34 +++++++ .../common/enums/FunctionSwitchEnum.java | 32 +++++++ .../{JavaModify.java => JavaModifyEnum.java} | 8 +- .../common/enums/WhetherEnum.java | 32 +++++++ .../objecthelper/common/util/PsiUtils.java | 44 ++++++--- .../objecthelper/common/util/XMLUtils.java | 84 +++++++---------- .../config/ObjectHelperConfigurable.java | 10 +- .../config/PluginConfigModel.java | 71 ++++++++++---- .../generator/AbstractMethodGenerator.java | 5 + .../generator/idl/ThriftIDLGenerator.java | 3 + .../method/ObjectCopyMethodGenerator.java | 43 +++++++-- .../plugin/objecthelper/ui/ConfigPage.form | 92 +++++++++++++++++-- .../plugin/objecthelper/ui/ConfigPage.java | 55 +++++++---- src/main/resources/META-INF/plugin.xml | 6 +- 22 files changed, 486 insertions(+), 186 deletions(-) create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/action/AbstractClassAnAction.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/CommonEnum.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FieldGenerateModeEnum.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FunctionSwitchEnum.java rename src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/{JavaModify.java => JavaModifyEnum.java} (77%) create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/WhetherEnum.java diff --git a/README.md b/README.md index 7e6b309..8d6430e 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@
    - + - +
    @@ -25,7 +25,7 @@ JetBrains Intellij IDEA ObjectHelper 插件旨在减少开发者重复低效的 - Java类转JSON - ![](https://image.bigcoder.cn/20210227223302.gif) + ![](https://image.bigcoder.cn/20231224171155.gif) - Java类转Thrift IDL @@ -33,22 +33,28 @@ JetBrains Intellij IDEA ObjectHelper 插件旨在减少开发者重复低效的 - Java类转XML - ![](https://image.bigcoder.cn/20220916170144.gif) + ![](https://image.bigcoder.cn/20231224171113.gif) - 插件配置 File->Settings->Tools->Object Helper 即可进入插件的配置页面 -![](https://image.bigcoder.cn/20220916173227.png) +![](https://image.bigcoder.cn/20231224170305.png) + +- `generate field mode = target` 代表以方法返回类型的字段为基础生成对象拷贝; +`generate field mode = source` 代表以方法入参类型的字段为基础生成对象拷贝。 + +- `non-existent field generate annotation = yes` 代表当目标字段,在源对象中不存在时,是否以注释的形式生成代码,如果为 `no`,则代表不生成这一个字段拷贝代码。 ## 未来功能支持计划 object-helper插件未来功能支持计划: -- [x] Class转IDL(Class To Thrift IDL) -- [x] Class转XML(Class To XML) +- [x] Class 转 IDL(Class To Thrift IDL) +- [x] Class 转 XML(Class To XML) - [x] 个性化配置 -- [ ] JSON转Class(JSON TO Class) -- [ ] Class转Protobuf IDL(JSON TO Class) +- [ ] Object Copy Method 功能支持 Lambda 表达式 +- [ ] JSON 转 Class(JSON TO Class) +- [ ] Class 转 Protobuf IDL(JSON TO Class) - [ ] All Setter - [ ] 菜单分组显示 diff --git a/build.gradle b/build.gradle index 55b4ad7..95e9899 100644 --- a/build.gradle +++ b/build.gradle @@ -5,16 +5,21 @@ plugins { } group 'cn.bigcoder.plugin' -version '1.3.1' +version '1.3.2' repositories { mavenCentral() } dependencies { + implementation 'org.apache.commons:commons-lang3:3.13.0' + / object 转 xml 依赖 开始/ + implementation 'com.fasterxml.jackson.core:jackson-core:2.13.3' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.3' + / object 转 xml 依赖 结束/ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' - implementation 'org.apache.commons:commons-lang3:3.13.0' } // See https://github.com/JetBrains/gradle-intellij-plugin/ diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/AbstractClassAnAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/AbstractClassAnAction.java new file mode 100644 index 0000000..365eeb0 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/AbstractClassAnAction.java @@ -0,0 +1,28 @@ +package cn.bigcoder.plugin.objecthelper.action; + +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.setActionInvisible; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; + +/** + * @author: Jindong.Tian + * @date: 2023-12-24 + **/ +public abstract class AbstractClassAnAction extends AnAction { + + /** + * 是否开启该功能 + * @return true代表开启该功能,false表示关闭该功能 + */ + public abstract boolean actionShow(AnActionEvent anActionEvent); + + @Override + public void update(@NotNull AnActionEvent anActionEvent) { + if (!actionShow(anActionEvent)) { + setActionInvisible(anActionEvent); + } + super.update(anActionEvent); + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java index ed31287..8e96e8c 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java @@ -1,23 +1,21 @@ package cn.bigcoder.plugin.objecthelper.action; +import cn.bigcoder.plugin.objecthelper.common.enums.FunctionSwitchEnum; import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.generator.Generator; import cn.bigcoder.plugin.objecthelper.generator.json.ClassJsonGenerator; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.psi.PsiClass; -import org.jetbrains.annotations.NotNull; import java.awt.datatransfer.StringSelection; import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.setActionInvisible; -public class ClassToJsonAction extends AnAction { +public class ClassToJsonAction extends AbstractClassAnAction { @Override public void actionPerformed(AnActionEvent anAction) { @@ -31,14 +29,9 @@ public void actionPerformed(AnActionEvent anAction) { } @Override - public void update(@NotNull AnActionEvent anActionEvent) { - if (!PluginConfigState.getInstance().isJsonSwitch()) { - setActionInvisible(anActionEvent); - } else if (getOperatePsiClass(anActionEvent) == null) { - // 如果当前光标不在类名上,则不显示ConvertToJson组件 - setActionInvisible(anActionEvent); - } - super.update(anActionEvent); + public boolean actionShow(AnActionEvent anActionEvent) { + return PluginConfigState.getInstance().getJsonSwitch() == FunctionSwitchEnum.OPEN + && getOperatePsiClass(anActionEvent) != null; } protected Generator getGenerator(PsiClass psiClass) { diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java index 6af3f62..d25b2bd 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java @@ -1,9 +1,9 @@ package cn.bigcoder.plugin.objecthelper.action; +import cn.bigcoder.plugin.objecthelper.common.enums.FunctionSwitchEnum; import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.generator.idl.ThriftIDLGenerator; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.psi.PsiClass; @@ -12,13 +12,12 @@ import java.awt.datatransfer.StringSelection; import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.setActionInvisible; /** * @author: Jindong.Tian * @date: 2021-08-21 **/ -public class ClassToThriftIDLAction extends AnAction { +public class ClassToThriftIDLAction extends AbstractClassAnAction { @Override public void actionPerformed(@NotNull AnActionEvent anActionEvent) { PsiClass psiClass = getOperatePsiClass(anActionEvent); @@ -31,13 +30,8 @@ public void actionPerformed(@NotNull AnActionEvent anActionEvent) { } @Override - public void update(@NotNull AnActionEvent anActionEvent) { - if (!PluginConfigState.getInstance().isThriftSwitch()) { - setActionInvisible(anActionEvent); - } else if (getOperatePsiClass(anActionEvent) == null) { - // 如果当前光标不在类名上,则不显示ConvertToJson组件 - setActionInvisible(anActionEvent); - } - super.update(anActionEvent); + public boolean actionShow(@NotNull AnActionEvent anActionEvent) { + return PluginConfigState.getInstance().getThriftSwitch() == FunctionSwitchEnum.OPEN + && getOperatePsiClass(anActionEvent) != null; } } \ No newline at end of file diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java index 5a38a49..82cb64c 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java @@ -1,24 +1,21 @@ package cn.bigcoder.plugin.objecthelper.action; +import cn.bigcoder.plugin.objecthelper.common.enums.FunctionSwitchEnum; import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.generator.Generator; -import cn.bigcoder.plugin.objecthelper.generator.json.ClassJsonGenerator; import cn.bigcoder.plugin.objecthelper.generator.xml.ClassXMLGenerator; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.psi.PsiClass; -import org.jetbrains.annotations.NotNull; +import groovy.json.StringEscapeUtils; import java.awt.datatransfer.StringSelection; +import org.jetbrains.annotations.NotNull; import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.setActionInvisible; -public class ClassToXMLAction extends AnAction { +public class ClassToXMLAction extends AbstractClassAnAction { @Override public void actionPerformed(AnActionEvent anAction) { @@ -26,20 +23,15 @@ public void actionPerformed(AnActionEvent anAction) { if (psiClass == null) { return; } - String json = getGenerator(psiClass).generate(); - CopyPasteManager.getInstance().setContents(new StringSelection(json)); - NotificationUtils.notifyInfo(anAction.getProject(), "XML字符串成功置入剪贴板:
    " + json); + String xmlStr = getGenerator(psiClass).generate(); + CopyPasteManager.getInstance().setContents(new StringSelection(xmlStr)); + NotificationUtils.notifyInfo(anAction.getProject(), "XML字符串成功置入剪贴板"); } @Override - public void update(@NotNull AnActionEvent anActionEvent) { - if (!PluginConfigState.getInstance().isXmlSwitch()) { - setActionInvisible(anActionEvent); - } else if (getOperatePsiClass(anActionEvent) == null) { - // 如果当前光标不在类名上,则不显示ConvertToJson组件 - setActionInvisible(anActionEvent); - } - super.update(anActionEvent); + public boolean actionShow(@NotNull AnActionEvent anActionEvent) { + return PluginConfigState.getInstance().getXmlSwitch() == FunctionSwitchEnum.OPEN + && getOperatePsiClass(anActionEvent) != null; } protected Generator getGenerator(PsiClass psiClass) { diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java index 9cc5808..8b8fe9e 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java @@ -1,23 +1,20 @@ package cn.bigcoder.plugin.objecthelper.action; +import cn.bigcoder.plugin.objecthelper.common.enums.FunctionSwitchEnum; import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.generator.Generator; import cn.bigcoder.plugin.objecthelper.generator.method.ObjectCopyMethodGenerator; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiElementFactory; import com.intellij.psi.PsiMethod; -import org.jetbrains.annotations.NotNull; import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.VOID; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.setActionInvisible; -public class ObjectCopyMethodAction extends AnAction { +public class ObjectCopyMethodAction extends AbstractClassAnAction { @Override public void actionPerformed(AnActionEvent anActionEvent) { @@ -27,14 +24,9 @@ public void actionPerformed(AnActionEvent anActionEvent) { } @Override - public void update(@NotNull AnActionEvent anActionEvent) { - if (!PluginConfigState.getInstance().isObjectCopySwitch()) { - PsiUtils.setActionDisabled(anActionEvent); - } else if (!check(PsiUtils.getCursorPsiMethod(anActionEvent))) { - // 如果当前光标不在方法中,则不显示Object Copy组件 - PsiUtils.setActionDisabled(anActionEvent); - } - super.update(anActionEvent); + public boolean actionShow(AnActionEvent anActionEvent) { + return PluginConfigState.getInstance().getObjectCopySwitch() == FunctionSwitchEnum.OPEN + && check(PsiUtils.getCursorPsiMethod(anActionEvent)); } private void generateO2O(PsiMethod psiMethod) { @@ -64,7 +56,7 @@ private void generateO2O(PsiMethod psiMethod) { */ private boolean check(PsiMethod psiMethod) { if (psiMethod == null - || PsiUtils.getPsiParameters(psiMethod).size() == 0 + || PsiUtils.getPsiParameters(psiMethod).isEmpty() || VOID.equals(PsiUtils.getMethodReturnClassName(psiMethod))) { return false; } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/CommonEnum.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/CommonEnum.java new file mode 100644 index 0000000..f470499 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/CommonEnum.java @@ -0,0 +1,11 @@ +package cn.bigcoder.plugin.objecthelper.common.enums; + +/** + * @author: Jindong.Tian + * @date: 2023-12-24 + * @description: + **/ +public interface CommonEnum { + + String getCode(); +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FieldGenerateModeEnum.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FieldGenerateModeEnum.java new file mode 100644 index 0000000..4ff4899 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FieldGenerateModeEnum.java @@ -0,0 +1,34 @@ +package cn.bigcoder.plugin.objecthelper.common.enums; + +/** + * @author: Jindong.Tian + * @date: 2023-12-24 + **/ +public enum FieldGenerateModeEnum implements CommonEnum { + SOURCE("source"), + TARGET("target"), + ; + private String code; + + FieldGenerateModeEnum(String code) { + this.code = code; + } + + + public static FieldGenerateModeEnum nameOf(String modify) { + if (modify == null) { + return null; + } + for (FieldGenerateModeEnum item : values()) { + if (modify.equals(item.getCode())) { + return item; + } + } + return null; + } + + @Override + public String getCode() { + return code; + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FunctionSwitchEnum.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FunctionSwitchEnum.java new file mode 100644 index 0000000..866c40f --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FunctionSwitchEnum.java @@ -0,0 +1,32 @@ +package cn.bigcoder.plugin.objecthelper.common.enums; + +/** + * @author: Jindong.Tian + * @date: 2023-12-24 + **/ +public enum FunctionSwitchEnum implements CommonEnum { + OPEN("open"), + CLOSE("close"), + ; + private String code; + + FunctionSwitchEnum(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public static FunctionSwitchEnum nameOf(String modify) { + if (modify == null) { + return null; + } + for (FunctionSwitchEnum item : values()) { + if (modify.equals(item.getCode())) { + return item; + } + } + return null; + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/JavaModify.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/JavaModifyEnum.java similarity index 77% rename from src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/JavaModify.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/JavaModifyEnum.java index f5d106a..c599104 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/JavaModify.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/JavaModifyEnum.java @@ -4,7 +4,7 @@ * @author: Jindong.Tian * @date: 2021-01-09 **/ -public enum JavaModify { +public enum JavaModifyEnum { PUBLIC("public", 1), PROTECTED("protected", 1), PRIVATE("private", 1), @@ -14,7 +14,7 @@ public enum JavaModify { private String name; private Integer priority; - JavaModify(String name, Integer priority) { + JavaModifyEnum(String name, Integer priority) { this.name = name; this.priority = priority; } @@ -23,11 +23,11 @@ public String getName() { return name; } - public JavaModify nameOf(String modify){ + public JavaModifyEnum nameOf(String modify){ if (modify == null){ return null; } - for (JavaModify item : values()) { + for (JavaModifyEnum item : values()) { if (modify.equals(item.getName())){ return item; } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/WhetherEnum.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/WhetherEnum.java new file mode 100644 index 0000000..918c484 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/WhetherEnum.java @@ -0,0 +1,32 @@ +package cn.bigcoder.plugin.objecthelper.common.enums; + +/** + * @author: Jindong.Tian + * @date: 2023-12-24 + **/ +public enum WhetherEnum implements CommonEnum { + YES("yes"), + NO("no"), + ; + private String code; + + WhetherEnum(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public static WhetherEnum nameOf(String modify) { + if (modify == null) { + return null; + } + for (WhetherEnum item : values()) { + if (modify.equals(item.getCode())) { + return item; + } + } + return null; + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java index a727e5c..c243b0e 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java @@ -1,7 +1,7 @@ package cn.bigcoder.plugin.objecthelper.common.util; import cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord; -import cn.bigcoder.plugin.objecthelper.common.enums.JavaModify; +import cn.bigcoder.plugin.objecthelper.common.enums.JavaModifyEnum; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -13,6 +13,7 @@ import com.intellij.psi.PsiField; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiModifierList; import com.intellij.psi.PsiParameter; import com.intellij.psi.PsiType; @@ -170,20 +171,20 @@ public static List getPsiParameters(PsiMethod psiMethod) { * @return */ @NotNull - public static List getMethodModifies(PsiModifierList modifierList) { - List result = new ArrayList<>(); - if (modifierList.hasModifierProperty(JavaModify.PUBLIC.getName())) { - result.add(JavaModify.PUBLIC); - } else if (modifierList.hasModifierProperty(JavaModify.PROTECTED.getName())) { - result.add(JavaModify.PROTECTED); - } else if (modifierList.hasModifierProperty(JavaModify.PRIVATE.getName())) { - result.add(JavaModify.PRIVATE); + public static List getMethodModifies(PsiModifierList modifierList) { + List result = new ArrayList<>(); + if (modifierList.hasModifierProperty(JavaModifyEnum.PUBLIC.getName())) { + result.add(JavaModifyEnum.PUBLIC); + } else if (modifierList.hasModifierProperty(JavaModifyEnum.PROTECTED.getName())) { + result.add(JavaModifyEnum.PROTECTED); + } else if (modifierList.hasModifierProperty(JavaModifyEnum.PRIVATE.getName())) { + result.add(JavaModifyEnum.PRIVATE); } - if (modifierList.hasModifierProperty(JavaModify.STATIC.getName())) { - result.add(JavaModify.STATIC); + if (modifierList.hasModifierProperty(JavaModifyEnum.STATIC.getName())) { + result.add(JavaModifyEnum.STATIC); } - if (modifierList.hasModifierProperty(JavaModify.FINAL.getName())) { - result.add(JavaModify.FINAL); + if (modifierList.hasModifierProperty(JavaModifyEnum.FINAL.getName())) { + result.add(JavaModifyEnum.FINAL); } return result; } @@ -201,6 +202,23 @@ public static List getAllPsiFields(PsiClass psiClass) { return result; } + /** + * 判断一个字段是否是类的成员属性 + * + * @param psiField + * @return + */ + public static boolean isMemberField(PsiField psiField) { + PsiModifierList modifierList = psiField.getModifierList(); + if (modifierList == null || + modifierList.hasModifierProperty(PsiModifier.STATIC) || + modifierList.hasModifierProperty(PsiModifier.FINAL) || + modifierList.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + return false; + } + return true; + } + /** * 递归获取类中所有字段 * diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/XMLUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/XMLUtils.java index d1ec63f..d55f516 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/XMLUtils.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/XMLUtils.java @@ -1,16 +1,10 @@ package cn.bigcoder.plugin.objecthelper.common.util; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.IOException; -import java.io.StringWriter; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import java.util.Map; /** @@ -18,45 +12,33 @@ * @date: 2022-08-26 **/ public class XMLUtils { - /** - * 将Map转换为XML格式的字符串 - * - * @param data Map类型数据 - * @return XML格式的字符串 - * @throws Exception - */ - public static String mapToXml(Map data) { - DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - String output = null; //.replaceAll("\n|\r", ""); - try { - DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder(); - org.w3c.dom.Document document = documentBuilder.newDocument(); - org.w3c.dom.Element root = document.createElement("xml"); - document.appendChild(root); - for (String key: data.keySet()) { - String value = data.get(key).toString(); - value = value.trim(); - org.w3c.dom.Element filed = document.createElement(key); - filed.appendChild(document.createTextNode(value)); - root.appendChild(filed); - } - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(); - DOMSource source = new DOMSource(document); - transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - StringWriter writer = new StringWriter(); - StreamResult result = new StreamResult(writer); - transformer.transform(source, result); - output = writer.getBuffer().toString(); - writer.close(); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (TransformerException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + + /** + * 将Map转换为XML格式的字符串 + * + * @param data Map类型数据 + * @return XML格式的字符串 + * @throws Exception + */ + public static String mapToXml(Map data) { + ObjectMapper objectMapper = new XmlMapper(); + // 修正根元素名称 + objectMapper.addMixIn(Map.class, MapMixin.class); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + String xmlString = ""; + try { + xmlString = objectMapper.writeValueAsString(data); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + return xmlString; + } + + /** + * 用于修正根元素名称 + */ + @JacksonXmlRootElement(localName = "root") + public static abstract class MapMixin { + } - return output; - } } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java b/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java index 7d2b187..39e1853 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java @@ -44,10 +44,12 @@ public boolean isModified() { public void apply() { PluginConfigModel instance = PluginConfigState.getInstance(); PluginConfigModel currentConfigModel = configPage.getCurrentConfigModel(); - instance.setJsonSwitch(currentConfigModel.isJsonSwitch()); - instance.setThriftSwitch(currentConfigModel.isThriftSwitch()); - instance.setXmlSwitch(currentConfigModel.isXmlSwitch()); - instance.setObjectCopySwitch(currentConfigModel.isObjectCopySwitch()); + instance.setJsonSwitch(currentConfigModel.getJsonSwitch()); + instance.setThriftSwitch(currentConfigModel.getThriftSwitch()); + instance.setXmlSwitch(currentConfigModel.getXmlSwitch()); + instance.setObjectCopySwitch(currentConfigModel.getObjectCopySwitch()); + instance.setObjectCopyMethodFieldGenerateAnnotation(currentConfigModel.getObjectCopyMethodFieldGenerateAnnotation()); + instance.setObjectCopyMethodFieldGenerateMode(currentConfigModel.getObjectCopyMethodFieldGenerateMode()); } } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java index ef25e8e..36d3b94 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java @@ -1,5 +1,8 @@ package cn.bigcoder.plugin.objecthelper.config; +import cn.bigcoder.plugin.objecthelper.common.enums.FieldGenerateModeEnum; +import cn.bigcoder.plugin.objecthelper.common.enums.FunctionSwitchEnum; +import cn.bigcoder.plugin.objecthelper.common.enums.WhetherEnum; import java.util.Objects; /** @@ -7,65 +10,101 @@ * @date: 2022-08-31 **/ public class PluginConfigModel { + /** * 是否开启 Class To Json 功能,默认为开启状态 */ - private boolean jsonSwitch = true; + private FunctionSwitchEnum jsonSwitch = FunctionSwitchEnum.OPEN; /** * 是否开启 Class To Thrift IDL 功能,默认为开启状态 */ - private boolean thriftSwitch = true; + private FunctionSwitchEnum thriftSwitch = FunctionSwitchEnum.OPEN; /** * 是否开启 Class To XML 功能,默认为开启状态 */ - private boolean xmlSwitch = true; + private FunctionSwitchEnum xmlSwitch = FunctionSwitchEnum.OPEN; /** * 是否开启 Object Copy Method 功能,默认为开启状态 */ - private boolean objectCopySwitch = true; + private FunctionSwitchEnum objectCopySwitch = FunctionSwitchEnum.OPEN; + /** + * Object Copy Method 功能中,以Source/Target对象为基础生成字段拷贝 + */ + private FieldGenerateModeEnum objectCopyMethodFieldGenerateMode = FieldGenerateModeEnum.TARGET; - public boolean isJsonSwitch() { + /** + * Object Copy Method 功能中,Source 和 Target 对象之间差异的字段,是否以代码注释的形式生成代码 + */ + private WhetherEnum objectCopyMethodFieldGenerateAnnotation = WhetherEnum.YES; + + public FunctionSwitchEnum getJsonSwitch() { return jsonSwitch; } - public void setJsonSwitch(boolean jsonSwitch) { + public void setJsonSwitch(FunctionSwitchEnum jsonSwitch) { this.jsonSwitch = jsonSwitch; } - public boolean isThriftSwitch() { + public FunctionSwitchEnum getThriftSwitch() { return thriftSwitch; } - public void setThriftSwitch(boolean thriftSwitch) { + public void setThriftSwitch(FunctionSwitchEnum thriftSwitch) { this.thriftSwitch = thriftSwitch; } - public boolean isXmlSwitch() { + public FunctionSwitchEnum getXmlSwitch() { return xmlSwitch; } - public void setXmlSwitch(boolean xmlSwitch) { + public void setXmlSwitch(FunctionSwitchEnum xmlSwitch) { this.xmlSwitch = xmlSwitch; } - public boolean isObjectCopySwitch() { + public FunctionSwitchEnum getObjectCopySwitch() { return objectCopySwitch; } - public void setObjectCopySwitch(boolean objectCopySwitch) { + public void setObjectCopySwitch(FunctionSwitchEnum objectCopySwitch) { this.objectCopySwitch = objectCopySwitch; } + public FieldGenerateModeEnum getObjectCopyMethodFieldGenerateMode() { + return objectCopyMethodFieldGenerateMode; + } + + public void setObjectCopyMethodFieldGenerateMode( + FieldGenerateModeEnum objectCopyMethodFieldGenerateMode) { + this.objectCopyMethodFieldGenerateMode = objectCopyMethodFieldGenerateMode; + } + + public WhetherEnum getObjectCopyMethodFieldGenerateAnnotation() { + return objectCopyMethodFieldGenerateAnnotation; + } + + public void setObjectCopyMethodFieldGenerateAnnotation( + WhetherEnum objectCopyMethodFieldGenerateAnnotation) { + this.objectCopyMethodFieldGenerateAnnotation = objectCopyMethodFieldGenerateAnnotation; + } + @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } PluginConfigModel that = (PluginConfigModel) o; - return jsonSwitch == that.jsonSwitch && thriftSwitch == that.thriftSwitch && xmlSwitch == that.xmlSwitch && objectCopySwitch == that.objectCopySwitch; + return jsonSwitch == that.jsonSwitch && thriftSwitch == that.thriftSwitch && xmlSwitch == that.xmlSwitch + && objectCopySwitch == that.objectCopySwitch + && objectCopyMethodFieldGenerateMode == that.objectCopyMethodFieldGenerateMode + && objectCopyMethodFieldGenerateAnnotation == that.objectCopyMethodFieldGenerateAnnotation; } @Override public int hashCode() { - return Objects.hash(jsonSwitch, thriftSwitch, xmlSwitch, objectCopySwitch); + return Objects.hash(jsonSwitch, thriftSwitch, xmlSwitch, objectCopySwitch, objectCopyMethodFieldGenerateMode, + objectCopyMethodFieldGenerateAnnotation); } } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractMethodGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractMethodGenerator.java index abb3ad1..c3912c2 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractMethodGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractMethodGenerator.java @@ -6,6 +6,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiParameter; +import com.intellij.psi.PsiType; import org.apache.commons.collections.CollectionUtils; import java.util.List; @@ -66,4 +67,8 @@ protected boolean check() { protected List getParameters() { return getPsiParameters(psiMethod); } + + protected PsiType getReturnType() { + return psiMethod.getReturnType(); + } } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java index 2ea54f1..0679bdd 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/idl/ThriftIDLGenerator.java @@ -46,6 +46,9 @@ public String generate() { * @return */ private StringBuilder generateStructCode(PsiClass psiClass) { + if (psiClass == null) { + return new StringBuilder(); + } if (recursiveCache.contains(psiClass.getQualifiedName())) { return new StringBuilder(); } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java index 1203fd6..0799f9a 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java @@ -1,7 +1,10 @@ package cn.bigcoder.plugin.objecthelper.generator.method; +import cn.bigcoder.plugin.objecthelper.common.enums.FieldGenerateModeEnum; +import cn.bigcoder.plugin.objecthelper.common.enums.WhetherEnum; import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; +import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.generator.AbstractMethodGenerator; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiField; @@ -9,6 +12,10 @@ import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiModifierList; import com.intellij.psi.PsiParameter; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import org.jetbrains.annotations.NotNull; import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.*; @@ -60,16 +67,33 @@ protected String generateMethodBody() { StringBuilder result = new StringBuilder(); result.append(generateNullCheck()); result.append(generateObjectCreateLine()); - for (PsiField field : PsiUtils.getAllPsiFields(getFirstParameterClass())) { - PsiModifierList modifierList = field.getModifierList(); - if (modifierList == null || - modifierList.hasModifierProperty(PsiModifier.STATIC) || - modifierList.hasModifierProperty(PsiModifier.FINAL) || - modifierList.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + FieldGenerateModeEnum generateModeEnum = PluginConfigState.getInstance() + .getObjectCopyMethodFieldGenerateMode(); + // mainClass 代表以哪个类字段为基础生成字段拷贝代码 + PsiClass mainClass = getReturnClass(); + PsiClass secondClass = getFirstParameterClass(); + if (generateModeEnum == FieldGenerateModeEnum.SOURCE) { + mainClass = getFirstParameterClass(); + secondClass = getReturnClass(); + } + + Set secondFieldNames = PsiUtils.getAllPsiFields(secondClass).stream().filter(e -> PsiUtils.isMemberField(e)) + .map(PsiField::getName).collect(Collectors.toSet()); + + List annotationLine = new LinkedList<>(); + for (PsiField field : PsiUtils.getAllPsiFields(mainClass)) { + if (!PsiUtils.isMemberField(field)) { continue; } - result.append(generateFieldCopyLine(field)); + if (secondFieldNames.contains(field.getName())) { + result.append(generateFieldCopyLine(field)); + } else if (PluginConfigState.getInstance().getObjectCopyMethodFieldGenerateAnnotation() + == WhetherEnum.YES) { + // 如果源对象没有该字段,且开启了以注释模式生成代码的开关,则生成注释 + annotationLine.add("// "+ generateFieldCopyLine(field)); + } } + annotationLine.forEach(result::append); result.append(generateReturnLine()); return result.toString(); } @@ -123,6 +147,7 @@ private PsiParameter getFirstParameter() { return getParameters().get(FIRST_INDEX); } + /** * 获取参数列表第一个参数的{@code PsiClass} * @@ -131,4 +156,8 @@ private PsiParameter getFirstParameter() { private PsiClass getFirstParameterClass() { return getPsiClass(getFirstParameter().getType(), project); } + + private PsiClass getReturnClass() { + return getPsiClass(getReturnType(), project); + } } \ No newline at end of file diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form index f4c3584..7e08139 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form @@ -8,15 +8,22 @@ - + + + + + + + + - + - + @@ -47,7 +54,7 @@ - + @@ -60,7 +67,7 @@ - + @@ -72,7 +79,7 @@ - + @@ -93,7 +100,7 @@ - + @@ -103,6 +110,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java index 8ccee25..033ca7e 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java @@ -1,8 +1,13 @@ package cn.bigcoder.plugin.objecthelper.ui; +import cn.bigcoder.plugin.objecthelper.common.enums.FieldGenerateModeEnum; +import cn.bigcoder.plugin.objecthelper.common.enums.FunctionSwitchEnum; +import cn.bigcoder.plugin.objecthelper.common.enums.WhetherEnum; import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.config.PluginConfigModel; +import java.util.Optional; +import java.util.function.Function; import javax.swing.*; /** @@ -11,13 +16,14 @@ **/ public class ConfigPage { - private static final String OPEN_STATUS = "open"; - private JPanel mainPanel; private JComboBox classToJsonSwitch; private JComboBox classToThriftSwitch; private JComboBox classToXmlSwitch; private JComboBox objectCopyMethodSwitch; + private JButton tipsButton; + private JComboBox objectCopyMethodGenerateMode; + private JComboBox objectCopyMethodGenerateAnnotation; public JPanel getMainPanel() { initField(); @@ -29,10 +35,12 @@ public JPanel getMainPanel() { */ public void initField() { PluginConfigModel instance = PluginConfigState.getInstance(); - this.classToJsonSwitch.setSelectedItem(convertComboBoxItem(instance.isJsonSwitch())); - this.classToThriftSwitch.setSelectedItem(convertComboBoxItem(instance.isThriftSwitch())); - this.classToXmlSwitch.setSelectedItem(convertComboBoxItem(instance.isXmlSwitch())); - this.objectCopyMethodSwitch.setSelectedItem(convertComboBoxItem(instance.isObjectCopySwitch())); + this.classToJsonSwitch.setSelectedItem(instance.getJsonSwitch().getCode()); + this.classToThriftSwitch.setSelectedItem(instance.getThriftSwitch().getCode()); + this.classToXmlSwitch.setSelectedItem(instance.getXmlSwitch().getCode()); + this.objectCopyMethodSwitch.setSelectedItem(instance.getObjectCopySwitch().getCode()); + this.objectCopyMethodGenerateAnnotation.setSelectedItem(instance.getObjectCopyMethodFieldGenerateAnnotation().getCode()); + this.objectCopyMethodGenerateMode.setSelectedItem(instance.getObjectCopyMethodFieldGenerateMode().getCode()); } /** @@ -42,17 +50,32 @@ public void initField() { */ public PluginConfigModel getCurrentConfigModel() { PluginConfigModel pluginConfigModel = new PluginConfigModel(); - pluginConfigModel.setJsonSwitch(this.classToJsonSwitch.getSelectedItem().equals(OPEN_STATUS)); - pluginConfigModel.setThriftSwitch(this.classToThriftSwitch.getSelectedItem().equals(OPEN_STATUS)); - pluginConfigModel.setXmlSwitch(this.classToXmlSwitch.getSelectedItem().equals(OPEN_STATUS)); - pluginConfigModel.setObjectCopySwitch(this.objectCopyMethodSwitch.getSelectedItem().equals(OPEN_STATUS)); + + Optional.ofNullable(this.classToJsonSwitch.getSelectedItem()).ifPresent(e -> { + pluginConfigModel.setJsonSwitch(FunctionSwitchEnum.nameOf(e.toString())); + } + ); + Optional.ofNullable(this.classToThriftSwitch.getSelectedItem()).ifPresent(e -> { + pluginConfigModel.setThriftSwitch(FunctionSwitchEnum.nameOf(e.toString())); + } + ); + Optional.ofNullable(this.classToXmlSwitch.getSelectedItem()).ifPresent(e -> { + pluginConfigModel.setXmlSwitch(FunctionSwitchEnum.nameOf(e.toString())); + } + ); + Optional.ofNullable(this.objectCopyMethodSwitch.getSelectedItem()).ifPresent(e -> { + pluginConfigModel.setObjectCopySwitch(FunctionSwitchEnum.nameOf(e.toString())); + } + ); + Optional.ofNullable(this.objectCopyMethodGenerateMode.getSelectedItem()).ifPresent(e -> { + pluginConfigModel.setObjectCopyMethodFieldGenerateMode(FieldGenerateModeEnum.nameOf(e.toString())); + } + ); + Optional.ofNullable(this.objectCopyMethodGenerateAnnotation.getSelectedItem()).ifPresent(e -> { + pluginConfigModel.setObjectCopyMethodFieldGenerateAnnotation(WhetherEnum.nameOf(e.toString())); + } + ); return pluginConfigModel; } - private static String convertComboBoxItem(boolean switchTag) { - if (switchTag) { - return "open"; - } - return "close"; - } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 5c2e9be..1581439 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -1,7 +1,7 @@ cn.bigcoder.plugin.objecthelper ObjectHelper - 1.3.1 + 1.3.2 HearingSmile fix feature:Resolve version compatibility issues and adapt new versions of the IDE +
  • add feature:Optimize the class to xml generation results
  • +
  • fix feature:Optimize the class to xml generation results
  • +
  • fix bug:Fix class to Thrift-IDL function NPE problem
  • ]]>
    From e5fd066ae6da36d3e4c8b982396852ac03e4159e Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 24 Dec 2023 17:29:13 +0800 Subject: [PATCH 06/10] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e6b309..a731083 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@
    - + From 44f2a293b29067fd17ce53d51422803356cd7596 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 24 Dec 2023 17:32:13 +0800 Subject: [PATCH 07/10] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d6430e..9eb5cb7 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ File->Settings->Tools->Object Helper 即可进入插件的配置页面 - `generate field mode = target` 代表以方法返回类型的字段为基础生成对象拷贝; `generate field mode = source` 代表以方法入参类型的字段为基础生成对象拷贝。 -- `non-existent field generate annotation = yes` 代表当目标字段,在源对象中不存在时,是否以注释的形式生成代码,如果为 `no`,则代表不生成这一个字段拷贝代码。 +- `non-existent field generate annotation = yes` 代表当目标字段在源对象中不存在时,是否以注释的形式生成代码,如果为 `no`,则代表不生成这一个字段拷贝代码。 ## 未来功能支持计划 From 1d484ac1b0e6d0781283c608b9a287982d92e7f2 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 7 Jan 2024 11:35:10 +0800 Subject: [PATCH 08/10] =?UTF-8?q?1.3.2=E7=89=88=E6=9C=AC=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 优化Object Copy Method 功能,新增生成模式配置,以及在字段有差异时以注释的形式生成代码 2. 修复 Class To XML 功能在复杂类结构时生成XML不正确的问题 3. 修复 Class To Thrift-IDL 功能,在一些场景下的NPE问题 4. 优化 Class To Json、Class To XML等功能对基本数据类型的支持 --- README.md | 2 +- .../common/constant/JavaClassName.java | 6 ++ .../common/util/PsiTypeUtils.java | 57 ++++++++++++------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 9eb5cb7..a3b37ae 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ - +
    JetBrains Intellij IDEA ObjectHelper 插件旨在减少开发者重复低效的劳动,使开发者能够更专注于业务逻辑的开发。 diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java index 8360806..297cf03 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java @@ -16,6 +16,12 @@ public class JavaClassName { public static final String LOCAL_DATE_TYPE = "java.time.LocalDate"; public static final String LOCAL_DATE_TIME_TYPE = "java.time.LocalDateTime"; public static final String BIG_DECIMAL = "java.math.BigDecimal"; + public static final String BASE_INT_TYPE = "int"; + public static final String BASE_LONG_TYPE = "long"; + public static final String BASE_SHORT_TYPE = "short"; + public static final String BASE_BYTE_TYPE = "byte"; + public static final String BASE_DOUBLE_TYPE = "double"; + public static final String BASE_FLOAT_TYPE = "float"; public static final String COLLECTION_TYPE = "java.util.Collection"; public static final String MAP_TYPE = "java.util.Map"; diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java index c539a76..9dccef7 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java @@ -9,9 +9,12 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Date; +import java.util.HashSet; +import java.util.Set; import org.apache.commons.lang3.time.DateFormatUtils; import static cn.bigcoder.plugin.objecthelper.common.constant.JavaClassName.*; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaClassName.BASE_BYTE_TYPE; /** * @author: Jindong.Tian @@ -19,6 +22,29 @@ **/ public class PsiTypeUtils { + private static final Set DATA_TYPES; + + static { + DATA_TYPES = new HashSet<>(); + DATA_TYPES.add(STRING_TYPE); + DATA_TYPES.add(INTEGER_TYPE); + DATA_TYPES.add(BASE_INT_TYPE); + DATA_TYPES.add(LONG_TYPE); + DATA_TYPES.add(BASE_LONG_TYPE); + DATA_TYPES.add(SHORT_TYPE); + DATA_TYPES.add(BASE_SHORT_TYPE); + DATA_TYPES.add(BYTE_TYPE); + DATA_TYPES.add(BASE_BYTE_TYPE); + DATA_TYPES.add(DOUBLE_TYPE); + DATA_TYPES.add(BASE_DOUBLE_TYPE); + DATA_TYPES.add(FLOAT_TYPE); + DATA_TYPES.add(BASE_FLOAT_TYPE); + DATA_TYPES.add(DATE_TYPE); + DATA_TYPES.add(LOCAL_DATE_TYPE); + DATA_TYPES.add(LOCAL_DATE_TIME_TYPE); + DATA_TYPES.add(BIG_DECIMAL); + } + /** * 获取数据类型的默认值 * @@ -33,17 +59,23 @@ public static Object getDataTypeDefaultValue(String canonicalText) { case STRING_TYPE: return ""; case INTEGER_TYPE: + case BASE_INT_TYPE: return 1; case LONG_TYPE: + case BASE_LONG_TYPE: return 1L; case SHORT_TYPE: + case BASE_SHORT_TYPE: return (short) 1; case BYTE_TYPE: + case BASE_BYTE_TYPE: return (byte) 1; case DOUBLE_TYPE: - return 1.0; + case BASE_DOUBLE_TYPE: + return 1.1; case FLOAT_TYPE: - return 1.0f; + case BASE_FLOAT_TYPE: + return 1.1f; case DATE_TYPE: return DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"); case LOCAL_DATE_TYPE: @@ -62,21 +94,7 @@ public static Object getDataTypeDefaultValue(String canonicalText) { * @return */ public static boolean isDataType(PsiType psiType) { - String canonicalName = psiType.getCanonicalText(); - if (STRING_TYPE.equals(canonicalName) - || INTEGER_TYPE.equals(canonicalName) - || LONG_TYPE.equals(canonicalName) - || SHORT_TYPE.equals(canonicalName) - || BYTE_TYPE.equals(canonicalName) - || DOUBLE_TYPE.equals(canonicalName) - || FLOAT_TYPE.equals(canonicalName) - || DATE_TYPE.equals(canonicalName) - || LOCAL_DATE_TYPE.equals(canonicalName) - || LOCAL_DATE_TIME_TYPE.equals(canonicalName) - || BIG_DECIMAL.equals(canonicalName)) { - return true; - } - return false; + return DATA_TYPES.contains(psiType.getCanonicalText()); } /** @@ -132,11 +150,12 @@ public static boolean isMapType(PsiType psiType) { /** * 判断一个类是否是指定类型子类 - * @param psiType psiType + * + * @param psiType psiType * @param qualifiedName 全限定名称 * @return */ - public static boolean isSpecifiedType(PsiType psiType, String qualifiedName){ + public static boolean isSpecifiedType(PsiType psiType, String qualifiedName) { if (!(psiType instanceof PsiClassType)) { return false; } From 88ef0177be678fbf3fd2751be5d673263a799f23 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 7 Jan 2024 13:45:44 +0800 Subject: [PATCH 09/10] update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3b37ae..e80575f 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ object-helper插件未来功能支持计划: - [x] Class 转 XML(Class To XML) - [x] 个性化配置 - [ ] Object Copy Method 功能支持 Lambda 表达式 -- [ ] JSON 转 Class(JSON TO Class) -- [ ] Class 转 Protobuf IDL(JSON TO Class) +- [ ] JSON 转 Class(JSON To Class) +- [ ] Class 转 Protobuf IDL(JSON To Class) - [ ] All Setter - [ ] 菜单分组显示 From 40bceb01b29f2e86ca598463bbebf79e2ffeaa8d Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 5 May 2024 14:03:00 +0800 Subject: [PATCH 10/10] =?UTF-8?q?1.3.3=E7=89=88=E6=9C=AC=EF=BC=9A=20=201.?= =?UTF-8?q?=20Object=20Copy=20Method=20=E6=96=B0=E5=A2=9Ebuilder=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E6=94=AF=E6=8C=81=EF=BC=8C=E5=BD=93=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E4=B8=AD=E5=8C=85=E5=90=AB=E6=8C=87=E5=AE=9A=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E4=BD=BF=E7=94=A8builder=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E7=94=9F=E6=88=90=E6=8B=B7=E8=B4=9D=E4=BB=A3=E7=A0=81=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 18 ++- build.gradle | 5 +- .../common/enums/ObjectCopyStrategyEnum.java | 17 +++ .../ObjectHeplerPluginException.java | 28 +++++ .../objecthelper/common/util/PsiUtils.java | 17 +++ .../config/ObjectHelperConfigurable.java | 1 + .../config/PluginConfigModel.java | 22 +++- .../copy/AbstractObjectCopyStrategy.java | 98 +++++++++++++++ .../strategy/BuilderObjectCopyStrategy.java | 60 +++++++++ .../copy/strategy/SetObjectCopyStrategy.java | 59 +++++++++ .../method/ObjectCopyMethodGenerator.java | 114 +++--------------- .../plugin/objecthelper/ui/ConfigPage.form | 20 +++ .../plugin/objecthelper/ui/ConfigPage.java | 6 +- 13 files changed, 360 insertions(+), 105 deletions(-) create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/ObjectCopyStrategyEnum.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/common/exception/ObjectHeplerPluginException.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/AbstractObjectCopyStrategy.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/strategy/BuilderObjectCopyStrategy.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/strategy/SetObjectCopyStrategy.java diff --git a/README.md b/README.md index e80575f..2e927f6 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@
    - + - - + +
    JetBrains Intellij IDEA ObjectHelper 插件旨在减少开发者重复低效的劳动,使开发者能够更专注于业务逻辑的开发。 @@ -16,6 +16,7 @@ JetBrains Intellij IDEA ObjectHelper 插件旨在减少开发者重复低效的 该插件包含以下功能: - 对象拷贝 + set模式: ![](https://image.bigcoder.cn/7fce876e-fa94-4780-bb14-584068c35963.gif) @@ -23,6 +24,14 @@ JetBrains Intellij IDEA ObjectHelper 插件旨在减少开发者重复低效的 ![](https://image.bigcoder.cn/20220916173117.png) + 当对象中包含`builder` 或者 `newBuilder`方法时,则插件默认会采用 builder 模式生成代码: + + ![](https://image.bigcoder.cn/20240505142735.gif) + + 如果你的builder类生成的方法名与插件默认生成的不同,可以在设置中更改: + + ![](https://image.bigcoder.cn/20240505143027.png) + - Java类转JSON ![](https://image.bigcoder.cn/20231224171155.gif) @@ -42,7 +51,7 @@ File->Settings->Tools->Object Helper 即可进入插件的配置页面 ![](https://image.bigcoder.cn/20231224170305.png) - `generate field mode = target` 代表以方法返回类型的字段为基础生成对象拷贝; -`generate field mode = source` 代表以方法入参类型的字段为基础生成对象拷贝。 + `generate field mode = source` 代表以方法入参类型的字段为基础生成对象拷贝。 - `non-existent field generate annotation = yes` 代表当目标字段在源对象中不存在时,是否以注释的形式生成代码,如果为 `no`,则代表不生成这一个字段拷贝代码。 @@ -53,6 +62,7 @@ object-helper插件未来功能支持计划: - [x] Class 转 IDL(Class To Thrift IDL) - [x] Class 转 XML(Class To XML) - [x] 个性化配置 +- [x] Object Copy Method 功能支持 Builder 模式 - [ ] Object Copy Method 功能支持 Lambda 表达式 - [ ] JSON 转 Class(JSON To Class) - [ ] Class 转 Protobuf IDL(JSON To Class) diff --git a/build.gradle b/build.gradle index 95e9899..196c339 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'cn.bigcoder.plugin' -version '1.3.2' +version '1.3.3' repositories { mavenCentral() @@ -29,8 +29,9 @@ intellij { } patchPluginXml { sinceBuild = '211' + untilBuild = '281' changeNotes = """ - 1. fix feature:Resolve version compatibility issues and adapt new versions of the IDE + 1. new feature: Object Copy Method support builder mode. """ } test { diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/ObjectCopyStrategyEnum.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/ObjectCopyStrategyEnum.java new file mode 100644 index 0000000..2cb0bd6 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/ObjectCopyStrategyEnum.java @@ -0,0 +1,17 @@ +package cn.bigcoder.plugin.objecthelper.common.enums; + +/** + * @author: Jindong.Tian + * @date: 2023-12-24 + **/ +public enum ObjectCopyStrategyEnum { + /** + * 普通SET模式 + */ + SET, + /** + * builder模式 + */ + BUILDER, + ; +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/exception/ObjectHeplerPluginException.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/exception/ObjectHeplerPluginException.java new file mode 100644 index 0000000..08d0c3d --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/exception/ObjectHeplerPluginException.java @@ -0,0 +1,28 @@ +package cn.bigcoder.plugin.objecthelper.common.exception; + +/** + * @author: Jindong.Tian + * @date: 2024-05-05 + **/ +public class ObjectHeplerPluginException extends RuntimeException{ + + public ObjectHeplerPluginException() { + } + + public ObjectHeplerPluginException(String message) { + super(message); + } + + public ObjectHeplerPluginException(String message, Throwable cause) { + super(message, cause); + } + + public ObjectHeplerPluginException(Throwable cause) { + super(cause); + } + + public ObjectHeplerPluginException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java index c243b0e..c0cc060 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java @@ -12,6 +12,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiIdentifier; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiModifierList; @@ -25,6 +26,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.jetbrains.annotations.Nullable; /** * @author: Jindong.Tian @@ -153,6 +155,21 @@ public static String getMethodReturnClassName(PsiMethod psiMethod) { return returnType.getPresentableText(); } + /** + * 获取PsiClass 名称 + * + * @param psiClass + * @return + */ + @Nullable + public static String getPsiClassName(PsiClass psiClass) { + PsiIdentifier nameIdentifier = psiClass.getNameIdentifier(); + if (nameIdentifier == null) { + return null; + } + return nameIdentifier.getText(); + } + /** * 获取方法的参数列表 * diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java b/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java index 39e1853..46b9b29 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/ObjectHelperConfigurable.java @@ -50,6 +50,7 @@ public void apply() { instance.setObjectCopySwitch(currentConfigModel.getObjectCopySwitch()); instance.setObjectCopyMethodFieldGenerateAnnotation(currentConfigModel.getObjectCopyMethodFieldGenerateAnnotation()); instance.setObjectCopyMethodFieldGenerateMode(currentConfigModel.getObjectCopyMethodFieldGenerateMode()); + instance.setBuilderInstanceMethodName(currentConfigModel.getBuilderInstanceMethodName()); } } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java index 36d3b94..66fc4b6 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java @@ -37,6 +37,11 @@ public class PluginConfigModel { */ private WhetherEnum objectCopyMethodFieldGenerateAnnotation = WhetherEnum.YES; + /** + * Object Copy Method 功能中,使用builder模式生成拷贝代码时的判断依据,当目标对象类中包含正则所指定的方法,则默认按照builder模式生成,否则使用set模式生成 + */ + private String builderInstanceMethodName = ".*(builder|newBuilder).*"; + public FunctionSwitchEnum getJsonSwitch() { return jsonSwitch; } @@ -87,6 +92,14 @@ public void setObjectCopyMethodFieldGenerateAnnotation( this.objectCopyMethodFieldGenerateAnnotation = objectCopyMethodFieldGenerateAnnotation; } + public String getBuilderInstanceMethodName() { + return builderInstanceMethodName; + } + + public void setBuilderInstanceMethodName(String builderInstanceMethodName) { + this.builderInstanceMethodName = builderInstanceMethodName; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -97,14 +110,15 @@ public boolean equals(Object o) { } PluginConfigModel that = (PluginConfigModel) o; return jsonSwitch == that.jsonSwitch && thriftSwitch == that.thriftSwitch && xmlSwitch == that.xmlSwitch - && objectCopySwitch == that.objectCopySwitch - && objectCopyMethodFieldGenerateMode == that.objectCopyMethodFieldGenerateMode - && objectCopyMethodFieldGenerateAnnotation == that.objectCopyMethodFieldGenerateAnnotation; + && objectCopySwitch == that.objectCopySwitch + && objectCopyMethodFieldGenerateMode == that.objectCopyMethodFieldGenerateMode + && objectCopyMethodFieldGenerateAnnotation == that.objectCopyMethodFieldGenerateAnnotation + && Objects.equals(builderInstanceMethodName, that.builderInstanceMethodName); } @Override public int hashCode() { return Objects.hash(jsonSwitch, thriftSwitch, xmlSwitch, objectCopySwitch, objectCopyMethodFieldGenerateMode, - objectCopyMethodFieldGenerateAnnotation); + objectCopyMethodFieldGenerateAnnotation, builderInstanceMethodName); } } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/AbstractObjectCopyStrategy.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/AbstractObjectCopyStrategy.java new file mode 100644 index 0000000..5e27888 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/AbstractObjectCopyStrategy.java @@ -0,0 +1,98 @@ +package cn.bigcoder.plugin.objecthelper.generator.copy; + +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClassName; + +import cn.bigcoder.plugin.objecthelper.common.enums.FieldGenerateModeEnum; +import cn.bigcoder.plugin.objecthelper.common.enums.WhetherEnum; +import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; +import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; +import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; +import cn.bigcoder.plugin.objecthelper.generator.Generator; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiField; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author: Jindong.Tian + * @date: 2024-05-05 + **/ +public abstract class AbstractObjectCopyStrategy implements Generator { + + /** + * 对象拷贝源对象类型 + */ + protected PsiClass sourceClass; + /** + * 对象拷贝目标对象类型 + */ + protected PsiClass targetClass; + /** + * 对象拷贝源参数名称 + */ + protected String sourceParamName; + /** + * 对象拷贝目标参数名称 + */ + protected String targetParamName; + + public AbstractObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String sourceParamName) { + this.sourceClass = sourceClass; + this.targetClass = targetClass; + this.sourceParamName = sourceParamName; + // 生成参数名 + this.targetParamName = StringUtils.firstLowerCase(Objects.requireNonNull(getPsiClassName(targetClass))); + // 防止方法入参和返回参数名称一致 + if (sourceParamName.equals(this.targetParamName)) { + this.targetParamName = this.targetParamName + "Res"; + } + } + + @Override + public String generate() { + StringBuilder result = new StringBuilder(); + // 生成前缀 + result.append(generatePrefix()); + + // 字段copy模式 + FieldGenerateModeEnum generateModeEnum = PluginConfigState.getInstance().getObjectCopyMethodFieldGenerateMode(); + + // mainClass 代表以哪个类字段为基础生成字段拷贝代码 + PsiClass mainClass = targetClass; + PsiClass secondClass = sourceClass; + if (generateModeEnum == FieldGenerateModeEnum.SOURCE) { + // 字段拷贝使用源字段为蓝本拷贝 + mainClass = sourceClass; + secondClass = targetClass; + } + + Set secondFieldNames = PsiUtils.getAllPsiFields(secondClass).stream().filter(PsiUtils::isMemberField) + .map(PsiField::getName).collect(Collectors.toSet()); + + List annotationLine = new LinkedList<>(); + for (PsiField field : PsiUtils.getAllPsiFields(mainClass)) { + if (!PsiUtils.isMemberField(field)) { + continue; + } + if (secondFieldNames.contains(field.getName())) { + result.append(generateFiledCopy(field)); + } else if (PluginConfigState.getInstance().getObjectCopyMethodFieldGenerateAnnotation() + == WhetherEnum.YES) { + // 如果源对象没有该字段,且开启了以注释模式生成代码的开关,则生成注释 + annotationLine.add("// " + generateFiledCopy(field)); + } + } + annotationLine.forEach(result::append); + result.append(generateSuffix()); + return result.toString(); + } + + protected abstract String generatePrefix(); + + protected abstract String generateFiledCopy(PsiField field); + + protected abstract String generateSuffix(); +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/strategy/BuilderObjectCopyStrategy.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/strategy/BuilderObjectCopyStrategy.java new file mode 100644 index 0000000..fb72f61 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/strategy/BuilderObjectCopyStrategy.java @@ -0,0 +1,60 @@ +package cn.bigcoder.plugin.objecthelper.generator.copy.strategy; + +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.BLANK_SEPARATOR; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.LINE_SEPARATOR; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClassName; + +import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; +import cn.bigcoder.plugin.objecthelper.generator.copy.AbstractObjectCopyStrategy; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiField; + +/** + * @author: Jindong.Tian + * @date: 2024-05-05 + **/ +public class BuilderObjectCopyStrategy extends AbstractObjectCopyStrategy { + + public BuilderObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String sourceParamName) { + super(sourceClass, targetClass, sourceParamName); + } + + + /** + * 生成类似如下代码: + * + * if (user == null) { + * return null; + * } + * return UserDto.builder() + * + * @return + */ + @Override + protected String generatePrefix() { + return generateNullCheck(sourceParamName) + LINE_SEPARATOR + + "return" + BLANK_SEPARATOR + getPsiClassName(targetClass) + ".builder()" + LINE_SEPARATOR; + } + + @Override + protected String generateFiledCopy(PsiField field) { + return "." + field.getName() + "(" + + sourceParamName + ".get" + StringUtils.firstUpperCase(field.getName()) + "())" + + LINE_SEPARATOR; + } + + + @Override + protected String generateSuffix() { + return ".build();" + LINE_SEPARATOR; + } + + /** + * 生成示例:{@code if (user == null) {return null;}} + * + * @return + */ + private String generateNullCheck(String sourceParamName) { + return "if(" + sourceParamName + "==null){return null;}"; + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/strategy/SetObjectCopyStrategy.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/strategy/SetObjectCopyStrategy.java new file mode 100644 index 0000000..48dc32a --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/strategy/SetObjectCopyStrategy.java @@ -0,0 +1,59 @@ +package cn.bigcoder.plugin.objecthelper.generator.copy.strategy; + +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.BLANK_SEPARATOR; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.LINE_SEPARATOR; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.SEMICOLON_SEPARATOR; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClassName; + +import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; +import cn.bigcoder.plugin.objecthelper.generator.copy.AbstractObjectCopyStrategy; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiField; + +/** + * @author: Jindong.Tian + * @date: 2024-05-05 + **/ +public class SetObjectCopyStrategy extends AbstractObjectCopyStrategy { + + public SetObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String sourceParamName) { + super(sourceClass, targetClass, sourceParamName); + } + + /** + * 生成类似如下代码: + * + * if (user == null) { + * return null; + * } + * UserDto userDto = new UserDto(); + * + * @return + */ + @Override + protected String generatePrefix() { + String psiClassName = getPsiClassName(targetClass); + return generateNullCheck(sourceParamName) + LINE_SEPARATOR + + psiClassName + BLANK_SEPARATOR + targetParamName + "= new " + psiClassName + "();" + LINE_SEPARATOR; + } + + @Override + protected String generateFiledCopy(PsiField field) { + return targetParamName + ".set" + StringUtils.firstUpperCase(field.getName()) + "(" + sourceParamName + ".get" + StringUtils.firstUpperCase(field.getName()) + "());" + LINE_SEPARATOR; + } + + + @Override + protected String generateSuffix() { + return "return " + targetParamName + SEMICOLON_SEPARATOR; + } + + /** + * 生成示例:{@code if (user == null) {return null;}} + * + * @return + */ + private String generateNullCheck(String sourceParamName) { + return "if(" + sourceParamName + "==null){return null;}"; + } +} diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java index 0799f9a..63a4b78 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java @@ -1,26 +1,16 @@ package cn.bigcoder.plugin.objecthelper.generator.method; -import cn.bigcoder.plugin.objecthelper.common.enums.FieldGenerateModeEnum; -import cn.bigcoder.plugin.objecthelper.common.enums.WhetherEnum; -import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; -import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClass; + import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import cn.bigcoder.plugin.objecthelper.generator.AbstractMethodGenerator; +import cn.bigcoder.plugin.objecthelper.generator.copy.AbstractObjectCopyStrategy; +import cn.bigcoder.plugin.objecthelper.generator.copy.strategy.BuilderObjectCopyStrategy; +import cn.bigcoder.plugin.objecthelper.generator.copy.strategy.SetObjectCopyStrategy; import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiModifier; -import com.intellij.psi.PsiModifierList; import com.intellij.psi.PsiParameter; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import org.jetbrains.annotations.NotNull; - -import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.*; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getMethodReturnClassName; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClass; +import java.util.regex.Pattern; /** * @author: Jindong.Tian @@ -32,10 +22,6 @@ public class ObjectCopyMethodGenerator extends AbstractMethodGenerator { * 方法第一个参数名称 */ private String firstParameterName; - /** - * 方法返回局部变量名称 - */ - private String returnObjName; private void init(PsiMethod psiMethod) { if (psiMethod == null) { @@ -44,11 +30,6 @@ private void init(PsiMethod psiMethod) { super.project = psiMethod.getProject(); super.psiMethod = psiMethod; this.firstParameterName = getFirstParameter().getName(); - this.returnObjName = StringUtils.firstLowerCase(getMethodReturnClassName(psiMethod)); - // 防止方法入参和返回参数名称一致 - if (firstParameterName.equals(returnObjName)) { - this.returnObjName = this.returnObjName + "1"; - } } public static ObjectCopyMethodGenerator getInstance(PsiMethod psiMethod) { @@ -64,78 +45,23 @@ public static ObjectCopyMethodGenerator getInstance(PsiMethod psiMethod) { */ @Override protected String generateMethodBody() { - StringBuilder result = new StringBuilder(); - result.append(generateNullCheck()); - result.append(generateObjectCreateLine()); - FieldGenerateModeEnum generateModeEnum = PluginConfigState.getInstance() - .getObjectCopyMethodFieldGenerateMode(); - // mainClass 代表以哪个类字段为基础生成字段拷贝代码 - PsiClass mainClass = getReturnClass(); - PsiClass secondClass = getFirstParameterClass(); - if (generateModeEnum == FieldGenerateModeEnum.SOURCE) { - mainClass = getFirstParameterClass(); - secondClass = getReturnClass(); - } - - Set secondFieldNames = PsiUtils.getAllPsiFields(secondClass).stream().filter(e -> PsiUtils.isMemberField(e)) - .map(PsiField::getName).collect(Collectors.toSet()); + AbstractObjectCopyStrategy copyStrategy = getCopyStrategy(); + return copyStrategy.generate(); + } - List annotationLine = new LinkedList<>(); - for (PsiField field : PsiUtils.getAllPsiFields(mainClass)) { - if (!PsiUtils.isMemberField(field)) { - continue; - } - if (secondFieldNames.contains(field.getName())) { - result.append(generateFieldCopyLine(field)); - } else if (PluginConfigState.getInstance().getObjectCopyMethodFieldGenerateAnnotation() - == WhetherEnum.YES) { - // 如果源对象没有该字段,且开启了以注释模式生成代码的开关,则生成注释 - annotationLine.add("// "+ generateFieldCopyLine(field)); + private AbstractObjectCopyStrategy getCopyStrategy() { + // mainClass 代表以哪个类字段为基础生成字段拷贝代码 + PsiClass returnClass = getReturnClass(); + PsiClass sourceClass = getFirstParameterClass(); + String builderRegex = PluginConfigState.getInstance().getBuilderInstanceMethodName(); + + Pattern pattern = Pattern.compile(builderRegex); + for (PsiMethod method : returnClass.getMethods()) { + if (pattern.matcher(method.getName()).matches()) { + return new BuilderObjectCopyStrategy(sourceClass, returnClass, this.firstParameterName); } } - annotationLine.forEach(result::append); - result.append(generateReturnLine()); - return result.toString(); - } - - /** - * 生成示例:{@code UserDTO userDTO = new UserDTO();} - * - * @return - */ - @NotNull - private String generateObjectCreateLine() { - return getMethodReturnClassName(psiMethod) + BLANK_SEPARATOR + returnObjName + "= new " + getMethodReturnClassName(psiMethod) + "();" + LINE_SEPARATOR; - } - - /** - * 生成示例:{@code userDTO.setId(user.getId());} - * - * @param field - * @return - */ - @NotNull - private String generateFieldCopyLine(PsiField field) { - return returnObjName + ".set" + StringUtils.firstUpperCase(field.getName()) + "(" + firstParameterName + ".get" + StringUtils.firstUpperCase(field.getName()) + "());" + LINE_SEPARATOR; - } - - /** - * 生成示例:{@code return userDTO;} - * - * @return - */ - @NotNull - private String generateReturnLine() { - return "return " + returnObjName + SEMICOLON_SEPARATOR; - } - - /** - * 生成示例:{@code if (user == null) {return null;}} - * - * @return - */ - private String generateNullCheck() { - return "if(" + getFirstParameter().getName() + "==null){return null;}"; + return new SetObjectCopyStrategy(sourceClass, returnClass, this.firstParameterName); } /** diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form index 7e08139..ec970d0 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form @@ -14,6 +14,8 @@ + + @@ -181,6 +183,24 @@
    + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java index 033ca7e..985abb4 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java @@ -7,7 +7,6 @@ import cn.bigcoder.plugin.objecthelper.config.PluginConfigModel; import java.util.Optional; -import java.util.function.Function; import javax.swing.*; /** @@ -24,6 +23,7 @@ public class ConfigPage { private JButton tipsButton; private JComboBox objectCopyMethodGenerateMode; private JComboBox objectCopyMethodGenerateAnnotation; + private JTextField builderInstanceMethodName; public JPanel getMainPanel() { initField(); @@ -41,6 +41,7 @@ public void initField() { this.objectCopyMethodSwitch.setSelectedItem(instance.getObjectCopySwitch().getCode()); this.objectCopyMethodGenerateAnnotation.setSelectedItem(instance.getObjectCopyMethodFieldGenerateAnnotation().getCode()); this.objectCopyMethodGenerateMode.setSelectedItem(instance.getObjectCopyMethodFieldGenerateMode().getCode()); + this.builderInstanceMethodName.setText(instance.getBuilderInstanceMethodName()); } /** @@ -75,6 +76,9 @@ public PluginConfigModel getCurrentConfigModel() { pluginConfigModel.setObjectCopyMethodFieldGenerateAnnotation(WhetherEnum.nameOf(e.toString())); } ); + Optional.ofNullable(this.builderInstanceMethodName.getText()).ifPresent( + pluginConfigModel::setBuilderInstanceMethodName + ); return pluginConfigModel; }