From 3e23613623f6a46c34d10df0b6a84f42ee3234f3 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 30 Jan 2021 21:43:08 +0800 Subject: [PATCH 01/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8F=92=E4=BB=B6BUG?= =?UTF-8?q?=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.修复GenerateO2O组件在异常场景下使用的BUG --- README.md | 2 +- images/1.gif | Bin 79414 -> 0 bytes object-helper.jar | Bin 14908 -> 15190 bytes resources/META-INF/plugin.xml | 11 +-- resources/META-INF/pluginIcon.svg | 3 + .../{ => component}/GenerateO2O.java | 29 +++---- .../method/AbstractMethodGenerator.java | 18 ++-- .../method/ObjectCopyMethodGenerator.java | 77 ++++++++++++++---- 8 files changed, 93 insertions(+), 47 deletions(-) delete mode 100644 images/1.gif create mode 100644 resources/META-INF/pluginIcon.svg rename src/cn/bigcoder/plugin/objecthelper/{ => component}/GenerateO2O.java (74%) diff --git a/README.md b/README.md index 2f9a9f6..357b0ff 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,6 @@ JetBrains Intellij IDEA Obejct辅助插件,包含以下功能: - 对象拷贝 - ![](./images/1.gif) + ![](https://image.bigcoder.cn/6d6af6fd-255c-4d32-83bb-85b39280460d.gif) - … \ No newline at end of file diff --git a/images/1.gif b/images/1.gif deleted file mode 100644 index 1c8bc92d9308ab176f3226519f40671ae2592085..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79414 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 diff --git a/object-helper.jar b/object-helper.jar index e2416de5aa71fe2c68605ee1bbca10fa9c08cb0b..db816c1ab3105893f1ae4c60da59ee28005a072e 100644 GIT binary patch delta 10308 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⋁SH~cxbl{im=r68Em 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 delta 9982 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 F{STTFu$=$^ diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index 76fabb9..b5d4b8b 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -1,21 +1,22 @@ cn.bigcoder.plugin.objecthelper ObjectHelper - 1.0 + 1.0.1 HearingSmile 对象拷贝 + This is a Java object toolset +
  • Copy the object
  • + ]]>
    Fix bug:fixed bugs in exception scenarios.Improve plugin compatibility. ]]> - + diff --git a/resources/META-INF/pluginIcon.svg b/resources/META-INF/pluginIcon.svg new file mode 100644 index 0000000..f8fc670 --- /dev/null +++ b/resources/META-INF/pluginIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/cn/bigcoder/plugin/objecthelper/GenerateO2O.java b/src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java similarity index 74% rename from src/cn/bigcoder/plugin/objecthelper/GenerateO2O.java rename to src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java index 7f63f6c..c1444f4 100644 --- a/src/cn/bigcoder/plugin/objecthelper/GenerateO2O.java +++ b/src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java @@ -8,34 +8,27 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; public class GenerateO2O extends AnAction { @Override - public void actionPerformed(AnActionEvent e) { - PsiMethod method = getPsiMethodFromContext(e); - generateO2OMethod(method); - } - - /** - * 启动写线程 - * - * @param psiMethod - */ - private void generateO2OMethod(PsiMethod psiMethod) { - new WriteCommandAction.Simple(psiMethod.getProject(), psiMethod.getContainingFile()) { - @Override - protected void run() throws Throwable { - generateO2O(psiMethod); - } - }.execute(); + public void actionPerformed(AnActionEvent anActionEvent) { + WriteCommandAction.runWriteCommandAction(anActionEvent.getProject(), () -> { + generateO2O(getPsiMethodFromContext(anActionEvent)); + }); } private void generateO2O(PsiMethod psiMethod) { + if (psiMethod == null) { + return; + } + // 初始化生成器 Generator generator = ObjectCopyMethodGenerator.getInstance(psiMethod); PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(psiMethod.getProject()); + // 生成新的PsiMethod PsiMethod toMethod = elementFactory.createMethodFromText(generator.generate(), psiMethod); psiMethod.replace(toMethod); } @@ -55,7 +48,7 @@ private PsiElement getPsiElement(AnActionEvent e) { e.getPresentation().setEnabled(false); return null; } - //用来获取当前光标处的PsiElement + //获取当前光标处的PsiElement int offset = editor.getCaretModel().getOffset(); return psiFile.findElementAt(offset); } diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java index 59e443d..ab47bba 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java +++ b/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java @@ -15,6 +15,14 @@ **/ public abstract class AbstractMethodGenerator implements Generator { + protected static final int FIRST_INDEX = 0; + protected static final String EMPTY_BODY = ""; + protected static final String BLANK_SEPARATOR = " "; + protected static final String LINE_SEPARATOR = "\n"; + protected static final String COMMA_SEPARATOR = ","; + + protected static final String VOID_KEYWORD = "void"; + /** * 方法修饰符 */ @@ -40,18 +48,18 @@ public abstract class AbstractMethodGenerator implements Generator { public String generate() { StringBuilder result = generateMethodFirstLine() .append(generateMethodBody()) - .append("}\n"); + .append("}"); return result.toString(); } protected StringBuilder generateMethodFirstLine() { StringBuilder builder = new StringBuilder(); - methodModifies.forEach(e -> builder.append(e.getName() + " ")); - builder.append(returnClassName + " ") + methodModifies.forEach(e -> builder.append(e.getName()).append(BLANK_SEPARATOR)); + builder.append(returnClassName + BLANK_SEPARATOR) .append(methodName) .append("(") - .append(StringUtils.join(parameters, PsiParameter::getText, " ,")) - .append(") {\n"); + .append(StringUtils.join(parameters, PsiParameter::getText, COMMA_SEPARATOR)) + .append("){"); return builder; } diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java index a187422..0746eda 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java +++ b/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java @@ -5,6 +5,7 @@ import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import org.apache.commons.collections.CollectionUtils; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Arrays; @@ -17,9 +18,6 @@ **/ public class ObjectCopyMethodGenerator extends AbstractMethodGenerator { - private ObjectCopyMethodGenerator() { - } - private void init(PsiMethod psiMethod) { super.methodName = psiMethod.getName(); super.returnClassName = getReturnClassName(psiMethod); @@ -36,17 +34,19 @@ public static ObjectCopyMethodGenerator getInstance(PsiMethod psiMethod) { @Override protected String generateMethodBody() { - if (CollectionUtils.isEmpty(parameters)) { - return ""; + if (CollectionUtils.isEmpty(parameters) || VOID_KEYWORD.equals(returnClassName)) { + return EMPTY_BODY; } StringBuilder result = new StringBuilder(); String returnObjName = StringUtils.firstLowerCase(returnClassName); - PsiParameter firstParameter = parameters.get(0); - PsiClass firstClass = parameterClass.get(0); - String parameterName = firstParameter.getName(); - result.append(generateNullCheck(parameterName)); - result.append(returnClassName).append(" ").append(returnObjName).append("= new ").append(returnClassName).append("();\n"); - for (PsiField field : firstClass.getFields()) { + PsiParameter firstParameter = parameters.get(FIRST_INDEX); + PsiClass firstParameterClass = parameterClass.get(FIRST_INDEX); + if (firstParameterClass == null) { + return EMPTY_BODY; + } + result.append(generateNullCheck(firstParameter.getName())); + result.append(generateObjectCreateLine(returnObjName)); + for (PsiField field : firstParameterClass.getFields()) { PsiModifierList modifierList = field.getModifierList(); if (modifierList == null || modifierList.hasModifierProperty(PsiModifier.STATIC) || @@ -54,12 +54,57 @@ protected String generateMethodBody() { modifierList.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { continue; } - result.append(returnObjName + ".set" + StringUtils.firstUpperCase(field.getName()) + "(" + parameterName + ".get" + StringUtils.firstUpperCase(field.getName()) + "());\n"); + result.append(generateFieldCopyLine(returnObjName, firstParameter.getName(), field)); } - result.append("return " + returnObjName + ";\n"); + result.append(generateReturnLine(returnObjName)); return result.toString(); } + /** + * 生成示例:{@code UserDTO userDTO = new UserDTO();} + * + * @param returnObjName + * @return + */ + @NotNull + private String generateObjectCreateLine(String returnObjName) { + return returnClassName + BLANK_SEPARATOR + returnObjName + "= new " + returnClassName + "();" + LINE_SEPARATOR; + } + + /** + * 生成示例:{@code userDTO.setId(user.getId());} + * + * @param returnObjName + * @param parameterName + * @param field + * @return + */ + @NotNull + private String generateFieldCopyLine(String returnObjName, String parameterName, PsiField field) { + return returnObjName + ".set" + StringUtils.firstUpperCase(field.getName()) + "(" + parameterName + ".get" + StringUtils.firstUpperCase(field.getName()) + "());" + LINE_SEPARATOR; + } + + /** + * 生成示例:{@code return userDTO;} + * + * @param returnObjName + * @return + */ + @NotNull + private String generateReturnLine(String returnObjName) { + return "return " + returnObjName + ";" + LINE_SEPARATOR; + } + + /** + * 生成示例:{@code if (user == null) {return null;}} + * + * @param parameterName + * @return + */ + private String generateNullCheck(String parameterName) { + return "if(" + parameterName + "==null){return null;}"; + } + private static String getReturnClassName(PsiMethod psiMethod) { PsiType returnType = psiMethod.getReturnType(); if (returnType == null) { @@ -93,8 +138,4 @@ private List getMethodModifies(PsiModifierList modifierList) { } return result; } - - private String generateNullCheck(String parameterName) { - return "if ( " + parameterName + "== null ){\nreturn null;\n}\n"; - } -} +} \ No newline at end of file From c78a0beb1e67115e344698b8647a4769bf9ffe6a Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 31 Jan 2021 11:27:37 +0800 Subject: [PATCH 02/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8F=92=E4=BB=B6BUG?= =?UTF-8?q?=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.修改GenerateO2O组件在方法上下文以外环境时的可见性问题 2.重构插件部分逻辑 3.新增插件logo --- object-helper.jar | Bin 15190 -> 17364 bytes resources/META-INF/plugin.xml | 7 +- .../common/constant/JavaSeparator.java | 25 ++++ .../objecthelper/common/util/PsiUtils.java | 119 ++++++++++++++++++ .../objecthelper/component/GenerateO2O.java | 36 +++--- .../method/AbstractMethodGenerator.java | 68 +++------- .../method/ObjectCopyMethodGenerator.java | 65 +++------- 7 files changed, 198 insertions(+), 122 deletions(-) create mode 100644 src/cn/bigcoder/plugin/objecthelper/common/constant/JavaSeparator.java create mode 100644 src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java diff --git a/object-helper.jar b/object-helper.jar index db816c1ab3105893f1ae4c60da59ee28005a072e..57c58878a257d397be35a21e893f1fb70201b329 100644 GIT binary patch delta 9963 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 iIl+5CakvN`a0eSHSV9;Dix`F&<{L5$%*2Wrhx zno<4^*)hf7=_ulGO=;BHK*BUs%>SB&mr23H==dOt)-Kjyb9ZYEehqF*C-V;<%JmlY zi1c1On_!TC0R&^bGi>HGh7>!}| z1R>l!<8o*EzH}dVd>&xm7=#z$aOeRwBqhNHm5btX((Xqvqm> zOKV4M$9iDcJ<0VUcG)s1<3}!_zxy1T2=bWT49(Uk(S@ZMD(gvhXD`Pq)XQfQ`Nf)lphaz62=AO&C z{0?z-r9V1?aE#^5$#|#qcGD)5C_G7k>)htB4d1gz$qOuU1cEB=#OO(GvkTc>svE8UQ6tK2~Lf4RwsO1n*j`gKbHRdJ$Z0~bopa9G3!P;qi#Q?9_maYAxdE~jC;$fANYE9{9Em#L=Q^4=Z4tBdu zzJW`x6h!Ub4Vo>fI_wtt4npRrX|74h(dY12{2y-0VoOxi#>3=h=4u@)y}3y2HOj^$)IV30 zoj+ZgBU0xJ>{l{O-nHAi<-{?~50PuvYw_FWV^4N0LX*mUPqoOP3n-kMG7^>rLKrT7(ybl2H9kYW~K8GcXX^OH3c*|8>U z$kSZx=+6-$Z;_!8y`_*mw9lVPn{3TH5UzT+pNr8Nz>tOHw_ogy!el|)PW~&m%l1T; zZ<5Hwibg>#juKM$-2A?N!%A{CRlf`!Y)r$7~L<^5H{W`!Jv zd95ij1DV)3tKyD)AH;kRAE~D9XQH4tCT56W0&dL2-ijgLH&*51ZsJvEF~CPBm|1o$21Hn5B7Tb(+CjURxy1{>gl4rTtRysPEJP# zTIhYMYc_OLP>*e1E0Abtg`td{5TQos&95P=av(cuf+WoiLxLfdha_QMM_d2I>#0vm z+EpFdZ$#7`DS`u5h3%LD2jPz}wacQWh#{%_m7_r2YvE_a;vLc<%!Q;aA5d*`66y>u zXI9dtcNU~M)W5MFKESqAtN{kqREr34b(BPj(Y=HkDd;EF{suZvAnC*_$s(WNn1@FWiayIS~?i! zRyjN!ak^p>>UxIUt4(bYh~Y(~hBubAC#|W1jsai_Qt~%NLqO=nM?i?npn$)n75Njc z@Zo8+2Y;hi0-f}KhTC)?$b%Q zI4&-+7gyy@y6Z6r?UcCe z>@`C+4=~fbwB(lzF=75W+I}zZ3ai`8v7=Z4$FY=9)(M)_vfG0E9kp={?7Gis3Pv{^ z74*DK4iDbn%p3)5sy9X`Ds&sz6{hFXQ&4j^#wm4E98n8F5U|r|6$i71cu!AIdE^1n z%*rkW$kCQ_^)mFD@R}7ULGX6Ygz(!Y;ezCKQbxSZ(l>L1-C*5cs?IY4ilwYbzl|z6 zFjO(FoRpR5s9xGhxhxexfLVMgsl?&d`z+>rYRfMw5^Mloz^~N+A1!s+Mi!6x1pm4h zmwReU5|_pF5O#`&&7a@49kOo>Pe1Rq`gYM`Exes|MuI8UfFO?iI$vp^M--;L7pR_d z$G>z`BVW9%%PnE4<27r^{4k{Y2FodJzWt@+iq?EK<ta{P6y_Fjs& zp#AG=OW_Q`t4dN|Us!Ggq3+ejlq9*RMpf-m^V(UIb%(AMe$GD^DUR zG7`4DC-MzsitFL$JnCITt>Na|LOovOO*+nY`wd3B;X`t>K__e)z8%IM2&FB(rNW)k z)$S#rg1Gc+EE%3ndp@f6j-O)(O+S|c3L@mN0*kj4j0x@DREs?+_g0=$l63T*f*xsj zioMAzF;=|bZhGhF>7cU`*!-E;=&`MpE|M^z9ll77Pnbhhtwbcs`Za2Qx^+!?LVWr= z68pJf>z-YgaYG*SkYtjZjQ4Co!e{+DJZ#WWNJ6~ikp@yf{8`6P=S^r4ZtWx+-mZ ze>s~p(BiXK!0^SCSszE|w>Ag&wwh_c#aoL0RH0PwO47)|Z$DCl$iu_0c8P>F@qbFI z#6xiVNvWnuzm(v->#OEu1hr?cs)hcn+9nljA93VoprY9;!K~~vhAQ#3I~8-PJdAmm z4PMX)S4w|87Dg$$=e0UC>v>3ED6@JWkMqNLia4Q?ENW+zP6jf+$02%MNQEOk z*s(6fE4^1arJU1tdGZGOXnL>61%2~Q|4RMvSDCeU#%7nGi(PvN5!rCxsB1CVF&hnDXBS zszvpk6jO64ur@@#5kJa`2Eivcm6RdE@7LDqp=eJO$@qtMTd}96z{}*iDPq{=Ga9VYQ&lf1g}j?_nf57cx2c|W@Y)7MB%p>t^NaJ}SW z(mEC2((ei9S01o_E4F-_eG0e3mZ;i<$^|iw^`AUC}wB zz`G4ypzRv5pbNfZx6XsxW1g}%yaT@7wpM!AgBz4BH-APh`|ell0^6C_iquLi)C4f? zqTI*baegjM$#dy#iQvTZ3=hU9e3dsP57Rv9wKrWOr=SGL92YvlT)u9#Jnnso-cVvE zV;Ui!GQxlR97T#6^6>Nt4GHqYmibhW9@`QsL1bcKL^gR8@3zFaT_;8sJqyj@!azWB zfc`R=?%c=sYH^B5Ko+W?oFs@w$FtI@KJMn>?qll5= z#)wSvNI}f~utHf)M)MM?OXW3^<^!@D1>&tb{_k(nif_$$h<{WtZ8h=&Y z1kg6H|L#axw1PWDYo|S4{PH^uIBo4X4RF0Ya%81NuL2!i3nM)~)~8Xkut}2LMQ>ixg9HANtl4TkyyaD2roMXa)tT*7=iU&l z)sqIX5To=}G>*B}MFah>@u325xi5L^5Y?bm>YL#1Wm`VG$id63NwQQ*JrPVWdW6-m z+UqW#{RCG9=3#G9Sw~P1=u|pD1(@xSg z!aiLt>rEE{oynm}YoA%7@?ff}q|RI_8MAWs7?_!w<&D^@Nm@F_*i&k?4@#IZ0cwhb z)rRMsdidFv(_=|au})@>qnm8LL}UpykvlaU?Pk7#zJkHQBDzUyUZ3pL80AwFCx0jE zZYfpgAxfSyHM@GW?bb*^IGSH7IPK5%JW$Cm_qu&P%rq5I56mOzJPlPea{atlSSZPT z^ON{dKC3g@(Z(W%M&ll|v313X&S;(fnVQjXMjwkB&By6YnX~ZG3F&M2oI=-!Uv}nd zq@5RW#KPM42Po*dW7P%67dP?IhMY9L?~4r%QY!m}7-V_WuwQelL8uK~?Zqm0T_{3Z z!7C055jjcZGozVy-ILt}g^ezPi$5ADObT9)$JKbCbw9hVuqxEqDHiIoVF&JXYlU=P zUWg#_d*WlT@4MFfZke;>)mbhU3Hk+rw0c>f#E+of@v67I}q!k1UxA!KR>gd&Sez20jquyLE1Jk2eQhElQ$9m5kDmMJTW) zN;rBdWU;rmYqur@o6~GHQ*p%+yXXx??b{f(u%AL=^50u;R0~AZ%wy!`w3JT4AB!#{ zd$%6V1BNy4i&c*HdkKRQw^#El$%dS`NF%GT%hTTAZ49&(_5+4bSQqvYJqDdH2cg)yZLwL(Z>aZHIu>bh4Ic-;wO6WfB=j zm~98Z!9eeJ|K`{>;*)vLXzv4kz^m8_JufJMaCH-US3_47*eo$tBbD~fwRn~n5h_~her)_^l@kCQZ5fnF3@7*NcBxT`Y7pH4GMbVH~BE>~`-Z>|bZ1(D&UuR*^-8bLf zw#6<*q`JB?GD0_M^SAV{%y2_}b^!z}Xvg+3)GU8e%-{{!sKLeFXnvyM1lad>c&^~r zeS?S9#FFkh3%QlBkl=h6akViC$9D%3*Pd%wlZ=qFqxWyTr9NIf{f8^F0iT4koatMN zA2>1wmpLH<3T4d4vDU|jn+gR&DFt4b16#k1OUfmEPZFDD1;iPBbEYIkJi!oL(S4?I za_1J#ekmhCaHA|*q4_Xx303t0)*)$kU!IT4^Rwe|cFdZ6{;Ujv`|}FsV4nq_5Y4;C z#Kc55Nt@n`Q*V(?xL{`Tq|z6ac*mG*_dtwFE^!LeFOV#T_>0 z8CD^{!Me#O;_AsTbpP;M{7Z;z!z;fsZ;<7tQ6@`VKVNuQK8(~Yj&{|ew6m;hmBkao zWW@7Z(3J;zkFTmHHq4H4C(~&!SHJF|SExGU#*tzSwh*-VC0KjltCIiqIl-u#fUWGn z9#^bM0M(W`61m;(mu*f`b8N*~1sQB^@UJ`mYuxous$)UFex?RmVNgNjY&=FWt*9AA zD}G>Hg;dTHol(oVcwFZW9HXCBq{0V~8)pD6YCrpb03;$FEngNT72b*+$!+ox<0uPc zTp+yNRK&#M!$|~LOX@Y6hca%0^sqF5nDuTksNoZy8gpvjQC-Q?RT`K%G~qpTLT9V)D?STj}KLEme`3*)MsA4 z6;QY2t07U<(k#d_lKlki-w*_`@j|^x97&FJs!q$2?Xzt9IeMw~riw22I}qe*U>&pi zFp5_>Ni?Y%ZFJm_ULe0HSy&ZD`OiH&|l)H<@M_S@o3L3|h-B zX;~k)F|d->!rd4qJYnu0Nk&q8PVBiI6AOJ>DnKu-BO%Tw5Fc^#TffJ^Zn&%sqmFO+FDZ2bPPz zta(S0rTFF&f=ePM!WrpV zGLjE^Cqzt>aZ_6|NMr<)fBVbQVmf++fxsc-i7x$N==b2+hUjDIYMc&}P-D%4a#qSm z_8=}4eHBBE2xoCGS~4W9n zZkgK6B`;S7ZhMJ4kcZ{9g?tOR3z#GS>ek02vQ74k{5Ri1hA=A9;2$pgR#CI_=i654lKiOOEh>H^Nf;|afX=ykQgL?B;<%n}xdZ^jJ zm1+x_yxoX%9V<2<`;}Er+jO@{9?UfL4$*%NCnU0j;J(6jm zU_RgB;K#u{qM$?xJO7vA1b82)8Ey!eIE=@k5t9CiM9&j)0>|&Ec0HskbF@$*SME8(neaoP*SPh?Jq5^j+T|)H_~g zU6&Ym)9A_!7Ue}0K$oBUhYy4KBRRtfUe0nY>zwAC(Z^nFK+MJ*aG(N#c){Jip}}~y z-sR8}=PI;+`I6`FMZOt|2jn3kAgI)a2pD1@|EU1OH^fij(GvLZbqT5eAeW@VUqs}B zhe(RRKcis4(}?&4v{Hx62I=BqZR} zR6#@{M);pvvGzZCdcJ?q69@>d065L4PM1d0{4+)N6O}e=gZOK Q68+Ht{h@Y_Uj0@4KLe@{p#T5? diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index b5d4b8b..db36db8 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -1,7 +1,7 @@ cn.bigcoder.plugin.objecthelper ObjectHelper - 1.0.1 + 1.0.2 HearingSmile Fix bug:fixed bugs in exception scenarios.Improve plugin compatibility. +
  • Fix bug:Fixed location visibility of GenerateO2O components outside of methods
  • +
  • Add logo
  • ]]>
    @@ -28,7 +29,7 @@ - + diff --git a/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaSeparator.java b/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaSeparator.java new file mode 100644 index 0000000..cbb4d39 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaSeparator.java @@ -0,0 +1,25 @@ +package cn.bigcoder.plugin.objecthelper.common.constant; + +/** + * @author: Jindong.Tian + * @date: 2021-01-31 + **/ +public class JavaSeparator { + public static final String EMPTY_BODY = ""; + public static final String BLANK_SEPARATOR = " "; + public static final String LINE_SEPARATOR = "\n"; + public static final String COMMA_SEPARATOR = ","; + public static final String SEMICOLON_SEPARATOR = ";\n"; + + public static final String VOID = "void"; + + public static final String PARENTHESIS_OPEN = "("; + public static final String PARENTHESIS_CLOSE = ")"; + public static final String PARENTHESIS = "()"; + public static final String BRACE_OPEN = "{"; + public static final String BRACE_CLOSE = "}"; + public static final String BRACE = "{}"; + public static final String BRACKET_OPEN = "["; + public static final String BRACKET_CLOSE = "]"; + public static final String BRACKET = "[]"; +} diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java new file mode 100644 index 0000000..3aef871 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java @@ -0,0 +1,119 @@ +package cn.bigcoder.plugin.objecthelper.common.util; + +import cn.bigcoder.plugin.objecthelper.common.constant.JavaSeparator; +import cn.bigcoder.plugin.objecthelper.common.enums.JavaModify; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.LangDataKeys; +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.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author: Jindong.Tian + * @date: 2021-01-31 + **/ +public class PsiUtils { + + /** + * 获取光标所在处的{@code PsiElement} + * @param anActionEvent + * @return + */ + public static PsiElement getCursorPsiElement(AnActionEvent anActionEvent) { + PsiFile psiFile = anActionEvent.getData(LangDataKeys.PSI_FILE); + Editor editor = anActionEvent.getData(PlatformDataKeys.EDITOR); + if (psiFile == null || editor == null) { + anActionEvent.getPresentation().setEnabled(false); + return null; + } + //获取当前光标处的PsiElement + int offset = editor.getCaretModel().getOffset(); + return psiFile.findElementAt(offset); + } + + /** + * 根据{@code PsiType}获取对应的{@code PsiClass} + * + * @param psiType + * @param project + * @return + */ + public static PsiClass getPsiClass(PsiType psiType, Project project) { + if (psiType == null) { + return null; + } + //带package的class名称 + String parameterClassWithPackage = psiType.getInternalCanonicalText(); + //为了解析字段,这里需要加载参数的class + JavaPsiFacade facade = JavaPsiFacade.getInstance(project); + return facade.findClass(parameterClassWithPackage, GlobalSearchScope.allScope(project)); + } + + /** + * 获取方法名称 + * @param psiMethod + * @return + */ + public static String getMethodName(PsiMethod psiMethod) { + if (psiMethod == null) { + return null; + } + return psiMethod.getName(); + } + + /** + * 获取方法返回名称 + * @param psiMethod + * @return + */ + @NotNull + public static String getMethodReturnClassName(PsiMethod psiMethod) { + PsiType returnType = psiMethod.getReturnType(); + if (returnType == null) { + return JavaSeparator.VOID; + } + return returnType.getPresentableText(); + } + + /** + * 获取方法的参数列表 + * @param psiMethod + * @return + */ + @NotNull + public static List getPsiParameters(PsiMethod psiMethod){ + return Arrays.asList(psiMethod.getParameterList().getParameters()); + } + + /** + * 获取方法的修饰符 + * + * @param modifierList + * @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); + } + if (modifierList.hasModifierProperty(JavaModify.STATIC.getName())) { + result.add(JavaModify.STATIC); + } + if (modifierList.hasModifierProperty(JavaModify.FINAL.getName())) { + result.add(JavaModify.FINAL); + } + return result; + } +} diff --git a/src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java b/src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java index c1444f4..b07d666 100644 --- a/src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java +++ b/src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java @@ -1,16 +1,17 @@ -package cn.bigcoder.plugin.objecthelper; +package cn.bigcoder.plugin.objecthelper.component; +import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; 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.actionSystem.LangDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.command.WriteCommandAction; -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.PsiElement; +import com.intellij.psi.PsiElementFactory; +import com.intellij.psi.PsiMethod; import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; public class GenerateO2O extends AnAction { @@ -21,6 +22,15 @@ public void actionPerformed(AnActionEvent anActionEvent) { }); } + @Override + public void update(@NotNull AnActionEvent anActionEvent) { + // 如果当前光标不在方法中,则不显示GernerateO2O组件 + if (getPsiMethodFromContext(anActionEvent) == null) { + anActionEvent.getPresentation().setEnabled(false); + } + super.update(anActionEvent); + } + private void generateO2O(PsiMethod psiMethod) { if (psiMethod == null) { return; @@ -34,22 +44,10 @@ private void generateO2O(PsiMethod psiMethod) { } private PsiMethod getPsiMethodFromContext(AnActionEvent e) { - PsiElement elementAt = getPsiElement(e); + PsiElement elementAt = PsiUtils.getCursorPsiElement(e); if (elementAt == null) { return null; } return PsiTreeUtil.getParentOfType(elementAt, PsiMethod.class); } - - private PsiElement getPsiElement(AnActionEvent e) { - PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE); - Editor editor = e.getData(PlatformDataKeys.EDITOR); - if (psiFile == null || editor == null) { - e.getPresentation().setEnabled(false); - return null; - } - //获取当前光标处的PsiElement - int offset = editor.getCaretModel().getOffset(); - return psiFile.findElementAt(offset); - } } diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java index ab47bba..330e19c 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java +++ b/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java @@ -1,14 +1,17 @@ package cn.bigcoder.plugin.objecthelper.generator.method; -import cn.bigcoder.plugin.objecthelper.common.enums.JavaModify; -import cn.bigcoder.plugin.objecthelper.generator.Generator; +import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; -import com.intellij.psi.PsiClass; +import cn.bigcoder.plugin.objecthelper.generator.Generator; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiParameter; -import org.apache.commons.collections.CollectionUtils; import java.util.List; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaSeparator.*; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.*; + /** * @author: Jindong.Tian * @date: 2021-01-09 @@ -16,34 +19,9 @@ public abstract class AbstractMethodGenerator implements Generator { protected static final int FIRST_INDEX = 0; - protected static final String EMPTY_BODY = ""; - protected static final String BLANK_SEPARATOR = " "; - protected static final String LINE_SEPARATOR = "\n"; - protected static final String COMMA_SEPARATOR = ","; - - protected static final String VOID_KEYWORD = "void"; - - /** - * 方法修饰符 - */ - protected List methodModifies; - /** - * 方法返回类型名称 - */ - protected String returnClassName; - /** - * 方法名称 - */ - protected String methodName; - /** - * 方法参数 - */ - protected List parameters; - /** - * 方法参数 - */ - protected List parameterClass; + protected Project project; + protected PsiMethod psiMethod; public String generate() { StringBuilder result = generateMethodFirstLine() @@ -52,28 +30,20 @@ public String generate() { return result.toString(); } + abstract String generateMethodBody(); + protected StringBuilder generateMethodFirstLine() { StringBuilder builder = new StringBuilder(); - methodModifies.forEach(e -> builder.append(e.getName()).append(BLANK_SEPARATOR)); - builder.append(returnClassName + BLANK_SEPARATOR) - .append(methodName) - .append("(") - .append(StringUtils.join(parameters, PsiParameter::getText, COMMA_SEPARATOR)) - .append("){"); + PsiUtils.getMethodModifies(psiMethod.getModifierList()).forEach(e -> builder.append(e.getName()).append(BLANK_SEPARATOR)); + builder.append(getMethodReturnClassName(psiMethod) + BLANK_SEPARATOR) + .append(getMethodName(psiMethod)) + .append(PARENTHESIS_OPEN) + .append(StringUtils.join(getParameters(), PsiParameter::getText, COMMA_SEPARATOR)) + .append(PARENTHESIS_CLOSE + BRACE_OPEN); return builder; } - protected boolean hasModifierProperty(String modify) { - if (CollectionUtils.isEmpty(methodModifies)) { - return false; - } - for (JavaModify methodModify : methodModifies) { - if (methodModify.getName().equals(modify)) { - return true; - } - } - return false; + protected List getParameters() { + return getPsiParameters(psiMethod); } - - abstract String generateMethodBody(); } diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java index 0746eda..d2e59a0 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java +++ b/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java @@ -1,16 +1,13 @@ package cn.bigcoder.plugin.objecthelper.generator.method; -import cn.bigcoder.plugin.objecthelper.common.enums.JavaModify; import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; import org.apache.commons.collections.CollectionUtils; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaSeparator.*; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getMethodReturnClassName; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClass; /** * @author: Jindong.Tian @@ -19,11 +16,11 @@ public class ObjectCopyMethodGenerator extends AbstractMethodGenerator { private void init(PsiMethod psiMethod) { - super.methodName = psiMethod.getName(); - super.returnClassName = getReturnClassName(psiMethod); - super.parameters = Arrays.asList(psiMethod.getParameterList().getParameters()); - super.parameterClass = super.parameters.stream().map(e -> transferPsiClass(e, psiMethod)).collect(Collectors.toList()); - super.methodModifies = getMethodModifies(psiMethod.getModifierList()); + if (psiMethod == null) { + return; + } + super.project = psiMethod.getProject(); + super.psiMethod = psiMethod; } public static ObjectCopyMethodGenerator getInstance(PsiMethod psiMethod) { @@ -34,13 +31,13 @@ public static ObjectCopyMethodGenerator getInstance(PsiMethod psiMethod) { @Override protected String generateMethodBody() { - if (CollectionUtils.isEmpty(parameters) || VOID_KEYWORD.equals(returnClassName)) { + if (CollectionUtils.isEmpty(getParameters()) || VOID.equals(getMethodReturnClassName(psiMethod))) { return EMPTY_BODY; } StringBuilder result = new StringBuilder(); - String returnObjName = StringUtils.firstLowerCase(returnClassName); - PsiParameter firstParameter = parameters.get(FIRST_INDEX); - PsiClass firstParameterClass = parameterClass.get(FIRST_INDEX); + String returnObjName = StringUtils.firstLowerCase(getMethodReturnClassName(psiMethod)); + PsiParameter firstParameter = getParameters().get(FIRST_INDEX); + PsiClass firstParameterClass = getPsiClass(firstParameter.getType(), project); if (firstParameterClass == null) { return EMPTY_BODY; } @@ -68,7 +65,7 @@ protected String generateMethodBody() { */ @NotNull private String generateObjectCreateLine(String returnObjName) { - return returnClassName + BLANK_SEPARATOR + returnObjName + "= new " + returnClassName + "();" + LINE_SEPARATOR; + return getMethodReturnClassName(psiMethod) + BLANK_SEPARATOR + returnObjName + "= new " + getMethodReturnClassName(psiMethod) + "();" + LINE_SEPARATOR; } /** @@ -92,7 +89,7 @@ private String generateFieldCopyLine(String returnObjName, String parameterName, */ @NotNull private String generateReturnLine(String returnObjName) { - return "return " + returnObjName + ";" + LINE_SEPARATOR; + return "return " + returnObjName + SEMICOLON_SEPARATOR; } /** @@ -104,38 +101,4 @@ private String generateReturnLine(String returnObjName) { private String generateNullCheck(String parameterName) { return "if(" + parameterName + "==null){return null;}"; } - - private static String getReturnClassName(PsiMethod psiMethod) { - PsiType returnType = psiMethod.getReturnType(); - if (returnType == null) { - return "void"; - } - return returnType.getPresentableText(); - } - - private static PsiClass transferPsiClass(PsiParameter psiParameter, PsiMethod psiMethod) { - //带package的class名称 - String parameterClassWithPackage = psiParameter.getType().getInternalCanonicalText(); - //为了解析字段,这里需要加载参数的class - JavaPsiFacade facade = JavaPsiFacade.getInstance(psiMethod.getProject()); - return facade.findClass(parameterClassWithPackage, GlobalSearchScope.allScope(psiMethod.getProject())); - } - - private 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); - } - if (modifierList.hasModifierProperty(JavaModify.STATIC.getName())) { - result.add(JavaModify.STATIC); - } - if (modifierList.hasModifierProperty(JavaModify.FINAL.getName())) { - result.add(JavaModify.FINAL); - } - return result; - } } \ No newline at end of file From d97ed8b0b39157cc8d34c74f843b9a9f94abbf4f Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Mon, 8 Feb 2021 21:56:11 +0800 Subject: [PATCH 03/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8F=92=E4=BB=B6BUG:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.修复GenerateO2O组件不能生成父类中字段代码的问题 2.优化插件使用体验 --- README.md | 4 + object-helper.jar | Bin 17364 -> 18679 bytes resources/META-INF/plugin.xml | 7 +- .../{component => action}/GenerateO2O.java | 37 ++++++--- .../{JavaSeparator.java => JavaKeyWord.java} | 2 +- .../objecthelper/common/util/PsiUtils.java | 59 ++++++++++++- .../method/AbstractMethodGenerator.java | 26 +++++- .../method/ObjectCopyMethodGenerator.java | 78 ++++++++++++------ 8 files changed, 164 insertions(+), 49 deletions(-) rename src/cn/bigcoder/plugin/objecthelper/{component => action}/GenerateO2O.java (60%) rename src/cn/bigcoder/plugin/objecthelper/common/constant/{JavaSeparator.java => JavaKeyWord.java} (96%) diff --git a/README.md b/README.md index 357b0ff..d77a699 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ # object-helper-plugin +![](https://img.shields.io/badge/version-v1.0.2-blue) +![](https://img.shields.io/badge/license-Apache%202-red) +![](https://img.shields.io/badge/download-100%2B-green) + JetBrains Intellij IDEA Obejct辅助插件,包含以下功能: - 对象拷贝 diff --git a/object-helper.jar b/object-helper.jar index 57c58878a257d397be35a21e893f1fb70201b329..9dc2fcbbd22b3fb937ece06ef00d37053e900f1d 100644 GIT binary patch delta 11286 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 z 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 cn.bigcoder.plugin.objecthelper ObjectHelper - 1.0.2 + 1.0.3 HearingSmile Fix bug:Fixed location visibility of GenerateO2O components outside of methods -
  • Add logo
  • +
  • Fix bug:Fixed parent field not being generated
  • ]]>
    @@ -29,7 +28,7 @@ - + diff --git a/src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java b/src/cn/bigcoder/plugin/objecthelper/action/GenerateO2O.java similarity index 60% rename from src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java rename to src/cn/bigcoder/plugin/objecthelper/action/GenerateO2O.java index b07d666..7bd4385 100644 --- a/src/cn/bigcoder/plugin/objecthelper/component/GenerateO2O.java +++ b/src/cn/bigcoder/plugin/objecthelper/action/GenerateO2O.java @@ -1,32 +1,33 @@ -package cn.bigcoder.plugin.objecthelper.component; +package cn.bigcoder.plugin.objecthelper.action; import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; +import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; 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.PsiElement; import com.intellij.psi.PsiElementFactory; import com.intellij.psi.PsiMethod; -import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.*; + public class GenerateO2O extends AnAction { @Override public void actionPerformed(AnActionEvent anActionEvent) { WriteCommandAction.runWriteCommandAction(anActionEvent.getProject(), () -> { - generateO2O(getPsiMethodFromContext(anActionEvent)); + generateO2O(PsiUtils.getCursorPsiMethod(anActionEvent)); }); } @Override public void update(@NotNull AnActionEvent anActionEvent) { // 如果当前光标不在方法中,则不显示GernerateO2O组件 - if (getPsiMethodFromContext(anActionEvent) == null) { - anActionEvent.getPresentation().setEnabled(false); + if (!check(PsiUtils.getCursorPsiMethod(anActionEvent))) { + PsiUtils.setActionDisabled(anActionEvent); } super.update(anActionEvent); } @@ -37,17 +38,31 @@ private void generateO2O(PsiMethod psiMethod) { } // 初始化生成器 Generator generator = ObjectCopyMethodGenerator.getInstance(psiMethod); + String methodCode = generator.generate(); + if (StringUtils.isEmpty(methodCode)) { + return; + } PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(psiMethod.getProject()); // 生成新的PsiMethod PsiMethod toMethod = elementFactory.createMethodFromText(generator.generate(), psiMethod); psiMethod.replace(toMethod); } - private PsiMethod getPsiMethodFromContext(AnActionEvent e) { - PsiElement elementAt = PsiUtils.getCursorPsiElement(e); - if (elementAt == null) { - return null; + /** + * 检查当前光标 + * 1. 是否在方法中 + * 2. 方法是否有入参 + * 3. 方法是否有返回值 + * + * @param psiMethod + * @return + */ + private boolean check(PsiMethod psiMethod) { + if (psiMethod == null + || PsiUtils.getPsiParameters(psiMethod).size() == 0 + || VOID.equals(PsiUtils.getMethodReturnClassName(psiMethod))) { + return false; } - return PsiTreeUtil.getParentOfType(elementAt, PsiMethod.class); + return true; } } diff --git a/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaSeparator.java b/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaKeyWord.java similarity index 96% rename from src/cn/bigcoder/plugin/objecthelper/common/constant/JavaSeparator.java rename to src/cn/bigcoder/plugin/objecthelper/common/constant/JavaKeyWord.java index cbb4d39..2483e08 100644 --- a/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaSeparator.java +++ b/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaKeyWord.java @@ -4,7 +4,7 @@ * @author: Jindong.Tian * @date: 2021-01-31 **/ -public class JavaSeparator { +public class JavaKeyWord { public static final String EMPTY_BODY = ""; public static final String BLANK_SEPARATOR = " "; public static final String LINE_SEPARATOR = "\n"; diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java index 3aef871..54789dd 100644 --- a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java +++ b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java @@ -1,6 +1,6 @@ package cn.bigcoder.plugin.objecthelper.common.util; -import cn.bigcoder.plugin.objecthelper.common.constant.JavaSeparator; +import cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord; import cn.bigcoder.plugin.objecthelper.common.enums.JavaModify; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.LangDataKeys; @@ -9,6 +9,8 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiTreeUtil; +import org.apache.commons.compress.utils.Lists; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -21,8 +23,22 @@ **/ public class PsiUtils { + /** + * 获取光标处上下文的{@code PsiMethod} + * @param actionEvent + * @return + */ + public static PsiMethod getCursorPsiMethod(AnActionEvent actionEvent) { + PsiElement elementAt = PsiUtils.getCursorPsiElement(actionEvent); + if (elementAt == null) { + return null; + } + return PsiTreeUtil.getParentOfType(elementAt, PsiMethod.class); + } + /** * 获取光标所在处的{@code PsiElement} + * * @param anActionEvent * @return */ @@ -38,6 +54,14 @@ public static PsiElement getCursorPsiElement(AnActionEvent anActionEvent) { return psiFile.findElementAt(offset); } + /** + * 设置当前组件不可用(不显示) + * @param anActionEvent + */ + public static void setActionDisabled(AnActionEvent anActionEvent){ + anActionEvent.getPresentation().setEnabled(false); + } + /** * 根据{@code PsiType}获取对应的{@code PsiClass} * @@ -58,6 +82,7 @@ public static PsiClass getPsiClass(PsiType psiType, Project project) { /** * 获取方法名称 + * * @param psiMethod * @return */ @@ -70,6 +95,7 @@ public static String getMethodName(PsiMethod psiMethod) { /** * 获取方法返回名称 + * * @param psiMethod * @return */ @@ -77,18 +103,19 @@ public static String getMethodName(PsiMethod psiMethod) { public static String getMethodReturnClassName(PsiMethod psiMethod) { PsiType returnType = psiMethod.getReturnType(); if (returnType == null) { - return JavaSeparator.VOID; + return JavaKeyWord.VOID; } return returnType.getPresentableText(); } /** * 获取方法的参数列表 + * * @param psiMethod * @return */ @NotNull - public static List getPsiParameters(PsiMethod psiMethod){ + public static List getPsiParameters(PsiMethod psiMethod) { return Arrays.asList(psiMethod.getParameterList().getParameters()); } @@ -116,4 +143,30 @@ public static List getMethodModifies(PsiModifierList modifierList) { } return result; } + + /** + * 获取{@code PsiClass}所有字段(包含父类字段) + * + * @param psiClass + * @return + */ + @NotNull + public static List getAllPsiFields(PsiClass psiClass) { + List result = Lists.newArrayList(); + recursiveAllFields(psiClass, result); + return result; + } + + /** + * 递归获取类中所有字段 + * @param psiClass + * @param psiFields + */ + private static void recursiveAllFields(PsiClass psiClass, List psiFields) { + if (psiClass == null) { + return; + } + psiFields.addAll(Arrays.asList(psiClass.getFields())); + recursiveAllFields(psiClass.getSuperClass(), psiFields); + } } diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java index 330e19c..a3e08c8 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java +++ b/src/cn/bigcoder/plugin/objecthelper/generator/method/AbstractMethodGenerator.java @@ -6,10 +6,11 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiParameter; +import org.apache.commons.collections.CollectionUtils; import java.util.List; -import static cn.bigcoder.plugin.objecthelper.common.constant.JavaSeparator.*; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.*; import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.*; /** @@ -24,14 +25,15 @@ public abstract class AbstractMethodGenerator implements Generator { protected PsiMethod psiMethod; public String generate() { + if (!check()) { + return null; + } StringBuilder result = generateMethodFirstLine() .append(generateMethodBody()) .append("}"); return result.toString(); } - abstract String generateMethodBody(); - protected StringBuilder generateMethodFirstLine() { StringBuilder builder = new StringBuilder(); PsiUtils.getMethodModifies(psiMethod.getModifierList()).forEach(e -> builder.append(e.getName()).append(BLANK_SEPARATOR)); @@ -43,6 +45,24 @@ protected StringBuilder generateMethodFirstLine() { return builder; } + /** + * 生成方法体 + * @return + */ + abstract String generateMethodBody(); + + /** + * 检查是否具备生成方法所需要的环境 + * + * @return true代表校验通过 + */ + protected boolean check() { + if (CollectionUtils.isEmpty(getParameters()) || VOID.equals(getMethodReturnClassName(psiMethod))) { + return false; + } + return true; + } + protected List getParameters() { return getPsiParameters(psiMethod); } diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java index d2e59a0..921e9d7 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java +++ b/src/cn/bigcoder/plugin/objecthelper/generator/method/ObjectCopyMethodGenerator.java @@ -1,11 +1,11 @@ package cn.bigcoder.plugin.objecthelper.generator.method; +import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; import com.intellij.psi.*; -import org.apache.commons.collections.CollectionUtils; import org.jetbrains.annotations.NotNull; -import static cn.bigcoder.plugin.objecthelper.common.constant.JavaSeparator.*; +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; @@ -15,12 +15,27 @@ **/ public class ObjectCopyMethodGenerator extends AbstractMethodGenerator { + /** + * 方法第一个参数名称 + */ + private String firstParameterName; + /** + * 方法返回局部变量名称 + */ + private String returnObjName; + private void init(PsiMethod psiMethod) { if (psiMethod == null) { return; } 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) { @@ -29,21 +44,17 @@ public static ObjectCopyMethodGenerator getInstance(PsiMethod psiMethod) { return objectCopyMethodGenerator; } + /** + * 此方法中不应该存在判空的操作,依赖环境的建议重写父类的check方法,在生成早期拦截异常情况 + * + * @return + */ @Override protected String generateMethodBody() { - if (CollectionUtils.isEmpty(getParameters()) || VOID.equals(getMethodReturnClassName(psiMethod))) { - return EMPTY_BODY; - } StringBuilder result = new StringBuilder(); - String returnObjName = StringUtils.firstLowerCase(getMethodReturnClassName(psiMethod)); - PsiParameter firstParameter = getParameters().get(FIRST_INDEX); - PsiClass firstParameterClass = getPsiClass(firstParameter.getType(), project); - if (firstParameterClass == null) { - return EMPTY_BODY; - } - result.append(generateNullCheck(firstParameter.getName())); - result.append(generateObjectCreateLine(returnObjName)); - for (PsiField field : firstParameterClass.getFields()) { + result.append(generateNullCheck()); + result.append(generateObjectCreateLine()); + for (PsiField field : PsiUtils.getAllPsiFields(getFirstParameterClass())) { PsiModifierList modifierList = field.getModifierList(); if (modifierList == null || modifierList.hasModifierProperty(PsiModifier.STATIC) || @@ -51,54 +62,67 @@ protected String generateMethodBody() { modifierList.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { continue; } - result.append(generateFieldCopyLine(returnObjName, firstParameter.getName(), field)); + result.append(generateFieldCopyLine(field)); } - result.append(generateReturnLine(returnObjName)); + result.append(generateReturnLine()); return result.toString(); } /** * 生成示例:{@code UserDTO userDTO = new UserDTO();} * - * @param returnObjName * @return */ @NotNull - private String generateObjectCreateLine(String returnObjName) { + private String generateObjectCreateLine() { return getMethodReturnClassName(psiMethod) + BLANK_SEPARATOR + returnObjName + "= new " + getMethodReturnClassName(psiMethod) + "();" + LINE_SEPARATOR; } /** * 生成示例:{@code userDTO.setId(user.getId());} * - * @param returnObjName - * @param parameterName * @param field * @return */ @NotNull - private String generateFieldCopyLine(String returnObjName, String parameterName, PsiField field) { - return returnObjName + ".set" + StringUtils.firstUpperCase(field.getName()) + "(" + parameterName + ".get" + StringUtils.firstUpperCase(field.getName()) + "());" + LINE_SEPARATOR; + private String generateFieldCopyLine(PsiField field) { + return returnObjName + ".set" + StringUtils.firstUpperCase(field.getName()) + "(" + firstParameterName + ".get" + StringUtils.firstUpperCase(field.getName()) + "());" + LINE_SEPARATOR; } /** * 生成示例:{@code return userDTO;} * - * @param returnObjName * @return */ @NotNull - private String generateReturnLine(String returnObjName) { + private String generateReturnLine() { return "return " + returnObjName + SEMICOLON_SEPARATOR; } /** * 生成示例:{@code if (user == null) {return null;}} * - * @param parameterName * @return */ - private String generateNullCheck(String parameterName) { - return "if(" + parameterName + "==null){return null;}"; + private String generateNullCheck() { + return "if(" + getFirstParameter().getName() + "==null){return null;}"; + } + + /** + * 获取参数列表第一个参数的{@code PsiParameter} + * + * @return + */ + private PsiParameter getFirstParameter() { + return getParameters().get(FIRST_INDEX); + } + + /** + * 获取参数列表第一个参数的{@code PsiClass} + * + * @return + */ + private PsiClass getFirstParameterClass() { + return getPsiClass(getFirstParameter().getType(), project); } } \ No newline at end of file From abfcfcac729eb40c9ceb7d9c16b93051d2bee2a3 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Wed, 10 Feb 2021 10:26:11 +0800 Subject: [PATCH 04/21] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d77a699..e7f5c52 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # object-helper-plugin -![](https://img.shields.io/badge/version-v1.0.2-blue) +![](https://img.shields.io/badge/version-v1.0.3-blue) ![](https://img.shields.io/badge/license-Apache%202-red) ![](https://img.shields.io/badge/download-100%2B-green) From a85a616ff7dc064e72500ea4e6c918a25d56f5c1 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 27 Feb 2021 22:54:23 +0800 Subject: [PATCH 05/21] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=9B=B4=E6=94=B9=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=EF=BC=9A=201.=E6=96=B0=E5=A2=9EJava=E7=B1=BB?= =?UTF-8?q?=E8=BD=ACJSON=E5=8A=9F=E8=83=BD=202.=E5=B0=86GenerateO2O?= =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BAObject=20Copy=20Method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 13 +- object-helper.jar | Bin 18679 -> 26588 bytes resources/META-INF/plugin.xml | 26 +++- .../action/ClassToFormatJsonAction.java | 16 ++ .../action/ClassToJsonAction.java | 45 ++++++ ...teO2O.java => ObjectCopyMethodAction.java} | 6 +- .../common/util/NotificationUtils.java | 30 ++++ .../common/util/PsiTypeUtils.java | 142 ++++++++++++++++++ .../objecthelper/common/util/PsiUtils.java | 45 +++++- .../objecthelper/generator/Generator.java | 2 +- .../generator/json/ClassJsonGenerator.java | 105 +++++++++++++ 11 files changed, 411 insertions(+), 19 deletions(-) create mode 100644 src/cn/bigcoder/plugin/objecthelper/action/ClassToFormatJsonAction.java create mode 100644 src/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java rename src/cn/bigcoder/plugin/objecthelper/action/{GenerateO2O.java => ObjectCopyMethodAction.java} (93%) create mode 100644 src/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java create mode 100644 src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java create mode 100644 src/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java diff --git a/README.md b/README.md index e7f5c52..14e1f06 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,15 @@ # object-helper-plugin -![](https://img.shields.io/badge/version-v1.0.3-blue) +![](https://img.shields.io/badge/version-v1.1.0-blue) ![](https://img.shields.io/badge/license-Apache%202-red) -![](https://img.shields.io/badge/download-100%2B-green) +![](https://img.shields.io/badge/size-28%20kB-yellowgreen) +![](https://img.shields.io/badge/download-200%2B-green) -JetBrains Intellij IDEA Obejct辅助插件,包含以下功能: +JetBrains Intellij IDEA Object插件,包含以下功能: - 对象拷贝 - ![](https://image.bigcoder.cn/6d6af6fd-255c-4d32-83bb-85b39280460d.gif) + ![](https://image.bigcoder.cn/7fce876e-fa94-4780-bb14-584068c35963.gif) -- … \ No newline at end of file +- Java类转JSON + + ![](https://image.bigcoder.cn/20210227223302.gif) \ No newline at end of file diff --git a/object-helper.jar b/object-helper.jar index 9dc2fcbbd22b3fb937ece06ef00d37053e900f1d..29d71419fa3e9e5063bebbc01688f8d61cb01600 100644 GIT binary patch delta 16368 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
      UYpD1WK^dOnK4PzfT!Ux-8L e?|&7He<;1G07oQ<5b;3pKzx2}D@onocmEG&=I+t} delta 8688 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 diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index e1421f8..6d1d25a 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -1,17 +1,20 @@ cn.bigcoder.plugin.objecthelper ObjectHelper - 1.0.3 - HearingSmile + 1.1.0 + HearingSmile GitHub
    1. Copy the object
    2. - + +
    3. Class to JSON
    4. + ]]>
      Fix bug:Fixed parent field not being generated +
    5. New feature:Added the ability to quickly convert Java classes to JSON
    6. +
    7. Update feature:Rename GenerateO2O to Object Method Copy
    8. ]]>
      @@ -28,9 +31,20 @@ - + + + + + + + +
      \ No newline at end of file diff --git a/src/cn/bigcoder/plugin/objecthelper/action/ClassToFormatJsonAction.java b/src/cn/bigcoder/plugin/objecthelper/action/ClassToFormatJsonAction.java new file mode 100644 index 0000000..383ea56 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/action/ClassToFormatJsonAction.java @@ -0,0 +1,16 @@ +package cn.bigcoder.plugin.objecthelper.action; + +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.psi.PsiClass; + +public class ClassToFormatJsonAction extends ClassToJsonAction { + + @Override + protected Generator getGenerator(PsiClass psiClass) { + Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); + return ClassJsonGenerator.getInstance(psiClass, gson); + } +} diff --git a/src/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java b/src/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java new file mode 100644 index 0000000..7619892 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java @@ -0,0 +1,45 @@ +package cn.bigcoder.plugin.objecthelper.action; + +import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; +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 { + + @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(), "JSON字符串成功置入剪贴板:
      " + json); + } + + @Override + public void update(@NotNull AnActionEvent anActionEvent) { + // 如果当前光标不在方法中,则不显示ConvertToJson组件 + if (getOperatePsiClass(anActionEvent) == null) { + setActionInvisible(anActionEvent); + } + super.update(anActionEvent); + } + + protected Generator getGenerator(PsiClass psiClass) { + Gson gson = new GsonBuilder().serializeNulls().create(); + return ClassJsonGenerator.getInstance(psiClass, gson); + } +} diff --git a/src/cn/bigcoder/plugin/objecthelper/action/GenerateO2O.java b/src/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java similarity index 93% rename from src/cn/bigcoder/plugin/objecthelper/action/GenerateO2O.java rename to src/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java index 7bd4385..2ab5a9d 100644 --- a/src/cn/bigcoder/plugin/objecthelper/action/GenerateO2O.java +++ b/src/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java @@ -12,9 +12,9 @@ import com.intellij.psi.PsiMethod; import org.jetbrains.annotations.NotNull; -import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.*; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.VOID; -public class GenerateO2O extends AnAction { +public class ObjectCopyMethodAction extends AnAction { @Override public void actionPerformed(AnActionEvent anActionEvent) { @@ -25,7 +25,7 @@ public void actionPerformed(AnActionEvent anActionEvent) { @Override public void update(@NotNull AnActionEvent anActionEvent) { - // 如果当前光标不在方法中,则不显示GernerateO2O组件 + // 如果当前光标不在方法中,则不显示Object Copy组件 if (!check(PsiUtils.getCursorPsiMethod(anActionEvent))) { PsiUtils.setActionDisabled(anActionEvent); } diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java b/src/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java new file mode 100644 index 0000000..78b2453 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/common/util/NotificationUtils.java @@ -0,0 +1,30 @@ +package cn.bigcoder.plugin.objecthelper.common.util; + +import com.intellij.notification.NotificationDisplayType; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.project.Project; + +/** + * @author: Jindong.Tian + * @date: 2021-02-11 + **/ +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); + + public static void notifyInfo(Project project, String content) { + NOTIFICATION_GROUP.createNotification(content, NotificationType.INFORMATION).notify(project); + } + + public static void notifyWarning(Project project, String content) { + NOTIFICATION_GROUP.createNotification(content, NotificationType.WARNING).notify(project); + } + + public static void notifyError(Project project, String content) { + NOTIFICATION_GROUP.createNotification(content, NotificationType.ERROR).notify(project); + } +} diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java new file mode 100644 index 0000000..8cf8361 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java @@ -0,0 +1,142 @@ +package cn.bigcoder.plugin.objecthelper.common.util; + +import com.intellij.psi.PsiArrayType; +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; + +/** + * @author: Jindong.Tian + * @date: 2021-02-12 + **/ +public class PsiTypeUtils { + private static final String STRING_TYPE = "java.lang.String"; + private static final String INTEGER_TYPE = "java.lang.Integer"; + private static final String LONG_TYPE = "java.lang.Long"; + private static final String SHORT_TYPE = "java.lang.Short"; + private static final String BYTE_TYPE = "java.lang.Byte"; + private static final String DOUBLE_TYPE = "java.lang.Double"; + private static final String FLOAT_TYPE = "java.lang.Float"; + private static final String DATE_TYPE = "java.util.Date"; + private static final String LOCAL_DATE_TYPE = "java.time.LocalDate"; + private static final String LOCAL_DATE_TIME_TYPE = "java.time.LocalDateTime"; + + private static final String COLLECTION_TYPE = "java.util.Collection"; + private static final String OBJECT_TYPE = "java.lang.Object"; + + /** + * 获取数据类型的默认值 + * + * @param canonicalText 类的全限定名称 + * @return + */ + public static Object getDataTypeDefaultValue(String canonicalText) { + if (StringUtils.isEmpty(canonicalText)) { + return null; + } + switch (canonicalText) { + case STRING_TYPE: + return ""; + case INTEGER_TYPE: + return 1; + case LONG_TYPE: + return 1L; + case SHORT_TYPE: + return (short) 1; + case BYTE_TYPE: + return (byte) 1; + case DOUBLE_TYPE: + return 1.0; + case FLOAT_TYPE: + return 1.0f; + case DATE_TYPE: + return DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"); + case LOCAL_DATE_TYPE: + return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + case LOCAL_DATE_TIME_TYPE: + return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + default: + return null; + } + } + + /** + * 判断是否是数据类型 + * + * @param psiType + * @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)) { + return true; + } + return false; + } + + /** + * 判断是否是数组类型 + * + * @param psiType + * @return + */ + public static boolean isArrayType(PsiType psiType) { + return psiType instanceof PsiArrayType; + } + + /** + * 判断是否是Collection类型 + * + * @param psiType + * @return + */ + public static boolean isCollectionType(PsiType psiType) { + if (!(psiType instanceof PsiClassType)) { + return false; + } + PsiClassType psiClassReferenceType = ((PsiClassType) psiType); + PsiClass resolvePsiClass = psiClassReferenceType.resolve(); + if (resolvePsiClass == null) { + return false; + } + if (OBJECT_TYPE.equals(resolvePsiClass.getQualifiedName())) { + return false; + } + if (COLLECTION_TYPE.equals(resolvePsiClass.getQualifiedName())) { + return true; + } + // 如果父类是Collection类型 + for (PsiType parentPsiType : ((PsiClassType) psiType).rawType().getSuperTypes()) { + if (isCollectionType(parentPsiType)) { + return true; + } + } + return false; + } + + /** + * 是否是Java官方类库 + * + * @param psiType + * @return + */ + public static boolean isJavaOfficialType(PsiType psiType) { + return psiType.getCanonicalText().startsWith("java"); + } + +} diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java index 54789dd..474adbe 100644 --- a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java +++ b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiUtils.java @@ -25,11 +25,12 @@ public class PsiUtils { /** * 获取光标处上下文的{@code PsiMethod} + * * @param actionEvent * @return */ public static PsiMethod getCursorPsiMethod(AnActionEvent actionEvent) { - PsiElement elementAt = PsiUtils.getCursorPsiElement(actionEvent); + PsiElement elementAt = getCursorPsiElement(actionEvent); if (elementAt == null) { return null; } @@ -37,7 +38,22 @@ public static PsiMethod getCursorPsiMethod(AnActionEvent actionEvent) { } /** - * 获取光标所在处的{@code PsiElement} + * 获取当前操作下的 {@code PsiClass} + * + * @param actionEvent + * @return + */ + public static PsiClass getOperatePsiClass(AnActionEvent actionEvent) { + PsiElement psiElement = getOperatePsiElement(actionEvent); + if (psiElement instanceof PsiClass) { + return (PsiClass) psiElement; + } + return null; + } + + /** + * 通过偏移量获取光标所在处的{@code PsiElement} + * 这将返回指定偏移量中的最低级别元素,这通常是一个 lexer 令牌。最有可能你应该使用{@code PsiTreeUtil.getParentOfType()}来查找您真正需要的元素。 * * @param anActionEvent * @return @@ -55,13 +71,33 @@ public static PsiElement getCursorPsiElement(AnActionEvent anActionEvent) { } /** - * 设置当前组件不可用(不显示) + * 从操作中获取{@code PsiElement}。注意:如果编辑器当前处于打开状态,并且 caret 中的元素是引用,则这将返回解析引用的结果。这可能是你需要的,也可能不是。 + * + * @param anActionEvent + * @return + */ + public static PsiElement getOperatePsiElement(AnActionEvent anActionEvent) { + return anActionEvent.getData(LangDataKeys.PSI_ELEMENT); + } + + /** + * 设置当前组件不可用 + * * @param anActionEvent */ - public static void setActionDisabled(AnActionEvent anActionEvent){ + public static void setActionDisabled(AnActionEvent anActionEvent) { anActionEvent.getPresentation().setEnabled(false); } + /** + * 设置当前组件不可见 + * + * @param anActionEvent + */ + public static void setActionInvisible(AnActionEvent anActionEvent) { + anActionEvent.getPresentation().setVisible(false); + } + /** * 根据{@code PsiType}获取对应的{@code PsiClass} * @@ -159,6 +195,7 @@ public static List getAllPsiFields(PsiClass psiClass) { /** * 递归获取类中所有字段 + * * @param psiClass * @param psiFields */ diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/Generator.java b/src/cn/bigcoder/plugin/objecthelper/generator/Generator.java index 436fd08..b79cc16 100644 --- a/src/cn/bigcoder/plugin/objecthelper/generator/Generator.java +++ b/src/cn/bigcoder/plugin/objecthelper/generator/Generator.java @@ -7,4 +7,4 @@ **/ public interface Generator { String generate(); -} +} \ No newline at end of file diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java new file mode 100644 index 0000000..fc7bb62 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/generator/json/ClassJsonGenerator.java @@ -0,0 +1,105 @@ +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 From 86c08949b807ec3bd7356b57a13aee6650bbe59b Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Mon, 7 Jun 2021 16:23:05 +0800 Subject: [PATCH 06/21] update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 14e1f06..6bab604 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ ![](https://img.shields.io/badge/version-v1.1.0-blue) ![](https://img.shields.io/badge/license-Apache%202-red) ![](https://img.shields.io/badge/size-28%20kB-yellowgreen) -![](https://img.shields.io/badge/download-200%2B-green) +![](https://img.shields.io/badge/download-400%2B-green) -JetBrains Intellij IDEA Object插件,包含以下功能: +插件地址:[https://plugins.jetbrains.com/plugin/15788-objecthelper](https://plugins.jetbrains.com/plugin/15788-objecthelper) + +JetBrains Intellij IDEA ObjectHelper插件,包含以下功能: - 对象拷贝 From 196376a03a58a678b0304bd3ee8653b70c0f708d Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 28 Aug 2021 00:01:05 +0800 Subject: [PATCH 07/21] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=20=20=20=20=20=201.=E6=96=B0?= =?UTF-8?q?=E5=A2=9EJava=E7=B1=BB=E8=BD=ACIDL=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 ++- object-helper.jar | Bin 26588 -> 31706 bytes resources/META-INF/plugin.xml | 19 +- resources/META-INF/pluginIcon.svg | 16 +- .../objecthelper/action/ClassToIDLAction.java | 40 ++++ .../common/constant/IDLTypeName.java | 18 ++ .../common/constant/JavaClassName.java | 25 +++ .../objecthelper/common/util/IDLUtils.java | 48 +++++ .../common/util/PsiTypeUtils.java | 75 +++++-- .../generator/idl/IDLGenerator.java | 185 ++++++++++++++++++ 10 files changed, 415 insertions(+), 33 deletions(-) create mode 100644 src/cn/bigcoder/plugin/objecthelper/action/ClassToIDLAction.java create mode 100644 src/cn/bigcoder/plugin/objecthelper/common/constant/IDLTypeName.java create mode 100644 src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java create mode 100644 src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java create mode 100644 src/cn/bigcoder/plugin/objecthelper/generator/idl/IDLGenerator.java diff --git a/README.md b/README.md index 6bab604..ccf3df9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # object-helper-plugin -![](https://img.shields.io/badge/version-v1.1.0-blue) +![](https://img.shields.io/badge/version-v1.2.0-blue) ![](https://img.shields.io/badge/license-Apache%202-red) -![](https://img.shields.io/badge/size-28%20kB-yellowgreen) -![](https://img.shields.io/badge/download-400%2B-green) +![](https://img.shields.io/badge/size-36.43%20kB-yellowgreen) +![](https://img.shields.io/badge/download-500%2B-green) 插件地址:[https://plugins.jetbrains.com/plugin/15788-objecthelper](https://plugins.jetbrains.com/plugin/15788-objecthelper) @@ -14,4 +14,18 @@ JetBrains Intellij IDEA ObjectHelper插件,包含以下功能: - Java类转JSON - ![](https://image.bigcoder.cn/20210227223302.gif) \ No newline at end of file + ![](https://image.bigcoder.cn/20210227223302.gif) + +- Java类转IDL + ![](https://image.bigcoder.cn/6eee7a02-8e4e-4f11-9b8c-81d661a920c5.gif) + +## 未来功能支持计划 + +object-helper插件未来功能支持计划: + +- [x] Class转IDL(Class To IDL) +- [ ] Class转XML(Class To XML) +- [ ] JSON转Class(JSON TO Class) +- [ ] All Setter +- [ ] 菜单分组显示 +- [ ] 个性化配置 \ No newline at end of file diff --git a/object-helper.jar b/object-helper.jar index 29d71419fa3e9e5063bebbc01688f8d61cb01600..79aa4588bcd543ab7b438dd77d2266748b971a3c 100644 GIT binary patch delta 26754 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 A+yDRo delta 22137 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
      CoK^t|^29^(`} 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 cn.bigcoder.plugin.objecthelper ObjectHelper - 1.1.0 + 1.2.0 HearingSmile GitHub + This is a Java object toolset. Using document: GitHub
    9. Copy the object
    10. Class to JSON
    11. +
    12. Class to IDL
    13. + ]]>
      New feature:Added the ability to quickly convert Java classes to JSON -
    14. Update feature:Rename GenerateO2O to Object Method Copy
    15. +
    16. New feature:Added the ability to quickly convert Java classes to IDL
    17. ]]>
      @@ -35,14 +36,14 @@ + class="cn.bigcoder.plugin.objecthelper.action.ClassToFormatJsonAction" text="Class To JSON" + description="Converts the Java class to a JSON string"> - + diff --git a/resources/META-INF/pluginIcon.svg b/resources/META-INF/pluginIcon.svg index f8fc670..239e736 100644 --- a/resources/META-INF/pluginIcon.svg +++ b/resources/META-INF/pluginIcon.svg @@ -1,3 +1,13 @@ - - - + + + Layer 1 + + + + + + + + + + \ No newline at end of file diff --git a/src/cn/bigcoder/plugin/objecthelper/action/ClassToIDLAction.java b/src/cn/bigcoder/plugin/objecthelper/action/ClassToIDLAction.java new file mode 100644 index 0000000..aff3631 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/action/ClassToIDLAction.java @@ -0,0 +1,40 @@ +package cn.bigcoder.plugin.objecthelper.action; + +import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; +import cn.bigcoder.plugin.objecthelper.generator.idl.IDLGenerator; +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; + +/** + * @author: Jindong.Tian + * @date: 2021-08-21 + **/ +public class ClassToIDLAction extends AnAction { + @Override + public void actionPerformed(@NotNull AnActionEvent anActionEvent) { + PsiClass psiClass = getOperatePsiClass(anActionEvent); + if (psiClass == null) { + return; + } + String idl = IDLGenerator.getInstance(psiClass).generate(); + CopyPasteManager.getInstance().setContents(new StringSelection(idl)); + NotificationUtils.notifyInfo(anActionEvent.getProject(), "IDL代码成功置入剪贴板:
      " + idl); + } + + @Override + public void update(@NotNull AnActionEvent anActionEvent) { + // 如果当前光标不在方法中,则不显示ConvertToJson组件 + if (getOperatePsiClass(anActionEvent) == null) { + setActionInvisible(anActionEvent); + } + super.update(anActionEvent); + } +} \ No newline at end of file diff --git a/src/cn/bigcoder/plugin/objecthelper/common/constant/IDLTypeName.java b/src/cn/bigcoder/plugin/objecthelper/common/constant/IDLTypeName.java new file mode 100644 index 0000000..3660433 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/common/constant/IDLTypeName.java @@ -0,0 +1,18 @@ +package cn.bigcoder.plugin.objecthelper.common.constant; + +/** + * @author: Jindong.Tian + * @date: 2021-08-21 + **/ +public class IDLTypeName { + public static final String BOOL = "bool"; + public static final String BYTE = "byte"; + public static final String I16 = "i16"; + public static final String I32 = "i32"; + public static final String I64 = "i64"; + public static final String DOUBLE = "double"; + public static final String STRING = "string"; + public static final String LIST = "list"; + public static final String SET = "set"; + public static final String MAP = "map"; +} diff --git a/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java b/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java new file mode 100644 index 0000000..9f18611 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/common/constant/JavaClassName.java @@ -0,0 +1,25 @@ +package cn.bigcoder.plugin.objecthelper.common.constant; + +/** + * @author: Jindong.Tian + * @date: 2021-08-21 + **/ +public class JavaClassName { + public static final String STRING_TYPE = "java.lang.String"; + public static final String INTEGER_TYPE = "java.lang.Integer"; + public static final String LONG_TYPE = "java.lang.Long"; + public static final String SHORT_TYPE = "java.lang.Short"; + public static final String BYTE_TYPE = "java.lang.Byte"; + public static final String DOUBLE_TYPE = "java.lang.Double"; + public static final String FLOAT_TYPE = "java.lang.Float"; + 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 COLLECTION_TYPE = "java.util.Collection"; + public static final String MAP_TYPE = "java.util.Map"; + public static final String LIST_TYPE = "java.util.List"; + public static final String SET_TYPE = "java.util.Set"; + public static final String OBJECT_TYPE = "java.lang.Object"; + +} diff --git a/src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java b/src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java new file mode 100644 index 0000000..3264f6b --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/common/util/IDLUtils.java @@ -0,0 +1,48 @@ +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.*; + +/** + * @author: Jindong.Tian + * @date: 2021-08-21 + **/ +public class IDLUtils { + + /** + * 将Java类型转换为IDL类型声明 + * @param canonicalText 类的全限定名称 + * @return + */ + public static String convertJavaTypeToIDLType(String canonicalText){ + if (StringUtils.isEmpty(canonicalText)) { + return null; + } + switch (canonicalText) { + case STRING_TYPE: + return STRING; + case INTEGER_TYPE: + return I32; + case LONG_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 8cf8361..9286362 100644 --- a/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java +++ b/src/cn/bigcoder/plugin/objecthelper/common/util/PsiTypeUtils.java @@ -11,24 +11,13 @@ import java.time.format.DateTimeFormatter; import java.util.Date; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaClassName.*; + /** * @author: Jindong.Tian * @date: 2021-02-12 **/ public class PsiTypeUtils { - private static final String STRING_TYPE = "java.lang.String"; - private static final String INTEGER_TYPE = "java.lang.Integer"; - private static final String LONG_TYPE = "java.lang.Long"; - private static final String SHORT_TYPE = "java.lang.Short"; - private static final String BYTE_TYPE = "java.lang.Byte"; - private static final String DOUBLE_TYPE = "java.lang.Double"; - private static final String FLOAT_TYPE = "java.lang.Float"; - private static final String DATE_TYPE = "java.util.Date"; - private static final String LOCAL_DATE_TYPE = "java.time.LocalDate"; - private static final String LOCAL_DATE_TIME_TYPE = "java.time.LocalDateTime"; - - private static final String COLLECTION_TYPE = "java.util.Collection"; - private static final String OBJECT_TYPE = "java.lang.Object"; /** * 获取数据类型的默认值 @@ -100,12 +89,53 @@ public static boolean isArrayType(PsiType psiType) { } /** - * 判断是否是Collection类型 + * 判断是否是java.util.Collection类型 * * @param psiType * @return */ public static boolean isCollectionType(PsiType psiType) { + return isSpecifiedType(psiType, COLLECTION_TYPE); + } + + /** + * 判断是否是java.util.List类型 + * + * @param psiType + * @return + */ + public static boolean isListType(PsiType psiType) { + return isSpecifiedType(psiType, LIST_TYPE); + } + + /** + * 判断是否是java.util.List类型 + * + * @param psiType + * @return + */ + public static boolean isSetType(PsiType psiType) { + return isSpecifiedType(psiType, SET_TYPE); + } + + /** + * 判断是否是java.util.Map类型 + * + * @param psiType + * @return + */ + public static boolean isMapType(PsiType psiType) { + return isSpecifiedType(psiType, MAP_TYPE); + } + + + /** + * 判断一个类是否是指定类型子类 + * @param psiType psiType + * @param qualifiedName 全限定名称 + * @return + */ + public static boolean isSpecifiedType(PsiType psiType, String qualifiedName){ if (!(psiType instanceof PsiClassType)) { return false; } @@ -117,18 +147,18 @@ public static boolean isCollectionType(PsiType psiType) { if (OBJECT_TYPE.equals(resolvePsiClass.getQualifiedName())) { return false; } - if (COLLECTION_TYPE.equals(resolvePsiClass.getQualifiedName())) { + if (qualifiedName.equals(resolvePsiClass.getQualifiedName())) { return true; } - // 如果父类是Collection类型 for (PsiType parentPsiType : ((PsiClassType) psiType).rawType().getSuperTypes()) { - if (isCollectionType(parentPsiType)) { + if (isSpecifiedType(parentPsiType, qualifiedName)) { return true; } } return false; } + /** * 是否是Java官方类库 * @@ -139,4 +169,15 @@ public static boolean isJavaOfficialType(PsiType psiType) { return psiType.getCanonicalText().startsWith("java"); } + /** + * 如果不是Java官方类库则返回true + * + * @param psiType + * @return + */ + public static boolean isNotJavaOfficialType(PsiType psiType) { + return !isJavaOfficialType(psiType); + } + + } diff --git a/src/cn/bigcoder/plugin/objecthelper/generator/idl/IDLGenerator.java b/src/cn/bigcoder/plugin/objecthelper/generator/idl/IDLGenerator.java new file mode 100644 index 0000000..bfad7d2 --- /dev/null +++ b/src/cn/bigcoder/plugin/objecthelper/generator/idl/IDLGenerator.java @@ -0,0 +1,185 @@ +package cn.bigcoder.plugin.objecthelper.generator.idl; + +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.generator.Generator; +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.compress.utils.Lists; +import org.apache.commons.compress.utils.Sets; +import org.apache.commons.lang.ArrayUtils; + +import java.util.List; +import java.util.Set; + +/** + * @author: Jindong.Tian + * @date: 2021-08-20 + **/ +public class IDLGenerator implements Generator { + + private PsiClass psiClass; + + /** + * 保存已经解析过的自定义类型名称,防止出现递归嵌套的情况 + */ + private Set recursiveCache = Sets.newHashSet(); + + private IDLGenerator(PsiClass psiClass) { + this.psiClass = psiClass; + } + + @Override + public String generate() { + return generateStructCode(psiClass).toString(); + } + + /** + * 生成类的IDL语句 + * + * @param psiClass + * @return + */ + private StringBuilder generateStructCode(PsiClass psiClass) { + if (recursiveCache.contains(psiClass.getQualifiedName())) { + return new StringBuilder(); + } + recursiveCache.add(psiClass.getQualifiedName()); + List fields = Lists.newArrayList(); + List allPsiFields = PsiUtils.getAllPsiFields(psiClass); + StringBuilder code = new StringBuilder(); + for (PsiField allPsiField : allPsiFields) { + code = processAssociateClass(allPsiField.getType(), code); + fields.add(processPsiField(allPsiField)); + } + return code.append(generateStructCode(psiClass.getName(), fields)); + } + + /** + * 生成类泛型关联类的IDL语句 + * + * @param psiType + * @param code + * @return + */ + private StringBuilder processAssociateClass(PsiType psiType, StringBuilder code) { + if (PsiTypeUtils.isArrayType(psiType) && PsiTypeUtils.isNotJavaOfficialType(psiType)) { + //如果是数组类型 + PsiClass arrayContentClass = PsiUtils.getPsiClass(((PsiArrayType) psiType).getComponentType(), psiClass.getProject()); + code = generateStructCode(arrayContentClass).append(code).append("\n"); + } else if (PsiTypeUtils.isListType(psiType) || PsiTypeUtils.isSetType(psiType)) { + PsiType[] parameters = ((PsiClassReferenceType) psiType).getParameters(); + // 存在泛型且泛型不是Java自带的类型,则需要生成一个新的struct(后期这可以支持配置,配置需要生成的白名单或黑名单) + if (!ArrayUtils.isEmpty(parameters) && PsiTypeUtils.isNotJavaOfficialType(parameters[0])) { + //获取泛型 + PsiClass fieldPsiClass = PsiUtils.getPsiClass(parameters[0], psiClass.getProject()); + code = generateStructCode(fieldPsiClass).append(code).append("\n"); + } + } else if (PsiTypeUtils.isMapType(psiType)) { + PsiType[] parameters = ((PsiClassReferenceType) psiType).getParameters(); + if (!ArrayUtils.isEmpty(parameters)) { + if (parameters.length >= 1 && PsiTypeUtils.isNotJavaOfficialType(parameters[0])) { + PsiClass fieldPsiClass = PsiUtils.getPsiClass(parameters[0], psiClass.getProject()); + code = generateStructCode(fieldPsiClass).append(code).append("\n"); + } + if (parameters.length >= 2 && PsiTypeUtils.isNotJavaOfficialType(parameters[1])) { + PsiClass fieldPsiClass = PsiUtils.getPsiClass(parameters[1], psiClass.getProject()); + code = generateStructCode(fieldPsiClass).append(code).append("\n"); + } + } + } else if (PsiTypeUtils.isNotJavaOfficialType(psiType)) { + //如果是自定义类型 + PsiClass fieldPsiClass = PsiUtils.getPsiClass(psiType, psiClass.getProject()); + code = generateStructCode(fieldPsiClass).append(code).append("\n"); + } + return code; + } + + /** + * 生成struct代码 + * @param structName IDL名称 + * @param fields struct中所有字段声明 + * @return + */ + private StringBuilder generateStructCode(String structName, List fields) { + StringBuilder code = new StringBuilder(); + code.append("struct ").append(structName).append(" {\n"); + for (int i = 0; i < fields.size(); i++) { + code.append(" ").append(i + 1).append(":").append(fields.get(i)).append(";\n"); + } + code.append("}\n"); + return code; + } + + /** + * 生成IDL字段声明 + * + * @param psiField + * @return + */ + private String processPsiField(PsiField psiField) { + String fieldName = psiField.getName(); + String type = processType(psiField.getType()); + if (type == null) { + return null; + } + return type + " " + fieldName; + } + + /** + * 将Java Type转成IDL Type + * + * @param psiType + * @return + */ + private String processType(PsiType psiType) { + if (PsiTypeUtils.isDataType(psiType)) { + //如果是数据类型 + return IDLUtils.convertJavaTypeToIDLType(psiType.getCanonicalText()); + } else if (PsiTypeUtils.isArrayType(psiType)) { + //如果是数组类型 + PsiClass arrayContentClass = PsiUtils.getPsiClass(((PsiArrayType) psiType).getComponentType(), psiClass.getProject()); + String qualifiedName = arrayContentClass.getQualifiedName(); + String typeName = IDLUtils.convertJavaTypeToIDLType(qualifiedName); + if (typeName == null) { + typeName = qualifiedName.substring(qualifiedName.lastIndexOf(".")); + } + return "list<" + typeName + ">"; + } else if (PsiTypeUtils.isListType(psiType)) { + PsiType[] parameters = ((PsiClassReferenceType) psiType).getParameters(); + if (ArrayUtils.isEmpty(parameters)) { + return "list"; + } + //获取泛型 + PsiType genericType = parameters[0]; + return "list<" + processType(genericType) + ">"; + } else if (PsiTypeUtils.isSetType(psiType)) { + PsiType[] parameters = ((PsiClassReferenceType) psiType).getParameters(); + if (ArrayUtils.isEmpty(parameters)) { + return "set"; + } + //获取泛型 + PsiType genericType = parameters[0]; + return "set<" + processType(genericType) + ">"; + } else if (PsiTypeUtils.isMapType(psiType)) { + PsiType[] parameters = ((PsiClassReferenceType) psiType).getParameters(); + if (ArrayUtils.isEmpty(parameters) && parameters.length == 2) { + return "map"; + } + return "map<" + processType(parameters[0]) + ", " + processType(parameters[1]) + ">"; + } else if (PsiTypeUtils.isNotJavaOfficialType(psiType)) { + //如果是自定义类型 + String canonicalText = psiType.getCanonicalText(); + return canonicalText.substring(canonicalText.lastIndexOf(".") + 1); + } + return null; + } + + public static IDLGenerator getInstance(PsiClass psiClass) { + return new IDLGenerator(psiClass); + } +} From d836812f736237438eeca89dafc9564a7844c181 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 27 Nov 2021 20:31:31 +0800 Subject: [PATCH 08/21] =?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 09/21] =?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 +

    18. Fix:rename "Class To IDL" to "Class To Thrift IDL"
    19. +
    20. Fix bug:fix "Class To Thrift IDL" BigDecimal conversion exception
    21. ]]> @@ -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 10/21] =?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 zcmbrmb#Pou@+B;^n89LZW@ctt3@v76mMmMcn3O+lhJm zb;SLryKdIK6`7|pPoC;8vfvQtAkfgzAYq27DjiR2uO9l_rJ{z{`*&BJI4R}0Qi3n zFtRi^wl^_#`VS+~{xZ_R#?{>NKba=_pKq`?vNAPxu`so9__yg)_5Xd}*|6KaNzP{LhZ$#9_(AinlUc%nV*3d=9+1^h0AI2Gs|M>%?S&*tf(k^!!l4ZbH+Jdh}k=aMXvL z&D3`1$vkN+W!>u9{4n7+2FsoaNJ@zY?)v-1ixb5K<2T%Tlp6)h$JqBOY7?)q>XC zBq`pdP6-CYb`#ls0B}e57f};!y+2(SZ4RzKiDtUU8XvXf-t4v*H&={1hR11E{ z*rhLa^2vW+ayh|96Fe%wi|-@`@B2l5JFhNN$UJ@&tZc19?+JaaoBSE@WbmRz;;uSv zU@E6F#j~r~Ut*9p8%g4|p^=6Y;)wKM%m;l)Od#%ommkE_clZ%H3f#4V_?*kCFe`3- zml`BwjcU`VPFOlv1A|(4T3~NF`=VGG5uipj2JY zv*E#FD5mhUec2KtJ7|G|Iq_d`f?v4!gdM-nf}nvXZ1Ht&8VXYW~C?fe`2&n~03hx?>Fa~_Vwn7_m3>wbir^aeBftNKIE9`I>^4KJkrZfKB z!ab=g>Koh}@@*4{g=h+!l*JhaIqT{=ME4m%w)ti*Z#(;QktmBE5MgZ=O8(N*_+EOd z=@XbVV`|xXB&_?Wo2*e>E@dqBGWkZ0k73$igB@@0ZWN0Dz8SxM!mS_j&T>S}tDZFf zs3=Nbmn(Qo+a5NkU{K~m`CO0yj@@j}a08`nKg*m?&>2N@nAfB`Lb;T8x|0B-4%VRp zG7)4x`gR@b$XD1!3g2q+pe7a5F-{qy;WTExA5qax$;knX>!4$GUm2oNQ~9yi=uhW* zr`p$R_%f?)PPNvilH}vzt;Kh;k&_%+?c3ptQIQ;ppN3s9u1HSCQf9A>wmnopbQ>=6 zs9mUM6+MJ07BY0*;C5SxW%Di7s@hFE*c!H}A*-#q0yBc_j$sGcG6q}xIoUcwVS?_7 zYF_iIRkmBMoW{~gloN@L0;s{bLR}>Kv^om6Z4s`v@%o~mRGb=YQufJ2f0@{kwcqY( zxL5gpEcG%r3%)p=gxg=OKU$v5T_p*8>|C8K*?)7s$=>=Ykm3Hq-T{}Fnj8U(LqW_Y zm#ZcUTd9h(;Dc0YLABfQ349KgK}ugP2wc&N6-zlWO!nEinkB({oGM z25lbw-{u=lr?F72XWVHhZ-HdY)q98+@-oTgEj2ReNv-FJUAidDx0S^$CHmMZ62!-P zhKZ#~2@{A~DjcF$I16_~cc-AyO5L=MT6U%I>HNZqNtQa8bt-W^x`sZBE&VKXkQxw$ z3mt<>JgmS+Q`+qC(YK`Lmn@PjPtEu$I}iR!Z-jO+UjP7*PK&pOpojFlEIYx^oPf9V z#h?7+EJx=Ssb#<^^psZN%IQ_=alSvZJzBLRf8#7f<4 zYu?RN?I)EjBejk!*sYouI3wFyP}<|bTyVR@KvHaR$4MPRrdeCqNpJZpw}VJ}3CX54 z70uo(H;K^rr{w_j!@rz;b_8K5__z(bXLdrnx zG+a!S{O>l|qJ4Nc!E>2#7SEpCP*x!6y=MOLX1f@frmP5l!Shg50Pk8Pc7U4Jer{wH z(TtGwcx5~2w>%E@NqI3N*49vj+VECLpOz3>^T~<5y>w8lz8k-tw-4|?Fh2PU-=zm6 z2uKy&pE3Tg*@)=h#&}f=CrdLIX)(Ef%Olh_?9tWGKQ=Dw>g9^T0A1Qb>J}Gvf>_96 zwO=e`dlqag|!eLdMwVlXb(2M zoh3}QWfv;X3~?QaC%542qO_nBE56+qsEu<2<0_M5 zRh}nHJPNvv!@-Da86zC+QY%GxBXvxY_z$CGlu3iF6Xj(KpIBB76F8iUmjNt_StSIq z>iQ7*h>*45Wh#pMcm0hiVHBr9!7t-S6_gu#yWX?T=$7!Q3)}4oNUXn9m$KVUXv-7Q z3xEMMZ4qI>Zp)Ia9cBLYvD;t6VRV64U*_lADqS?3+y)G>bP7`mgEupP=qQ`prcaJ0 z%kv8h2QW+5y`0gQFDF0ZM@)+m#5KE5xf_?B3tC8~P-qO2ti&64E9DPc$M4tQ2~ zq*;%p5O0b3#%C4Z29Hx>q%H{=XE+tcZmyL#S_#z}`BfRU%1E-093K;rrGYcFx@S;U zOqO?^5wS?m2d8;P#1;T_GORCZ8FFhSQigQlbwO|Cmgg5bd0dvGK_q7L$^D z)g4#c2IcC3KF_q{gJXB;mBGSyD_2w&r(^Xp=3zMMmLlEg|dC6v;J^x1;M` z5{{C5<7L@BuLiP@K`#Vd;<(Sb#M1Q~y>+2X1;?)nA~8J-5ix4S=e9W^$Ym=Gb<;zb z!L_)SB5R>^N;Sbz#}w^FPQKi7MdsY8s3Vwh_%x{=3GnjLHs=?B?jnp3NB@%GV`VnQ zI6LrM+v1ot>Ku`VMieV-CCPx}ojK0aGW~oW9|;KBG{qtTx%GZY)>?GN@qU#7k)uYY zZVonIy0oh-tz;SuUoqMd7HOkzb})-i;cz7zuy5$ozWtYIDiOKjqT)ZCvzK*j#l2Y! z!A(9O|3KRoR`j{I-`TY8?{f8zqV#{xsQ(7qD*mII6t#Eols9#;us8WPwAIjZ#}&tX zUyWO@Tdy?^Jck(;rl=F2g@FKbJnv^#aEM6`^=E|{7Xnlb+cvkQUnYh6VVjxWe??$D zhX;1UG4}hhvf4W!21C6gJ0F(Yc_ugK1YcGGnlIgxtL+lI9=9kzKpnscOSlqy30#UD zaQH1pCkv;ehm^6ppU~a*{9nCv%HWF}P!!qrgwd6;dL39LrsI35x)vg2sYZ89OJ7Y` z2OY>m?ZWwz5ZL9+1GCc(~I-?QF20TpysH4yL z?ru^L@sncuRF@Qb1xz#@XHgm`Xs`25@HV;Qsf8p}b}i*y*~Z$hfK0=#uh zOr+;IfajkRnl#D|K4a=Bab>)Q5b*W@W+s_A(I5aEr+29pl$kjEDr=FwGMkl$gg8X+ zS-mYKQvpiR-lqRv;vF?ggm;kTOIs~hDH3mw!$MuitPW-qFogA2cZk2YdcfIpk-%xX zQd;kD+WJ$jKlmB7N~788H9B8|p)F>@9o&t6Lu^^VA_-3coXTKCE+9yEG2G95)zqp1 zT2?is_C~H~Z-Ry2wG&6PXux%(JCslDS{GxAN-BXu+|sKLPe-L@h=pbkO~MTlP&agJ zKU3;O?zou{xT>FRA!&*Z+r~Kx-B}V-NsdX!bT0IB*i=8=o7EZBFi zF`0+`6c3W@O!Te7+573Xj1ytE8vI+=5}$b&hVdJ&@6rM3jQ&z@%yY>CXa~E8o>+~I zY6ChViX4XqOzThNO>w1n>9d$^XA;A8?339ru$QB*i`H$F&C2N(YL$FtCrGO6-@kg9 z+clc5=sr~9m-x49$d6V@L2|f>W}(>1t#yZ?<<>}3EHXZo#qUiIYRl=2pp6^sKX^`+ z>R@s%lLVbYbP}9Ou&MIzXa|`LpFG2BZB4$?wddNHbhSDp8k9!ab+S4y%pv@mClhJ7kAp7D+OWs&5|m?u9OC%Vkl`1(+ge5p(-N;Cb*)-Gh)P`m;Ss;<%}IuFUxfxQ(hwGtolNSf6ZP~JyyOQFp!PzVnah<_w(+q<*jao zj{3x7=PeF=GjzALXObD=+o1k_?1Khm=U2T}8qegN0cz(aH|&X)oAoigOCXYY##t)j zhedF9sp=b1U%R!Lj)@Ho#r1<}vAe1ZMm2>aRcLYiaGlF98M7Gw=*1NW#RbE0D|!U` zZTTm~gG$p^>;^g|j*2JbPj(3bw9%j#R~0jJgZs7@`qUla57U$I=YFrHU-rqPrrz*Q zd}w_r+w5|8NPXG1L9!!rYY?EG=1CyeBfTHhV{&UPt|9wNkQxpJB`Rn?V0OFlP{YlX zcWxCLkO66{7^O>cBh{iUoVVYTg(s!+O}h#gdtQ&e7&|`#G<*>wn{&Eg6ZJ=`Ug_DS zL$G)rBl3w?Q2h&^GRejf)3)Rpk*4=aj(Z@df3Q!#n6QxD?@a6K5n3C56`zard6@n2 zDA_NEu<;Fd0yZdmT)3Uuw7FK^u!O#N*L!aUPrQ;jLuUVh!p_(myo#=^B$xP_-L0gh zq^@jsfx+xk1oz|VvxAObuj(c{QhE$H0jHcu~FEhoV{+?HqP zC?~ZD>j%dJ$5nxzC#aI-ZNBP_#^ZBsU)HCon(Us&4GHZY`Gz8Q2bZOxWlyxw<=|_i zFRf;m(D`CwD*H(OQ+SgVjZ(fdw_TR$XtNESbu0A-~ zQ2MS!h#-IV5CQ>a&#}nwN)l)@ukfyuvt#uiP=D;Bh%F`3OP@eM;*tLo`}^N;sK)lT zw*TT#|4AX+>;5|t%k*EAKL0XeY;Wi6Vrb{`4;J}<-r9x#AFTZ@qEtN{Oce}mP5(v5 z#sci;gpdQLI4q4sWMo^Dcn=maODu5@3crgn=15VLhJ^O-t?Cv6RyKz}7rfJD#dvH( z0rQc~b;<5ClT&XZrz+gdzP-I)qX{8Z^H^*v;YP1{kW8=RMuPbrY^(Yv`jXU_3Nkon z%DY2i-pi{eu+UPnlqLihFTRuW-2&xun3qqzHS3Mc*ZSHp-m-!b{1$tTZ}f!LoKGDe zEty`ocOcV$^l;q*;})-p2Pg)H+$9Nop7qY;lI^v$0NK-R_ECx5MmenP6|+(Yxe=(Q zj8;aeawb*uAM_k!Xu8lHFuUW?w`^wims4?8Wvp9b#WW0xsw~Fz9F|rrMK`UlJ;KOY z6Z2n+!fxCKi$;y_^wwCDGwjpdxOLZiZT&Vr9-$Q9nh%vW`o|;($v83-+1PH?w+1t9 zabNiD4wqH$5-Rh2v9!^2YigCKa8RT|NAK zMs~!1#q}kRj3Me1>$^VUJhk<44s+t`<)XSpN4RTVTYoy_>=N}Ur+3E&xYkB`M{GEQ zU+#g{Z?c?bQ4&+{Fs+Z2f(jzPAGX!S3U0<07;PR1o8W1?J~qo$qBD zOjnQE*rfRe0i6Aeer@LL@(1GE!EE6NzhB1%7I}MN2qAPud7c`shQm;Jo0@H+d|z4O zIXs@hri0BIo6cA%WtAvcs`d$6ZuAUj#i0kdq^3=pG0z|j{u{(z=ob>EZ{6Sw%pC2V z&JskXA&hjZ6iAw1m#yok3vIK-5ikhurYwd@75Wp-e}VduuE8~MTzRA*G{ywXo62X=RxCpHqKG0#mwozEz6m zFtws9;K>#kkzq(a1ayyz)q#!h(2>>f&Dfx%{*tMp72!6W`6M+ANj3>A$qcbK*LMbEu7~nA$7=mo^b5CBMA7FkM=XDFBn>@ z#EZ(ylJw01ioQzbd57+C z&}ff?IJXOa_lc(G<(eEa!f|sPkAw$8WbMXx*DtHR!uZP@)O=vX4cJ z#m&Kjs2uqG<$pW%vg3lYz80&%);F`kEbgPFD?&j~o1L#HtR6buW}qy&B~84Yox**~ z8>DoWLyM{8-bsRS6I3p5N|8*(5bu^IPfAxn@BFJ@W`-h^uPmWUBiWwIX9n&@ic zta56-w7nHXvK|xs>}{^%@;93f-3fCM%>gheMC6@5R;!cOf3P|THz0G~->9^-)>i0P{8A8vjiwa17I0mL~ z*hK?`6C z(H2kJ-=Xz=fCCy*^rk0u<@QwvQ$USJ)eY}73GH3kk-n89AM-1F{jT_@n}O;n5S>AF zEL2RAmQZmFM~r3?ERnEe@~)?pWJQvO0?$_b9()rvF?Kr18h^DZ)E4b(47i*xC4E9gq;D}i(> zW3nfSff3*Lwa5Y8!+ZtX1=gMe1t%K#)l%r%g{KMSQ6Ew{FT-C~Z!Yq5$)WCE4@JyK zO=0D>_=QVHs}2^=@%>gbU&;7pNg!cdOz@`kN)vy%v0ESLip&%BoHlhkoqOb8qZP2R z9QYsDX{!aZvd>c2M;$#ngR#=r6-JBFo8fL1xV=IlB9Pngh)?~pRx^rfBzn!ZXta2t z^=sm<^`LddP|q?a;qKDSbEdYC*-khC1llK6%H-qQHf?j@zz(E5PolJ;Png_SLUBpD zij6x}YS$#=O)gw-9gtDZpzM9<=?v+vqqW>8g}TV?%Hn^%PK>(o&=~Ue(3b?;{p)k#rb%HS7UX(vW|ZF(V)L;7mP~l zeKY%5;n4yvubxPTfQar;76zr%5P+}wDg5>XCoj5)V{57pY#5RAT&gdM;~WdnPz&!z zPX2uobTM@jwwDeLg5sD>Ch1!&Pe15t7HNYdr5~Ihf{>`P*Z)QVUvLLXRi#~qk?v7fgPtG@9gId*;wMr_kjcB^*~ z6@BPq%__pd9mem;SnkwHU&kE->*mU>=f@kJ*`0Pjm)IwHA4;`4{m|U*GwTzKYZh^{ zdPN#GxzpmL^z6_V5ZVX15EME|e&~wtpZa(u=Tf7R!YC{S zF)!^BCJCSQikiowz{q1utu?d%aop|Nw)Z5*-k#CR<|@6#v+6FStVdKqLe}5CwO?Y0 zNyu)sfkXq@^?{%~IW0O!eS%z^owvu#170G_5XUyR+bpvjjd)3)n~BB# zgC&hE!oZ;eY0b?C*dIuy^;R8;{(BF_|1DqnKS(zHmnwwrzlR@J7fYKz0oh+I@%&9o zzpD?m-xi(!iDH>5@;11?TlExf9cV++>(U}3Fn+VBsEpTf6fIwdf++0#Rhk0_D<4%7 z@7zr7HLu$4+emb{hzgvxzsJOoOonXzK*=kFCT4Kho`-u--<`G|NX_P~myjlc8kMpa z_-6l;^L=x2E&Jo~-WvpttI$wFlqTvWcj%hSY%fJ5tuN*gVhC?YDatbnGK!L$1#gHe zYu6)fk4rMiIF@uM_Q)e>PYZ#PjgGk=6MqWk7kunVDjfWb=||iIld2Qni(I>2ZMtdw zuChde&zK8iioE16I~JVz3{24?6HkeOQf<{WHXOV5Q;#71m4?b3vv!10E#J;dZwX!p zoqSEIOiCM5>_Pgib|cOo>^EUrn^w!F*#x76@G5hK@}oFaCu)&*IVTAeSHBjI0dY3ReT>pp6Ue{I3aF*3Dv zO{KW<(7RVJ)P0yP*)*Db1%tZ&9wY)rSsT|)lVvO=1F&3C;W?-FBU!|fQ0=n&)OZ`G zLcg4(!l@h7ga0(EPITq0@pZy})|#g#p4!V#w=vy&RHjSA6iYp{yL8Rc^$k*m0CRL- zx2UgwS)i_tbgQ3X3-V{BnOSlo#uDdBCdL(-d9Iu5z=-&Ii2q zk^~p3d7_u1Rp-mY(B%QJro_AJut8xFw+FND*w^@l1-v@7Qv1<%CRn{7>3qyqW%05U zdP4~k(J({6rPZr@Uu;@Hc$~;2ptJNW#HW-%P|915d@rSd9|abOOh9p-pHBc2z9O$I z3C*dzMbs9lws$4Hsu=d(Tz(8x5H3{~%^W4=c+Fd1+) zu1o%U;r9Nf2)z}#zH$%!4d-R2T?1wd@8x=0zE{zlbCO@?@ytrV7)`q^ME6HiBoaw$ z^mP_Pi;+ft|K_ZCwvqiUs`VL3RSGVt`hxgRqtEO{j3*?y%QqRz)VlCgO$iCJ;=1rO zJlP4WTDtJmUS!k*@oiExJZa~oJO$z4VS{nk>;2|sA9K(e86<0wd;>6HU<0RuM)E<( z_{{4lr1;FMC=agvn!&DAgh~%_%H}W@SVierrsNUz^<2Y~hW?pDWZo#jE3_#_pP4(I z-EF{w9RpH)zM)~Ayx^zfgnpXGDOkw9Pzs-qF2zoH|3?bmN5%>j`a1!l{LO^?|LZ3F ztFZhBbST)nSejWH8~&j!`%~l>s@f{feL?qSfNzT=VFDEv?*6e}Iey5oymD~ELf9$?`!!`F9uSVX-!nkQmBE_~~-ykypE z8=i$1e$h%SP{9Od$@HD;ty0_0?ca6R|r;0 zioj`d2pnESFaRc81vImUnUZDoXDsM-pS>OU$C&x5Ji2I!5+g0>6Ye9Yf{bt#wBuRE;#?MJ8 zniG`p-Ya9t?ikBDa^|Cg*i-R(8f-N1ttqVd3cyJ#EtN(R(IM^Die&7=-2?AFB>pw7 zFz6(`$|RXKB6k5ZWBHx={O2nd4)CwTw#NRx_8YhD#x2yJvfc0-irs}+MAJlQ(H38^ zmzix>9WqVKEfQu3N2fu-u?pA&aj|~u;ARxwg{ELuixj4P!^Gav@sF5JfGyc9NC97d z#PSA};smq;YIO(6Ir(>p)EZ`wi9G=kt0PtOSYQ!wABx8uc zL#D==3hold2R-VlsTP4=Hx{q&U@auea5X9}e3PGnLqH@#tuY>@RzC@SQbU+qpnSSO z+@SpI;YG)JfqXoN>*;h58_b~NDbH6qbDp`>chI+Kg%@J|mr7RKxh(H1e=?GkCSK{fT{Gf z_^0@{fXNO(OqNLzm6AXL#Bq>Hhr5+_NNA0f#rY-BGgKT2RA{;)s;N9Q2Q;qPC46)T zIDydKDECxdrQ6KdpV56}2Nd|KwqYO@X&##*u1YNWRbaCihLE!i`|Ho|GW?HHlNp(w z!ddhZuHyo_1!zrMGf{nd2GLMoH||rYb7_nU$4OWAOH#2pB+&Y2NZsb8GMHE}^ZARm zA^}kWO;T(a1dT>Yvl9Vxp*G_(ffq9{tfzw$Vrd>qyr~T;I~CUCy+5MZ`4Ty{ z9vY@R8FT#MAS9M-$7zf^Wdut_q;b`$?Ly3dz3Du`AQlZ}%n?$_j9b(U(R|aXBka+V z)hZHjn6e#^?AR=|O7%UgA(mO?a@z+B1IaWJqM3@Xk`!$Nrq3}deUCy~LY}y}>sUf( zHoTR_n8(d%Hp5(2v%W#0Jwn5zL#Eh-J9uO&e{WBHJ}-YSeL-syW$lebAHS|XwPeM* zwhj=hFG5eJ34{M(3L|lmu!lpL*ry)4hyW1HvLB>D-g}?ZT@~|HZU)%WS=4q}<|>oN z;!HYJ7OeF0Dm$EoI|S3amBn0tMX=wc#}+gI2D5CM0VP?gm>#1d2w6SU2HW8kyuHKp z?(Q@4iaiZ-JZ)@5_4NV2WfNR1zIi*v9*TnzK@ZogJb4)j5lC!4A<-%Q6%p2QMhb(j z2!wk<0os?gvkrUoy6P3dr#zNqCE(!;a(XxOhfcB9Bna-L$}yCS@~Ru$pIlWz<#ikT z&EUi-4 z7TWn}vhn!6|Bn>=#Wn-Qt{j8Ub{Fi9wl$pkan8~X>6xK{kqs!3>3XO5#NE#+&3e_D zxeV8c#7vXaFqL`|pLrUVyBXaef2|N#98DnVj|xblksX(!zsqT-JK5|Ad-%3NKj^qQ znchDVNvh0)$!@KUX{7F+kvDEdt^_BT)l?u}qmz_${U(di$w} z`;j46HO(?C!6m?K=UcM<9X9=)2pzBR^z-qL<~N9M-`>1FwxHjy6%{W%{I|WoU3NSo z_P}*bF%&{?R{Xph`3k|f_+hq32%Tl^3w*?f*y5XCu|nm;pOrO7X$ctmimw5*kV@ue zKcE~%IDsvmOhRQRm>uJCr4X9$B-TBcS4u7EBks&lfx^hU4|IuCX)jB)aF(jx-aoXW zXlE$UaH^|HgV6}QrBV1)HpXMuKDz6JwM(5p5Z9KhPFZQE{k7qf1%9z>+#*(GgC750 zc3&8_Dnfi5pa2n~kbzA)xJEuKN1P|gR;P}`H+))`q>592KmHaEZ^&k_@t)QdV% zXq#p7xK1d@Rh-EE%oOZoR?Y8xVGOcPcL}0Str~flr&F28)hkhm?W;;iao4=yMYbhasaoi>$Ve zoJ|e6ud*n2CQ5hjMyG)Al5E;C-29nU-pPCht##yA>7ugNls9#^8rcNyy#kxJqbJ-KpX6-BiX ziv(s>wI^AE}nNFz@tK8tS6=^sX%iR!RnQ`U*K{dWLtNeAHP#|DCmj`-glng6+Z~de@fl|Zms@1 zOZiiVQmF;wgT8?M@e_~NTaE}SSJ%0rYR_errRr-^=c~gD8 zMcKk?yBffId2#gxx!S4*2emYWzd)_L>Avf#Z}TB=_hEBfZ^RB&`R3(dBHeTArR&4J z>xw*@|6^MTgEtO`O3J+zzuIc);q$6eT^zrMhhbu)r z#2_)O51j~%nLo&S2=!w9u#PXXUNj3D6>=sNRcmL?VHuCMYFkZ}zArbcp3Tl-yi+2r zB6~(x*}Iw?qOsPLWzF~;d6w&IOQqmF@r5Q9d-gVF=BIunpwEg#d}~*N#qu~eqL5r< z!}3Des|XN!5@Xe9KHgwBJA}A^!|@5L4NQpy$+E4G0(JF0CRW*%yf84Kr4ZZ8hRn8f zV}mq!)C0EbuOML>YmE426*#K7Vl5dXmZ1dm7WMJXeAjAM@^$Cv$ z_%bxs+{$&~5jmPPGmVr9Y^fDD1Io%k($Y;;L~v2jTwQ1Vc73{3$Tph5eRxzQo4J-n zS=q~d>xPL!M2jRt7PdqQ6UN})-JX-ko}LDoSFHd;;aGm>)ddv4NYnD9!=&ObJm!cv zDyZ{En&P+M+S+J#x3S9|ANQYRPM3J&lmW71a;cvbL%uY>W%OjO$7E=6i^2+Lj2{lx zc)2NKE67q8#i`OSpx3!sEjn-xl(Ue<`TTSef+0u$N`+o8Cr`LLNT|9C%Lw~kD#bwT zbg3@fv*#CKQmjikVzB&WRZhW-BN_Eb`arhlWbWuLE~9~9VKk-f%P{6S`@m;A3YcJQ z9B-DkLh^+S(KVNi8uUx!Ux%qmeR!}J8kN2(Gq)~MBaA^j2<5EtQZX&sykKqh_xX`$ z=K0wrUP|=zu+nn4vl#wG3iK{>_M574Tu?=>td7-V*adx9)1TPc`PrfBlx@INwrN0B z6)=&RDl$@G#KTI9SYh(2GDq!|uAhW`9Y^<~O1&m8nUwD2Sm;TrrkM>*dQMnqt1T!5EQteICF*_dPm)|=`CxRsS0 z)GPD`L_j%;4I(OdYHK;53Q+D5<0S%XB8)u(!jxKX6nc+LeLy9tL(K%vO?*)FKJxSQw$d zvos&L|F&e7HVW;Y7qB(_NS~DmDg@-6P#oR4;o(dUtt@O=>Gonepgu{Z*} zMP%?N&>s7v=bPy(5@kurMBz?BTY{i{+w+BUeZks!yt|&`D|1DPNczE+bs0^v;Sw0l z=zd6*aJszY3Dy*c5~R5S2W|0H>*Cb*qv(CzE{8{!|`3h?>^Sz#?CVh!~6QfZ@PSeG#1f7)rAcm`uNKqDAeJU#Ml;$ct zQy`VWd7gR+-s)M1>zng66bUP2a`cc47tSTL`~B+Zttqa-rmeU|ekpCJn>eRSB;u{! zos3Zj(U-bJfWX(E77z0%N`T$lrcSxx@jU0O^? zht#9RT=l(_*hIee401PzCj_vv7rQth(w>}uhUMNhkG%~f7b*7SJZNKKVzOi}=d1K; z^KSF%yXf4hL?_(fkL_yGY=YtI~_*oy5k3f|btzSTvp~HBABZCR^QJ20OW!gyhK^b^O5GE+j~D!?bB#c8Jl& z3Nq4Z`|4PBQYM1iii#*yBW&wd}Yb%yLqiPq73%}TPr~|R?TB{x%~QG zU;+PDK6|E7_%rVG9g+f^}Vt) zH2n)kXnGR2Jjdqd|rw{ z<3zHJ;%XD(+Px&k>GDJyKnG*)}&_qpxct2LH_B0CKQ17Ix z^+~M-eE5x76@)X)efV&>P#ni;0kB+pfDJNH&0wL>gWF3?nNA$OlWbh_#F6?LT9dwK zEmQ-#{E~#;mS`>0rPT4eoB@m|%*u@gtd6L175T~%Mv2A`{ua5C=HwQ2=qhQ-Xq?b3 zOL)F`ox8~V9_Ea$Gp>SBM|C_2N+!kLE_~E-D(Gumsua8Zk0_!YPK*GLe9|wyU>$Mu zrXGoCpkd!<6c?+}nRxIt=qa$qJg^wev4*hmMAT3qR@W(G)oyZKto?$*@%_MiXHLl+ ze_+)O)S5;uauWJ|TQaQJE^TyzH&@6h1#8aXkg7)0RP)P(as;icWY7a->hfkTF77W` zS=dH)O2GN;1`65bwtD2Q=s`P~mgAe22h=q>WD3PYeA|m7mu;F;Df!Al4Yw{)>m7sM zg)iUoBcUxm?vWvEt)1HBvWMw1FjRE^{l$U*k`XvE(NGks>`HpS=ftAW%bfj2F3q~; zGe~w*NEKsiAIWuSjU_4D5I9Rj)!iP}z4RlqAXmgcoYY+F(alFdPE~adD5WIMMy>ex z{uH0HqF;g6Acw-n__Lq)+NTnHLQzZEl}c)-L0xPXV$pF=(STo91qPUlry!GY>R<3R zLqJftp7Mmx1J-=|1nj#n6j8RW7R2;>92A%G*@67`_%`GI=sBIm?y@q%-XPsXgbJRf zTZIr2n-5i<8}{2V#j(itGMp4zH{`J=vAhux0mnJ9Lo_6LDqicTny2;$e6u^GIRXmw z)u_{WO*ku78Y+46rfo98*+t#`fb$mX8ga;MOEYdrzHJvCrixV0p(k22s+|F8gi)>0rW`>IQZN%S zn-y8eY=8G}bD5L>ydbW9ix*AHKlE*%JL}ZjJP6q!EW^z4iuY>h#&_%W?lpM}Bx0|f z>G@g-LW7xb(9#F5huwr17#gD32kkV%zE9E;0_jWVG(e8B)Oya!(B4z(0|jd+rFn=< zo6$BBJ@r(J(~Hx!Jx`CKANCkV%$0vy#y+;KSfq{>z@1;gXvrTGG?JTB=1> ziLvqae(73Bz1|-KT6F-ay6vEfWKZTvyt7dBv#^zEx}bMbhAKAI$iY6lBt7*eY|W&i zsxL&7-`xwP2E%!LGgPYfH^MD8<7C}2_tQ3{P@1s`#?gzS4mn@^B~~u=2OnT)8Ojb9 ztR_|sLn!&>7E5@F#BXraC&c@l)OeQ`+AQgpEXof};6Pu`fy#3* z`+n&Ab4p9rQ9sPjIBjY=Hwj}y*;C_FeCfwZgkCjDz5WJ!)VxzF*Y}3cu-QonD>|x8 z)T+YG)te@x)*9eWl|>hLX>b~+mdIq_;>BiBnHF*P51LF1FJYNr^iIL1T)+DKE~c{U z7GgZ__Vi*auQ}V4*mNVrSkmvrLNz7UfJ5<{+8ZzA4O_17`mV;7rPE$pt73>2YdjHT z(Wf3Bx$<1{A4{*4vjo#|(@!*CO^=HfgoxhI&nZcKxJ1pT%_M+0nQ{5wh2dxLNlFZ7 zcL!yGXyP5WtdA1eJs$xAueKnW974THy|^B8QA7dFOd`LU0oyuB1-zzEF-@5fJPONH z#9{r6#UI}jHUqnX$UU0dBh}DV0)Z{Z+2|n~JxmzKNarN|2WT0vXtZ1$tAy*~{lQzr z>?obsN28glyT78LBQp;wt|0G^w*-gMj(4x&++L5UJc)v+6moGL%k=!M7K5ep4ol-a z%XVl6+`}8}Rg(Cov_`$+Sa`#k^Qd;!2Tgm&mQ#~1*1rbC_3?TnJK+jp9$gbW9o%7& zMEzji>`k#SltUea%zHr&dCnrGAQ=|Zd4)nFdHyIO;D+oFgDm(wVtWnd*mCx}<)G=_ z7Mc|d4ITX!4cIs>z@1;D@;u9fepuW5fgSd#NdvTtN?u^oURd9;m{JBD`2{o&2rYtJ z!3t5z(PDwC1JX5Y8pRooq|-t7v~Bgn&VJ4}H&jLbRyloEZ1BWwZC;@GXpIkkx9);C z00~gT{n_mi zR0wZF8a%-_)P5nR+Qh|8UD^5ZQlmg+n4e)0q5eKD?BX^(2(#5t@eH@d;P%Xm{FB=7 z{e!!6$6shTMvU7qfR8*P-<(SCkM(;w82=Ib`>mRPU;jr1^4Ila_*?I7Y4T?s$X{(q z{B2wR`$+F!7PM01Up&)>v{`*BvL*s5a>RG!I2%l8FbZf9F&KF;oNf^-*JZi5o{7u4 zcHx=TzA%1U{uz(0hFui;{TP|b#>U3`hQ{Rk`KHyi*+u2R_pS7iIC&1Z*VQfiql@&b zuUG9KTi!RlxyAS3nnVgfV{*6Smci)goju5sAs+>v2x2LLhp*ke9=4wyn1ov)#s1>BJ)>>?t+x;Csf zxw^^K??QTHI_^`MMJ}|@M$%6JWZfGJcI^+bKGq>kJ@52r>;p59^zU}81^BM|mcBj) zAu&Dz9NV!wnZlE?~&Z=kTNY`|1a4(sUdc1Vm{NS2T%*5u>6 z%C?ez3&n3#k%cTuJo+MF{^Pqkp|y(4MajbY#{cTs3ubDqzKGxM9%XU@!bsy~U9Ft7-VKr{Aq z7#a8^R%|qiPsyb+bE=JFhWj%w;Og#6`mRRq!?R-rTP*4M$)_q2NvQ>(RU;cw#6f+s zh#YGe@m)+aWolyN!~l*_l6UT*hsJzH#0IOZq`yg zlKGnox}u*E5g+*$E7d24Jaj|r*jN6#Hx(L;^P-6q`UyC;Cc1`pK=_X&Mm;WW?qo9z z!XhsTr`u)C^%tnGLe%7pE~7{o%BH?vriCBuIE!Wwr3Lzx8rZtf17H?H8`N8dKRu^@ zU5Y(ft`U@=LxQ|{evJt(BwrRqfHqkT9J*XH>e#K6Q{n?Ha4?4fJFR0tOWP+O7V+n1T|;*SWQ!>L#-Yn0Ge zfM8%=(#>FBLeK167QRbgK?}wsOoY(treyQ9T*kP}4c7)-GI{DRGc{Q**IuT+`?3ai z9zbVjwk&zm&O>Vce8IXfoEz&B<<5MWX2KV4&UCr_GC8~!_68Rc_U1VxSe_9|t%kQ0 zNp~A}Zr|G#i|0Rjc;l+HUtC4JbIS2`%Jsdq7|Ppl60AzGMg(>y1Uwc%r7E`jXQu6*o$`g?3-pYMW7zt5+aI#7aS+S2SJL_H_h44_9Nos<$hi0n)HI0r!MnkN z(Z}3ruezqgbDF67TCl3AH4RDF)eTYx2Gy~JUFq-D>e+}{Bto;>P8vbEx0!XclC4Sc z?b9YV0)-1JayUYQC94+9^^KD}>>G0rV)VzX6+5J;q$plm8oR!Wqh?hjz~LMb5^`&v z>WC9Bk26kLY}cN|v;ogp|azIodlhFlMfo)nTM z;SVRY9zVL=T_1N?up&*?FO1bZnmR|Sw{>f-lAB*4V*3)>TS|ta%#c#uGAU7|qTXmo z+2>OBnrq~<$b|+!%$`Am&xg(pwh9xQAX_sgIMvA|%M)f4oAdtpQe%(qtR`1hB5qML z6gtT64Z<~?>_(%{@ZGrK?*~=4QVfLKTy@LDC+I|n(v~yJeRXQ4)&m(&CK#j?(2v?&NjIei(h+#p6gZlT0C9oJCOTenG;=pgYX zDz`J|7=6k}vnJ02c8ZP`ynlaKw00}b07ed1Y6D|S3@W9QMn0k`{ZM?7kcKj+S$G(G zWv!1tB!(%cL^*{=RFGT1?*ixyvAhUVnq^CKoF=0_V++f(=1kEmFBAHW6^X$bj~pd+ znDymruO!i24(|`)S-5C0{e+iR3JSZtTHMFqGcNLow~Fr%Z)xnS<~~# znrMQm0p7!K+CWeQSD8A5yRcibUECHu=ld6w;3Nu2+OkiE1=HR>WatIMl*8Cv&h5?B zw#>YT$y_qY+OkR9fhf*kX1A;#l-A6+#Z1rSJf5Mr=_tf*`>+PtI^lZO#H;|ih~5=> z#+>U`o(jn?Q3)XRx`fWUOZ0#$EZZwYtN943cz4hFGU#NZtIG!L1n_^vo6 zn(lR>M`)ZZGm;;BlsWtDa^HSUeHeTByEVSPf)DM|Xkz>X^9q56gt!C?1N`hJqjG|V zg$AV$^A+vpD{bLsc+ZpS;&g3cNb5~rMdT)3whtG5-u?RUdGty0uC(!QNiTGyHW(7- z1Az4TKCFT|&kTprc=Kw5k)TuN1HMT%9+D&)e}>@xVRWtoxJa1^P#tau8ES!R&v0sq zVv3Glu{AiYMvB_c3_QlOHx7n^yfC}Ki^y2M$9I?!foP{(S37;mFfgGEl{!rPNJHKJVUy3J|CB zfCs=d!Biucnj*%6Uf`p`(yB~~Gw!W&fjys2QI0k7i4i+=Sx>9C9i2{^bGYo*(MfZM z#(Ou-2nwpO#}69)zKbdcbCHO1uIH;}k={qIO$q!Vqs53H=SnLE+jG2LT?q%) zr7%E_`5_+YMZrguRSZUuU^J4yh?>(JAmBLu6=A2VyvZY>|Xor$a+Vp=V? z=Yk69^RC;2H5;M2I%!8KBYZ!`bfTWPOdt6hr^?sWkA=aPyS$#uLrW9~H=8R9ME0ga zyD5o=TN9zFgFSQoX=Cr}Cky7&oe(b4nPPm}Z0qAYJ}**E6*IrBqFrqg@GmGV604^w zuC7tW5uM+FWw*vfv3Z_pPZ;gU5M3R8*yxw*MCoRYu;RcD^9}xdlwGybiO#`^f$(C5 z-}egF*=x;bE-c`X$WfODZ_}n4n`RBEDOmW34X;z(IVF8hIuPJ2r=Sx7rCYAjF%ad4 zWL!k)9Nq`9oH^rCCx_Nfps?zb0-RDQY}?OlDRkG%LA65tjjVE&~yYS%6^cV zkkl<)Ks9ht?9_IL3YnJ07vHsrX(1d8v&b}`Ge}ATBhBiUFM#t%B7;6m)ozSJR9_^OAA!7tS<5c(0{zaR5BA-KKE9+sg( zFToGD*OJx7KnAfhK%vgY+@BOe8wzc$?j?qvGi*e!HPTD;V$!a|NKCHah(c$2e@AzY zaOq|8%roGJ>zpxHQELye?tJ|@ztOHkRd=cGE$|~4oBQ`NBg>@GA?llmEKOTSZ6`4#1vm;;tX0}&KPXutCDO>E!O^GJ?Iq{SpjBt zt-jRwFhE!$(yf#d#UmYY${M3(0Pzb{S#UYcz(LBt_NiOvdtzZ~ntCN2(lA@j%5?ju?Zh*`(OR+@7)51W2;f7pnT2$7_ zPJs%ZW?M;h93mb(FNpA|&nOgHS5vErGqS{$A1z>N?nG+Y-zbN+(@m|dow;pml#)6$Y|SfSJzPpAFq=)mTMF=-O0aZfl7YU znsNRdf0QpV6_>odq+G^BQJ!Q7fK}q%XoxK_i>VXI6!CyG6L8pLjkmyakC#PqQoUNquf}~0qd^iae3%PerBGEcUJd7ybe)up2{Mb&^gU9e7VV^; z7a^{#zqaL|+DJLb$uO`aRZ9HJ^r{>Js>5IkV_48D48m)$#@jeGKOdV#1J}U=0v_Gw z!@8_=D`}$H-LH+NT|!BbCIS63avvck-jPgVbv980wD|Ekftif!N2q6q-s9U#W_d0;{O~HXfRk{ z%s-Wl*^Xq2Sn#q(7Kaf2!tVlp1Y*#*lLLE2m4V=gKy>hT#oZQoMZryrEL?+8vL9E8 zsISVJc%XG_bD&VwHY?tl)Kcs1d^Kzm5nI4%!1(Zb!3J(m*`^pu9C`tbN>A9TO8nVJ zdGne$YjxZaN7*8t!iBAhbh+%9c?UEnDDwl@iZJ^NA@*`zr=r&sktlNUT@5`Gqh1*oWlw-?_L_jN8&~+P(U!CDvC@O-#OY({r2ZFnyn1%_wz~TE zf1+3Y?a1+6c}fWN4g$TBig%`zMk@>52837*IPI;(i)hbF0i~yI!HgZp!yF_UCsyjw z`sG0ByC-)z_naL^;Cad&2G`UcD%W^22|rQv{sD3Nb&`0ozv*BZP#hrr!Jh0} zT}??HR|Mh7pa2<8AM#C-v%H>MS{$(^^Tfn^Gc%zi`5Hyi;%M%oxDrPrrc~DVGTrYf zDdle~(PT8a5q8XW$IW{;gy^T%$14K~iEi;-mX&;^7??U`vLp%yVz!zma~Mk-d@5f@ zM;1wj2MzNZYf8o=C#~U*ypLlxU@?o{Ula#pJI0#@HTe$0HT3&Fkd%fu=4KyM|f)JzXQ z)0kI44$0oBMA=EHAQQfifga8>UAN9WU0S=yD_&Xtny8W8)GvZS@sK~j*?>$Eq_w$# zFc745f%}`}0~=DxHzpk@#E%qEF$&$-f{g_@Lbkv-XjZ|S$X1D)B#M}WoV&5R1go+M zgOw=<57ki1L!6&mP24zwSOqy_AJC#QX(Aq$1zsF-8O~G{=7PDuTIF{qTGe+aSe8eM zXFXW@LAlVECy0R~eJyBoF)(iDC1w~>gcO^MEB?IPqyFYaV;*<6jAosTtYFsEah8a@ zMH(qATnxL5)4E8ccMY0QWc<6TTcWd=hT?iIX(umXJBuTBN{y&PB#jYF><08CFq&yw5&rb>$e)7BoN@Wor2Ag#3KnvsjJ*zxf&7I}Os(h-Z2WJ0f*^lmBHQ}Kg{0F@?U6tsSK`#K0L#9()E$KgI&%I}Evi3UA1dZ$M-x9Rmh zY=bv2#mmUK6WbfMhZMK{Sg_A{@m-cbsNPxR-esFvnpYMLP4do~z`1O*Wx1r2%YH9Q z_Rhv>TY!1 zg*|+YTH2*A<3h1sIKo8_iH7P-VROO*`v2VW@VrDJ$nHbFg5m#@uZGP3vPb=jvG})L z>Pj7T3-srUW|nna^0=PR782NyT)tq1Hh zcL(3Lp6zyU3&Q$YV^7ig)5-B>%g&hK3(%tX;DsuWi6H2L3PF)nn!CP*LN`Z}f{K+< zjgGbsKFb%BsLZA?%TuxQzX$g`f$v#=M~m0RuY0P8)!0$c+bGCEu)?W(y3&li zM7naj+x2F~-Aiq3 z3U#`d0xW$Pn0at6{iXmP1CHWs^#_5O8DwFL;aq8YL(0lK1)f{mE(6DiY=a&IN>%BT z!@zBOKutC#ASvuM&Gs2n`3P0DsMa}a;l5PB8%AOsi;_YWq77&}5$qWS%G^)uWy9T) zec71|8;mpk>MR(P7?a@mCYlO6{SYRh*afTV87;1AQ%!ugn*nHx$0FHdBa}qg{q^Xk*6FD=+ql)^} zb}ppBkV8xv1+|-;3&TeTm4!zbiFG5gObjElDbGVHMR}eJW+XJZAR|{;_SZ{ke(0YF zBZfb*V8h&|vs3b?GN^Os7hT`g5rP(3f(jur?O-fe`|5}c`E3s0VY?0p*I$Qgg?>Z~ z(C$$-a7WXQw!zqsJ7WG!y0#-SD5BRIXw_HeWfgos4@nPmLYZqWEdckoXYdjl5NLq( zO4hR#B|!XpbnC-2aV&t-s#j>VMEhEa3p*;{OXr24Mw|_}vY~{&P!Cla$xs}af2f(W zKSj5#3*T}r0G5G1t=o=67gjLe;A4L1P=O)VJRlYmZdnUJnvlpB6J8|`JD0M|t635x8)%7?hhiv70B_PMAh$4Mgb15F;+kw8<<8TCaL5nh z)M{i^gD@YSYmh?Ra)ab4k)eS;LhtFFKHv;8OK#)bWEY-C+JMt4C1|B!24+sCDGPnF z9+n-~e~N)fDS^mPj3uTdZlD?LE8LG0e}-V8d4z<#q2)!JRDXF*s zpDj<~nWjc!^VwaOZhqHoT@pZH69S_Gu2qBM*0$0NEoP^ zk3&1g=A9x&sCklL6>P+4v&0&N)eUkO%gK>TNdxVLgq{0$MoZn#G(()-L`=4k>k}a- zcN!6G#d9QCasmg%tgo`P1iri_8yQ+ss>Ga=RNCW(JJ)-DKCVXjDV4~0FCS74n;tB~ z#``@lDG6|ks{Rt`m{Z-d<*>U8`=D$#uQFA8cK1uv%)g3f_lSRUt9fFbPsyx(%I^UrU!P zxg*#(TR2kj&f3N`pG~kbft?$HFqr7VENGSzF)zv1C6bNN)hYD4q3_J42UPC6TsqoG zzW|?4OSo9}+G-b)Ug#U)XkBc0)#@JUz8a%S#TmVo*^`CG_ANUlA0gZ9(6A-4{}d%1 z+B2Hc89!44-!<*M|J4NF%NKZS&3J1R$7f}2RF3hoV!Pz)QG;u8Orw5j2YB&0y}3P# zK$=CE_zzYPrGBA!L;4D9^lG?zvq8OI=>`mI;)8E0Z&Ys@xDl@;NBv2iRSGcc-x@B} zMc%1j`$T>@*J#7qek<&eaQ#JI`qKRhOAAnEh4t1g?JF3bj}q7xq7M&%HxuzF;td5k zWinC#FE#tg+lMEEUCE|CmHRNU9OS1@2ES%lg1$f1{FPzp5eUNXmqbht8I1n=w?ESt zQ9E0h4=Y(%EifbAaq0YchjtztRl-`MKi5;4Cy7bTvtbp>VNhQ9J9<&A2({cc(j~m zq;@Mkwa25zj}hz#X1$R%;9C<)u>!Eoe_h%~D@dlPG^0kmQZHxhJtx9?Zk4h{L-3qY zU<<{@X0_=#*x=`0EkQE&uZFQG`WM6{KB=fRDpAp_miy237+>=C1#i%vN6e0MtW_k8 zdKvASi{+mPN=(|*=jMk1In)oMCqI4?O&Fw_(=jf-!Ow^S_z=IEP3Q7-2C#~zNURbi zlJ@tDrf>i*7rPH=P@Ev1*`br#gUDx0n$u?*fAgN~78o)@ag6J_Idx;yZdpEZHofLu z1uwSCsIJs$NhgYLS9fWhT0VaVrpc_HF1cKZMZCZ_ION*h$-$06WN~8X|Ao8iRcrqZ zC@YCNa@n?LFVttdLz4&&Jpw%E(`PQ}!<1s8@}LYnu+IR&bqjkP>J^1XmCTtFE<|Q9 zhU8X+g!=><;3&C6A~yr=Y8nyP`iV8KvZ`Wp>k1brz&)}x1yImyC`A3;-YQ7*eQRSE z5#R@{1L721e1InjAqw^R+S)n4w+^>&(ODv4NWQn^gX_wRD3|G2W@F;LDbPpte7B4^ zOet$)1_znfU4#K{BK%XvptTp0lJkcydPd@pDt-gQicS`^x9T6&*K@{mXdphT7ijjw zqBH4R0KdRSAsFG}u)nzGJp|{#@ZMDnLFHg0qs`<;A1}bvqqF>;?KFuS)CJFZq~p6d zUExNK)7uQGPG+;;4YFcc`J);mByg5DpEyl~-GjCa6~$Xk(5`ge|MJIFd#f)N<45an zL?F6MG%;F`fdkhcPHJQ^?yf$4zg;YbMtGvjtZxG|t=NYaWZtRJqO9^UD6w)e?sSlH4GqlJ zl!uCOi#Hyw!g#X zvrfZ9Oim595{P;vp<-l6(p@dih?KJJ$3q9Y6Ju%+_@!+XWBC*&G7P@m^|_n&sAccc zpjq?9$&XG-$&U)TzA(J9K`_^Hum?=H)$XBo@v?bxv65@TLe7DO%#bVTm|j4ql$$ zrTdp0 zdNSf5pf8^NYZLGN5P3rG_vJsb;r;sx5BcyODfPa1U*So1ynkQwVRw0?-uvRyntx@> z`}Yi9J=VT2UH)qZzhuvQMgRW={sRN(=^XnNO6UO~ z{E=G!d!|p|!haqBPXVKOA6eg*;O>|7|F2Vi1&RI}eE8Eb@Sx07B;TLAgcR`m;{F9D z^;3ZlW8f)x>(Bb#V*hUfe}W5s+F1|cp0?lvBJ3l%;r-X*{)rF!b5A`5Z+wUYd!(M< zW&JB&>{Bg%#c+H;gM1`G!v9)}KLXI6cE4_c^d2T z5XtjM^1sFR7d!la`uvB$nMV>A{GHGLGmPd@g@>kj>dN;JNb^YXzs>uvZSz0q^XoG9 z;3W7+G_t>=&p%uS9~F9F{?ubY_>uE{$^G}4|2r4Lr#;J<3Ke{UXI>vu8+&l`tFNNy-532oo;Q0?jqG_9X)06aQS?Cxp}yJK9Z}&6S;pf_~%trMjZV9-R{{l!uvl6xciLW 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 -
    22. Copy the object
    23. - -
    24. Class to JSON
    25. - -
    26. Class to IDL
    27. - + This is a Java object toolset. Using document: GitHub +
    28. Copy the object
    29. + +
    30. Class to JSON
    31. + +
    32. Class to Thrift IDL
    33. + +
    34. Class to XML
    35. + ]]>
      Fix:rename "Class To IDL" to "Class To Thrift IDL" -
    36. Fix bug:fix "Class To Thrift IDL" BigDecimal conversion exception
    37. +
    38. New feature:Added the ability to quickly convert Java classes to XML
    39. +
    40. New feature:Customize to enable specified functions
    41. ]]>
      @@ -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 11/21] =?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 -
    42. New feature:Customize to enable specified functions
    43. +
    44. fix feature:Resolve version compatibility issues and adapt new versions of the IDE
    45. ]]>
      - + @@ -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 12/21] =?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 +
    46. add feature:Optimize the class to xml generation results
    47. +
    48. fix feature:Optimize the class to xml generation results
    49. +
    50. fix bug:Fix class to Thrift-IDL function NPE problem
    51. ]]>
      From e5fd066ae6da36d3e4c8b982396852ac03e4159e Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 24 Dec 2023 17:29:13 +0800 Subject: [PATCH 13/21] 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 14/21] 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 15/21] =?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 16/21] 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 17/21] =?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; } From 32ff35c92861b5402e75ed7d07a47d7f9b665095 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 8 Jun 2025 00:36:51 +0800 Subject: [PATCH 18/21] =?UTF-8?q?1.4.0=E7=89=88=E6=9C=AC=EF=BC=9A=20?= =?UTF-8?q?=E5=AE=8C=E6=88=90Object=20Copy=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- build.gradle | 6 +- .../action/ClassToJsonAction.java | 8 +- .../objecthelper/action/ClassToXMLAction.java | 8 +- .../objecthelper/action/ObjectCopyAction.java | 117 ++++++++ .../{WhetherEnum.java => EnableEnum.java} | 12 +- .../objecthelper/common/util/PsiUtils.java | 70 ++++- .../config/PluginConfigModel.java | 8 +- .../generator/AbstractMethodGenerator.java | 65 +++- .../copy/AbstractObjectCopyStrategy.java | 17 +- .../copy/SmartObjectCopyGenerator.java | 44 +++ .../strategy/BuilderObjectCopyStrategy.java | 30 +- .../copy/strategy/SetObjectCopyStrategy.java | 18 +- .../method/ObjectCopyMethodGenerator.java | 83 ++---- .../objecthelper/ui/ClassSearchDialog.java | 277 ++++++++++++++++++ .../plugin/objecthelper/ui/ConfigPage.form | 20 +- .../plugin/objecthelper/ui/ConfigPage.java | 12 +- src/main/resources/META-INF/plugin.xml | 8 + 18 files changed, 649 insertions(+), 156 deletions(-) create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyAction.java rename src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/{WhetherEnum.java => EnableEnum.java} (66%) create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/SmartObjectCopyGenerator.java create mode 100644 src/main/java/cn/bigcoder/plugin/objecthelper/ui/ClassSearchDialog.java diff --git a/README.md b/README.md index 2e927f6..1d7a602 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,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 = enable` 代表当目标字段在源对象中不存在时,是否以注释的形式生成代码,如果为 `disable`,则代表不生成这一个字段拷贝代码。 ## 未来功能支持计划 diff --git a/build.gradle b/build.gradle index 196c339..731142b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'cn.bigcoder.plugin' -version '1.3.3' +version '1.4.0' repositories { mavenCentral() @@ -29,9 +29,9 @@ intellij { } patchPluginXml { sinceBuild = '211' - untilBuild = '281' + untilBuild = '301.*' changeNotes = """ - 1. new feature: Object Copy Method support builder mode. + 1. new feature: Object Copy support lambda and common scene. """ } test { 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 8e96e8c..7341f6b 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java @@ -1,5 +1,7 @@ package cn.bigcoder.plugin.objecthelper.action; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; + import cn.bigcoder.plugin.objecthelper.common.enums.FunctionSwitchEnum; import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; @@ -10,15 +12,13 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.psi.PsiClass; - import java.awt.datatransfer.StringSelection; - -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; +import org.jetbrains.annotations.NotNull; public class ClassToJsonAction extends AbstractClassAnAction { @Override - public void actionPerformed(AnActionEvent anAction) { + public void actionPerformed(@NotNull AnActionEvent anAction) { PsiClass psiClass = getOperatePsiClass(anAction); if (psiClass == null) { return; 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 82cb64c..14cc32a 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java @@ -1,5 +1,7 @@ package cn.bigcoder.plugin.objecthelper.action; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; + import cn.bigcoder.plugin.objecthelper.common.enums.FunctionSwitchEnum; import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; @@ -8,17 +10,13 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.psi.PsiClass; - -import groovy.json.StringEscapeUtils; import java.awt.datatransfer.StringSelection; import org.jetbrains.annotations.NotNull; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; - public class ClassToXMLAction extends AbstractClassAnAction { @Override - public void actionPerformed(AnActionEvent anAction) { + public void actionPerformed(@NotNull AnActionEvent anAction) { PsiClass psiClass = getOperatePsiClass(anAction); if (psiClass == null) { return; diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyAction.java new file mode 100644 index 0000000..55f8358 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyAction.java @@ -0,0 +1,117 @@ +package cn.bigcoder.plugin.objecthelper.action; + +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperateFieldName; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getOperatePsiClass; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClassName; + +import cn.bigcoder.plugin.objecthelper.common.util.NotificationUtils; +import cn.bigcoder.plugin.objecthelper.common.util.StringUtils; +import cn.bigcoder.plugin.objecthelper.generator.Generator; +import cn.bigcoder.plugin.objecthelper.generator.copy.SmartObjectCopyGenerator; +import cn.bigcoder.plugin.objecthelper.ui.ClassSearchDialog; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.CaretModel; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiClass; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +public class ObjectCopyAction extends AbstractClassAnAction { + + @Override + public void actionPerformed(@NotNull AnActionEvent anAction) { + PsiClass sourcePsiClass = getOperatePsiClass(anAction); + String operateFieldName = getOperateFieldName(anAction); + if (sourcePsiClass == null || StringUtils.isEmpty(operateFieldName)) { + NotificationUtils.notifyInfo(anAction.getProject(), "The source object type was not obtained"); + return; + } + Project project = anAction.getProject(); + PsiClass targetPsiClass = null; + if (project != null) { + ClassSearchDialog dialog = new ClassSearchDialog(project, "Search target object class"); + if (dialog.showAndGet()) { + targetPsiClass = dialog.getSelectedClass(); + } + } + if (targetPsiClass == null) { + NotificationUtils.notifyInfo(anAction.getProject(), "The target object type was not obtained"); + return; + } + String targetParameterName = StringUtils.firstLowerCase( + Objects.requireNonNull(getPsiClassName(targetPsiClass))); + // 防止方法入参和返回参数名称一致 + if (operateFieldName.equals(targetParameterName)) { + targetParameterName = targetParameterName + "Res"; + } + // 代码生成器 + Generator generator = new SmartObjectCopyGenerator(sourcePsiClass, targetPsiClass, operateFieldName, + targetParameterName); + + insertCode(project, generator.generate()); + } + + /** + * 将代码插入光标处 + * + * @param project + * @param copyCodeStr + */ + private void insertCode(Project project, String copyCodeStr) { + Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); + if (editor == null) { + return; + } + CaretModel caretModel = editor.getCaretModel(); + int offset = caretModel.getOffset(); + Document document = editor.getDocument(); + // 删除光标所在的变量 + int startOffset = findVariableStartOffset(document, offset); + int endOffset = findVariableEndOffset(document, offset); + if (startOffset >= 0 && endOffset >= 0) { + WriteCommandAction.runWriteCommandAction(project, () -> { + document.deleteString(startOffset, endOffset); + }); + } + + WriteCommandAction.runWriteCommandAction(project, () -> { + document.insertString(offset, copyCodeStr); + }); + } + + private int findVariableStartOffset(Document document, int offset) { + int start = offset; + while (start > 0) { + char c = document.getCharsSequence().charAt(start - 1); + if (!Character.isJavaIdentifierPart(c)) { + break; + } + start--; + } + return start; + } + + private int findVariableEndOffset(Document document, int offset) { + int end = offset; + int length = document.getTextLength(); + while (end < length) { + char c = document.getCharsSequence().charAt(end); + if (!Character.isJavaIdentifierPart(c)) { + break; + } + end++; + } + return end; + } + + @Override + public boolean actionShow(AnActionEvent anActionEvent) { + PsiClass sourcePsiClass = getOperatePsiClass(anActionEvent); + String operateFieldName = getOperateFieldName(anActionEvent); + return sourcePsiClass != null && !StringUtils.isEmpty(operateFieldName); + } +} \ No newline at end of file diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/WhetherEnum.java b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/EnableEnum.java similarity index 66% rename from src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/WhetherEnum.java rename to src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/EnableEnum.java index 918c484..52067fa 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/WhetherEnum.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/EnableEnum.java @@ -4,13 +4,13 @@ * @author: Jindong.Tian * @date: 2023-12-24 **/ -public enum WhetherEnum implements CommonEnum { - YES("yes"), - NO("no"), +public enum EnableEnum implements CommonEnum { + ENABLE("enable"), + DISABLE("disable"), ; private String code; - WhetherEnum(String code) { + EnableEnum(String code) { this.code = code; } @@ -18,11 +18,11 @@ public String getCode() { return code; } - public static WhetherEnum nameOf(String modify) { + public static EnableEnum nameOf(String modify) { if (modify == null) { return null; } - for (WhetherEnum item : values()) { + for (EnableEnum item : values()) { if (modify.equals(item.getCode())) { return item; } 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 c0cc060..686ba38 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 @@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiClassType; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; import com.intellij.psi.PsiFile; @@ -18,7 +19,9 @@ import com.intellij.psi.PsiModifierList; import com.intellij.psi.PsiParameter; import com.intellij.psi.PsiType; +import com.intellij.psi.PsiVariable; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.util.PsiTreeUtil; import org.apache.commons.compress.utils.Lists; import org.jetbrains.annotations.NotNull; @@ -58,6 +61,25 @@ public static PsiClass getOperatePsiClass(AnActionEvent actionEvent) { PsiElement psiElement = getOperatePsiElement(actionEvent); if (psiElement instanceof PsiClass) { return (PsiClass) psiElement; + } else if (psiElement instanceof PsiVariable) { + PsiType type = ((PsiVariable) psiElement).getType(); + if (type instanceof PsiClassType) { + return ((PsiClassType) type).resolve(); + } + } + return null; + } + + /** + * 获取当前操作下的 {@code PsiClass} + * + * @param actionEvent + * @return + */ + public static String getOperateFieldName(AnActionEvent actionEvent) { + PsiElement psiElement = getOperatePsiElement(actionEvent); + if (psiElement instanceof PsiVariable) { + return ((PsiVariable) psiElement).getName(); } return null; } @@ -228,14 +250,54 @@ public static List getAllPsiFields(PsiClass psiClass) { 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)) { + modifierList.hasModifierProperty(PsiModifier.STATIC) || + modifierList.hasModifierProperty(PsiModifier.FINAL) || + modifierList.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { return false; } return true; } + /** + * 根据类名称模糊匹配项目中的PsiClass + * + * @param project + * @param classNameStr 模糊匹配的类名称(大小写不敏感) + * @return + */ + public static @NotNull List matchPsiClassByName(Project project, String classNameStr) { + JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + PsiShortNamesCache shortNamesCache = PsiShortNamesCache.getInstance(project); + List exactMatches = new ArrayList<>(); + List fuzzyMatches = new ArrayList<>(); + + // 处理带包名的情况 + if (classNameStr.contains(".")) { + PsiClass cls = psiFacade.findClass(classNameStr, GlobalSearchScope.allScope(project)); + if (cls != null) { + exactMatches.add(cls); + } + } + + // 获取所有类名 + String[] allClassNames = shortNamesCache.getAllClassNames(); + for (String className : allClassNames) { + if (className.equalsIgnoreCase(classNameStr)) { + // 完全匹配 + PsiClass[] classes = shortNamesCache.getClassesByName(className, GlobalSearchScope.allScope(project)); + exactMatches.addAll(Arrays.asList(classes)); + } else if (className.toLowerCase().contains(classNameStr.toLowerCase())) { + // 模糊匹配 + PsiClass[] classes = shortNamesCache.getClassesByName(className, GlobalSearchScope.allScope(project)); + fuzzyMatches.addAll(Arrays.asList(classes)); + } + } + + // 合并结果,优先展示完全匹配的类 + exactMatches.addAll(fuzzyMatches); + return exactMatches; + } + /** * 递归获取类中所有字段 * @@ -249,4 +311,4 @@ private static void recursiveAllFields(PsiClass psiClass, List psiFiel psiFields.addAll(Arrays.asList(psiClass.getFields())); recursiveAllFields(psiClass.getSuperClass(), psiFields); } -} +} \ No newline at end of file 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 66fc4b6..e136cbb 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java @@ -2,7 +2,7 @@ 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.common.enums.EnableEnum; import java.util.Objects; /** @@ -35,7 +35,7 @@ public class PluginConfigModel { /** * Object Copy Method 功能中,Source 和 Target 对象之间差异的字段,是否以代码注释的形式生成代码 */ - private WhetherEnum objectCopyMethodFieldGenerateAnnotation = WhetherEnum.YES; + private EnableEnum objectCopyMethodFieldGenerateAnnotation = EnableEnum.ENABLE; /** * Object Copy Method 功能中,使用builder模式生成拷贝代码时的判断依据,当目标对象类中包含正则所指定的方法,则默认按照builder模式生成,否则使用set模式生成 @@ -83,12 +83,12 @@ public void setObjectCopyMethodFieldGenerateMode( this.objectCopyMethodFieldGenerateMode = objectCopyMethodFieldGenerateMode; } - public WhetherEnum getObjectCopyMethodFieldGenerateAnnotation() { + public EnableEnum getObjectCopyMethodFieldGenerateAnnotation() { return objectCopyMethodFieldGenerateAnnotation; } public void setObjectCopyMethodFieldGenerateAnnotation( - WhetherEnum objectCopyMethodFieldGenerateAnnotation) { + EnableEnum objectCopyMethodFieldGenerateAnnotation) { this.objectCopyMethodFieldGenerateAnnotation = 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 c3912c2..7ecc61e 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractMethodGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractMethodGenerator.java @@ -1,18 +1,27 @@ package cn.bigcoder.plugin.objecthelper.generator; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.BLANK_SEPARATOR; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.BRACE_OPEN; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.COMMA_SEPARATOR; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.PARENTHESIS_CLOSE; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.PARENTHESIS_OPEN; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.VOID; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getMethodName; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getMethodReturnClassName; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClass; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClassName; +import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiParameters; + 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.openapi.project.Project; +import com.intellij.psi.PsiClass; 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; - -import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.*; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.*; +import java.util.Objects; +import org.apache.commons.collections.CollectionUtils; /** * @author: Jindong.Tian @@ -25,6 +34,42 @@ public abstract class AbstractMethodGenerator implements Generator { protected Project project; protected PsiMethod psiMethod; + /** + * 方法第一个参数名称 + */ + protected String firstParameterName; + /** + * 方法返回参数名称 + */ + protected String targetParameterName; + /** + * 方法第一个参数类型 + */ + protected PsiClass firstParameterClass; + /** + * 方法返回参数类型 + */ + protected PsiClass targetClass; + + public AbstractMethodGenerator(PsiMethod psiMethod) { + if (psiMethod == null) { + return; + } + this.project = psiMethod.getProject(); + this.psiMethod = psiMethod; + // 获取参数列表第一个参数 + PsiParameter firstParameter = getParameters().get(FIRST_INDEX); + this.firstParameterClass = getPsiClass(firstParameter.getType(), project); + // 获取返回值类型 + this.targetClass = getPsiClass(getReturnType(), project); + this.firstParameterName = firstParameter.getName(); + this.targetParameterName = StringUtils.firstLowerCase(Objects.requireNonNull(getPsiClassName(targetClass))); + // 防止方法入参和返回参数名称一致 + if (firstParameterName.equals(this.targetParameterName)) { + this.targetParameterName = this.targetParameterName + "Res"; + } + } + public String generate() { if (!check()) { return null; @@ -37,9 +82,9 @@ public String generate() { protected StringBuilder generateMethodFirstLine() { StringBuilder builder = new StringBuilder(); - PsiUtils.getMethodModifies(psiMethod.getModifierList()).forEach(e -> builder.append(e.getName()).append(BLANK_SEPARATOR)); - builder.append(getMethodReturnClassName(psiMethod) + BLANK_SEPARATOR) - .append(getMethodName(psiMethod)) + PsiUtils.getMethodModifies(psiMethod.getModifierList()) + .forEach(e -> builder.append(e.getName()).append(BLANK_SEPARATOR)); + builder.append(getMethodReturnClassName(psiMethod)).append(BLANK_SEPARATOR).append(getMethodName(psiMethod)) .append(PARENTHESIS_OPEN) .append(StringUtils.join(getParameters(), PsiParameter::getText, COMMA_SEPARATOR)) .append(PARENTHESIS_CLOSE + BRACE_OPEN); @@ -48,10 +93,12 @@ protected StringBuilder generateMethodFirstLine() { /** * 生成方法体 + * * @return */ protected abstract String generateMethodBody(); + /** * 检查是否具备生成方法所需要的环境 * 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 index 5e27888..5a63fb3 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/AbstractObjectCopyStrategy.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/AbstractObjectCopyStrategy.java @@ -1,18 +1,14 @@ package cn.bigcoder.plugin.objecthelper.generator.copy; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClassName; - +import cn.bigcoder.plugin.objecthelper.common.enums.EnableEnum; 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; @@ -39,16 +35,13 @@ public abstract class AbstractObjectCopyStrategy implements Generator { */ protected String targetParamName; - public AbstractObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String sourceParamName) { + public AbstractObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String sourceParamName, + String targetParamName) { 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"; - } + this.targetParamName = targetParamName; } @Override @@ -80,7 +73,7 @@ public String generate() { if (secondFieldNames.contains(field.getName())) { result.append(generateFiledCopy(field)); } else if (PluginConfigState.getInstance().getObjectCopyMethodFieldGenerateAnnotation() - == WhetherEnum.YES) { + == EnableEnum.ENABLE) { // 如果源对象没有该字段,且开启了以注释模式生成代码的开关,则生成注释 annotationLine.add("// " + generateFiledCopy(field)); } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/SmartObjectCopyGenerator.java b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/SmartObjectCopyGenerator.java new file mode 100644 index 0000000..a78fe0f --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/copy/SmartObjectCopyGenerator.java @@ -0,0 +1,44 @@ +package cn.bigcoder.plugin.objecthelper.generator.copy; + +import cn.bigcoder.plugin.objecthelper.config.PluginConfigState; +import cn.bigcoder.plugin.objecthelper.generator.Generator; +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.PsiMethod; +import java.util.regex.Pattern; + +/** + * 根据 sourceClass 和 targetClass 生成字段拷贝代码 + * + * @author: bigcoder84 + * @date: 2025-06-08 + **/ +public class SmartObjectCopyGenerator implements Generator { + + private AbstractObjectCopyStrategy objectCopyGenerator; + + + public SmartObjectCopyGenerator(PsiClass sourceClass, PsiClass targetClass, String sourceParameterName, String targetParameterName) { + // mainClass 代表以哪个类字段为基础生成字段拷贝代码 + String builderRegex = PluginConfigState.getInstance().getBuilderInstanceMethodName(); + + // 判断目标类是否有 builder 方法 + Pattern pattern = Pattern.compile(builderRegex); + for (PsiMethod method : targetClass.getMethods()) { + if (pattern.matcher(method.getName()).matches()) { + // 有 builder 方法,使用 BuilderObjectCopyStrategy + objectCopyGenerator = new BuilderObjectCopyStrategy(sourceClass, targetClass, sourceParameterName, + targetParameterName); + return; + } + } + objectCopyGenerator = new SetObjectCopyStrategy(sourceClass, targetClass, sourceParameterName, + targetParameterName); + } + + @Override + public String generate() { + return objectCopyGenerator.generate(); + } +} 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 index fb72f61..2960c5c 100644 --- 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 @@ -15,27 +15,18 @@ **/ public class BuilderObjectCopyStrategy extends AbstractObjectCopyStrategy { - public BuilderObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String sourceParamName) { - super(sourceClass, targetClass, sourceParamName); + public BuilderObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String sourceParamName, + String targetParamName) { + super(sourceClass, targetClass, sourceParamName, targetParamName); } - - /** - * 生成类似如下代码: - * - * 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; + String className = getPsiClassName(targetClass); + return className + BLANK_SEPARATOR + super.targetParamName + " = " + className + ".builder()" + LINE_SEPARATOR; } + @Override protected String generateFiledCopy(PsiField field) { return "." + field.getName() + "(" @@ -48,13 +39,4 @@ protected String generateFiledCopy(PsiField field) { 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 index 48dc32a..f58c2a2 100644 --- 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 @@ -16,8 +16,8 @@ **/ public class SetObjectCopyStrategy extends AbstractObjectCopyStrategy { - public SetObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String sourceParamName) { - super(sourceClass, targetClass, sourceParamName); + public SetObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String sourceParamName, String targetParamName) { + super(sourceClass, targetClass, sourceParamName, targetParamName); } /** @@ -33,8 +33,7 @@ public SetObjectCopyStrategy(PsiClass sourceClass, PsiClass targetClass, String @Override protected String generatePrefix() { String psiClassName = getPsiClassName(targetClass); - return generateNullCheck(sourceParamName) + LINE_SEPARATOR + - psiClassName + BLANK_SEPARATOR + targetParamName + "= new " + psiClassName + "();" + LINE_SEPARATOR; + return psiClassName + BLANK_SEPARATOR + targetParamName + " = new " + psiClassName + "();" + LINE_SEPARATOR; } @Override @@ -45,15 +44,6 @@ protected String generateFiledCopy(PsiField field) { @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;}"; + return ""; } } 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 63a4b78..57e8334 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,16 +1,11 @@ package cn.bigcoder.plugin.objecthelper.generator.method; -import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.getPsiClass; +import static cn.bigcoder.plugin.objecthelper.common.constant.JavaKeyWord.SEMICOLON_SEPARATOR; -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 cn.bigcoder.plugin.objecthelper.generator.Generator; +import cn.bigcoder.plugin.objecthelper.generator.copy.SmartObjectCopyGenerator; import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiParameter; -import java.util.regex.Pattern; /** * @author: Jindong.Tian @@ -18,72 +13,50 @@ **/ public class ObjectCopyMethodGenerator extends AbstractMethodGenerator { - /** - * 方法第一个参数名称 - */ - private String firstParameterName; - - private void init(PsiMethod psiMethod) { - if (psiMethod == null) { - return; - } - super.project = psiMethod.getProject(); - super.psiMethod = psiMethod; - this.firstParameterName = getFirstParameter().getName(); + public ObjectCopyMethodGenerator(PsiMethod psiMethod) { + super(psiMethod); } public static ObjectCopyMethodGenerator getInstance(PsiMethod psiMethod) { - ObjectCopyMethodGenerator objectCopyMethodGenerator = new ObjectCopyMethodGenerator(); - objectCopyMethodGenerator.init(psiMethod); - return objectCopyMethodGenerator; + return new ObjectCopyMethodGenerator(psiMethod); } /** + * 生成对象拷贝方法提 * 此方法中不应该存在判空的操作,依赖环境的建议重写父类的check方法,在生成早期拦截异常情况 * * @return */ @Override protected String generateMethodBody() { - AbstractObjectCopyStrategy copyStrategy = getCopyStrategy(); - return copyStrategy.generate(); + StringBuilder stringBuilder = new StringBuilder(); + // check null line + String nullCheckStr = generateNullCheck(); + stringBuilder.append(nullCheckStr); + + // object copy block + Generator generator = new SmartObjectCopyGenerator(firstParameterClass, targetClass, firstParameterName, + targetParameterName); + stringBuilder.append(generator.generate()); + + // return line + stringBuilder.append("return ") + .append(targetParameterName) + .append(SEMICOLON_SEPARATOR); + return stringBuilder.toString(); } - 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); - } - } - return new SetObjectCopyStrategy(sourceClass, returnClass, this.firstParameterName); - } /** - * 获取参数列表第一个参数的{@code PsiParameter} + * 生成类似如下代码: * - * @return - */ - private PsiParameter getFirstParameter() { - return getParameters().get(FIRST_INDEX); - } - - - /** - * 获取参数列表第一个参数的{@code PsiClass} + * if (user == null) { + * return null; + * } * * @return */ - private PsiClass getFirstParameterClass() { - return getPsiClass(getFirstParameter().getType(), project); - } - - private PsiClass getReturnClass() { - return getPsiClass(getReturnType(), project); + private String generateNullCheck() { + return "if(" + super.firstParameterName + "==null){return null;}"; } } \ No newline at end of file diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ClassSearchDialog.java b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ClassSearchDialog.java new file mode 100644 index 0000000..7e49766 --- /dev/null +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ClassSearchDialog.java @@ -0,0 +1,277 @@ +package cn.bigcoder.plugin.objecthelper.ui; + +import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiClass; +import com.intellij.ui.components.JBList; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.components.JBTextField; +import com.intellij.util.ArrayUtil; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.jetbrains.annotations.Nullable; + +public class ClassSearchDialog extends DialogWrapper { + + private final Project project; + private JBTextField classNameField; + private JBList classList; + private PsiClass selectedClass; + private Timer timer; + private static final int DEBOUNCE_DELAY = 500; // 防抖延迟时间,单位:毫秒 + // 定义默认宽度,可按需调整 + private static final int DEFAULT_WIDTH = 700; + // 定义默认高度,可按需调整 + private static final int DEFAULT_HEIGHT = 600; + + public ClassSearchDialog(@Nullable Project project, String title) { + super(project); + this.project = project; + this.setTitle(title); + this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); + this.init(); + } + + @Override + protected void init() { + super.init(); + // 确保对话框显示后输入框获得焦点 + SwingUtilities.invokeLater(() -> classNameField.requestFocusInWindow()); + } + + + @Nullable + @Override + protected JComponent createCenterPanel() { + JPanel panel = new JPanel(new BorderLayout()); + + // 输入框 + classNameField = new JBTextField(); + panel.add(classNameField, BorderLayout.NORTH); + + // 类列表 + classList = new JBList<>(); + classList.setCellRenderer(new ClassListCellRenderer()); + JBScrollPane scrollPane = new JBScrollPane(classList); + panel.add(scrollPane, BorderLayout.CENTER); + + // 输入框文本变化监听,添加防抖机制 + classNameField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + debounceUpdateClassList(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + debounceUpdateClassList(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + debounceUpdateClassList(); + } + }); + + // 给输入框添加键盘事件监听,处理方向下键 + classNameField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_DOWN) { + // 当按下方向下键时,将焦点转移到类列表 + classList.requestFocusInWindow(); + if (classList.getModel().getSize() > 0) { + // 选中列表第一项 + classList.setSelectedIndex(0); + } + } + } + }); + + // 双击列表项确认选择 + classList.addListSelectionListener(e -> { + if (!e.getValueIsAdjusting()) { + selectedClass = classList.getSelectedValue(); + } + }); + + // 添加双击事件监听 + classList.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { // 判断是否为双击事件 + if (classList.getSelectedValue() != null) { + selectedClass = classList.getSelectedValue(); + doOKAction(); // 调用确认操作 + } + } + } + }); + + // 监听候选列表的键盘事件,当有按键输入时,将焦点移回输入框 + classList.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (Character.isLetterOrDigit(e.getKeyChar()) || Character.isWhitespace(e.getKeyChar())) { + classNameField.requestFocusInWindow(); + // 将按下的字符插入到输入框中 + classNameField.setText(classNameField.getText() + e.getKeyChar()); + } + } + }); + + return panel; + } + + + private void debounceUpdateClassList() { + if (timer != null) { + timer.cancel(); + } + timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + SwingUtilities.invokeLater(() -> updateClassList()); + } + }, DEBOUNCE_DELAY); + } + + private void updateClassList() { + String query = classNameField.getText().trim(); + if (!query.isEmpty()) { + List matchedClasses = PsiUtils.matchPsiClassByName(this.project, query); + // 按优先级排序 + matchedClasses.sort(this::compareClasses); + classList.setListData(ArrayUtil.toObjectArray(matchedClasses, PsiClass.class)); + } else { + classList.setListData(new PsiClass[0]); + } + } + + private int compareClasses(PsiClass c1, PsiClass c2) { + int priority1 = getClassPriority(c1); + int priority2 = getClassPriority(c2); + return Integer.compare(priority1, priority2); + } + + private int getClassPriority(PsiClass cls) { + if (isProjectClass(cls)) { + return 1; // 项目内自定义的类 + } else if (isJDKClass(cls)) { + return 2; // Java JDK 自带的类 + } else { + return 3; // 其它类 + } + } + + private boolean isProjectClass(PsiClass cls) { + if (project == null || cls.getContainingFile() == null) { + return false; + } + VirtualFile virtualFile = cls.getContainingFile().getVirtualFile(); + return virtualFile != null && project.getBasePath() != null && virtualFile.getPath() + .startsWith(project.getBasePath()); + } + + private boolean isJDKClass(PsiClass cls) { + String qualifiedName = cls.getQualifiedName(); + return qualifiedName != null && qualifiedName.startsWith("java."); + } + + @Override + protected void doOKAction() { + if (selectedClass == null && classList.getModel().getSize() > 0) { + selectedClass = classList.getModel().getElementAt(0); + } + super.doOKAction(); + } + + public PsiClass getSelectedClass() { + return selectedClass; + } + + // 自定义 ListCellRenderer + private class ClassListCellRenderer extends DefaultListCellRenderer { + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, + boolean cellHasFocus) { + Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof PsiClass) { + PsiClass psiClass = (PsiClass) value; + String className = psiClass.getName(); + String qualifiedName = psiClass.getQualifiedName(); + String query = classNameField.getText().trim().toLowerCase(); + + if (className != null && qualifiedName != null) { + // 仅高亮显示类名 + String highlightedClassName = highlightMatches(className, query); + + // 使用 HTML 格式设置文本样式 + String text = String.format("%s of %s", highlightedClassName, + qualifiedName); + setText("" + text + ""); + // 设置 IDEA 官方类图标 + setIcon(AllIcons.Nodes.Class); + + // 如果是 JDK 自带的类,背景用浅蓝色展示 + if (isJDKClass(psiClass)) { + setBackground(new Color(61, 50, 35)); + if (isSelected) { + setBackground(new Color(46, 67, 110)); + } + } else if (!isProjectClass(psiClass)) { + // 其他类,背景用浅粉色展示 + setBackground(new Color(61, 50, 35)); + if (isSelected) { + setBackground(new Color(46, 67, 110)); + } + } else { + // 项目内的类,保持原有背景 + setBackground(list.getBackground()); + } + } + } + return c; + } + + private String highlightMatches(String input, String query) { + if (query.isEmpty()) { + return input; + } + StringBuilder result = new StringBuilder(); + int lastIndex = 0; + int index = input.toLowerCase().indexOf(query); + while (index != -1) { + result.append(input, lastIndex, index); + // 使用亮黄色作为高亮颜色 + result.append("") + .append(input, index, index + query.length()).append(""); + lastIndex = index + query.length(); + index = input.toLowerCase().indexOf(query, lastIndex); + } + result.append(input.substring(lastIndex)); + return result.toString(); + } + } + +} \ 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 ec970d0..f5572f8 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.form @@ -61,8 +61,8 @@ - - + + @@ -74,8 +74,8 @@ - - + + @@ -86,8 +86,8 @@ - - + + @@ -107,8 +107,8 @@ - - + + @@ -168,8 +168,8 @@ - - + + 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 985abb4..c2b5162 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ConfigPage.java @@ -1,13 +1,15 @@ package cn.bigcoder.plugin.objecthelper.ui; +import cn.bigcoder.plugin.objecthelper.common.enums.EnableEnum; 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 cn.bigcoder.plugin.objecthelper.config.PluginConfigState; import java.util.Optional; -import javax.swing.*; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JPanel; +import javax.swing.JTextField; /** * @author: Jindong.Tian @@ -73,7 +75,7 @@ public PluginConfigModel getCurrentConfigModel() { } ); Optional.ofNullable(this.objectCopyMethodGenerateAnnotation.getSelectedItem()).ifPresent(e -> { - pluginConfigModel.setObjectCopyMethodFieldGenerateAnnotation(WhetherEnum.nameOf(e.toString())); + pluginConfigModel.setObjectCopyMethodFieldGenerateAnnotation(EnableEnum.nameOf(e.toString())); } ); Optional.ofNullable(this.builderInstanceMethodName.getText()).ifPresent( diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 1581439..21b6ba4 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -48,6 +48,9 @@ + + + @@ -65,6 +68,11 @@ description="Converts the Java class to a XML string"> + + +
      \ No newline at end of file From b1ce3dde926af8e9153f7694c71948fc06d529c4 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 14 Jun 2025 10:29:25 +0800 Subject: [PATCH 19/21] update readme.md --- README.md | 81 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 1d7a602..4ab3a4e 100644 --- a/README.md +++ b/README.md @@ -5,55 +5,78 @@
      - + - - + +
      -JetBrains Intellij IDEA ObjectHelper 插件旨在减少开发者重复低效的劳动,使开发者能够更专注于业务逻辑的开发。 +JetBrains Intellij ObjectHelper 插件致力于消除开发者重复性的低效工作,助力开发者将更多精力聚焦于核心业务逻辑开发,显著提升开发效率。 -该插件包含以下功能: +## 功能介绍 -- 对象拷贝 - set模式: +### 生成对象拷贝方法(Object Copy Method) - ![](https://image.bigcoder.cn/7fce876e-fa94-4780-bb14-584068c35963.gif) +- **set 模式**:通过直观的操作流程,快速生成对象拷贝代码。默认使用快捷键 `Alt+Insert` 触发,若快捷键冲突,可在 `settings->keymap` 中搜索 “Generate” 关键字,查看并修改对应的快捷键设置。 - 对象拷贝的快捷键默认是 `Alt+Insert`,如果该快捷键无效,可以在settings->keymap中搜索“Generate”关键字查看具体的快捷键: +![](https://image.bigcoder.cn/7fce876e-fa94-4780-bb14-584068c35963.gif) - ![](https://image.bigcoder.cn/20220916173117.png) +- **builder 模式**:当对象中包含 builder 或者 newBuilder 方法时,插件会智能识别并采用 builder 模式生成代码,实现更优雅的对象构建。 - 当对象中包含`builder` 或者 `newBuilder`方法时,则插件默认会采用 builder 模式生成代码: +![](https://image.bigcoder.cn/20240505142735.gif) - ![](https://image.bigcoder.cn/20240505142735.gif) +> **使用提示**:使用对象拷贝方法时,需先定义好方法签名,插件将自动生成对应的方法体。适用于对象属性较多且需频繁拷贝的场景,如数据传输对象(DTO)的转换等,但在一些对代码灵活性要求较高的场景中,可能需要额外调整。 - 如果你的builder类生成的方法名与插件默认生成的不同,可以在设置中更改: +### 对象拷贝(Object Copy) - ![](https://image.bigcoder.cn/20240505143027.png) +支持在业务代码和 Lambda 表达式中直接进行对象拷贝操作,极大提升了代码编写的便利性和效率。无论是处理复杂业务逻辑,还是简化数据处理流程,都能轻松应对。 +![](https://image.bigcoder.cn/20250614092815.gif) -- Java类转JSON +### Java类转JSON - ![](https://image.bigcoder.cn/20231224171155.gif) +在开发过程中,若需要快速生成一个类的对象的 JSON 示例,只需右键单击目标类名,即可一键生成,方便接口调试、文档编写等场景下快速获取数据结构示例。 -- Java类转Thrift IDL +![](https://image.bigcoder.cn/20231224171155.gif) - ![](https://image.bigcoder.cn/6eee7a02-8e4e-4f11-9b8c-81d661a920c5.gif) +### Java类转 Thrift IDL -- Java类转XML +对于涉及 Thrift 框架的开发场景,通过右键单击目标类名,可快速生成对应的 Thrift IDL 文件,加速服务接口的定义和开发流程。 - ![](https://image.bigcoder.cn/20231224171113.gif) +![](https://image.bigcoder.cn/6eee7a02-8e4e-4f11-9b8c-81d661a920c5.gif) -- 插件配置 +### Java 类转 XML + +![](https://image.bigcoder.cn/20231224171113.gif) + +## 相关配置 + +### 插件配置 File->Settings->Tools->Object Helper 即可进入插件的配置页面 -![](https://image.bigcoder.cn/20231224170305.png) +![](https://image.bigcoder.cn/202506140953046.png) + +- `Class To Json/Thrift IDL/XML`:控制该功能是否启用。 +- `generate field mode`: + - `source`:以源字段类型的字段为基础生成对象拷贝代码。例如在 `Object Copy Method` 功能,方法第一个入参的类型就是源字段类型,方法返回的类型为目标类型字段。 + - `target`:以目标类为基础生成对象拷贝代码。 +- `non-existent field generate annotation`: + - `enable`:当目标字段在源对象中不存在时,以注释的形式生成代码。有助于开发者清晰了解字段缺失情况,方便后续代码维护和修改。 + + - `disable`:不生成不存在字段的拷贝代码,适用于对代码简洁性要求较高,且能确保目标字段在源对象中都存在的场景。 + +> 假设存在两个 Java 类:`ClassA` 与 `ClassB`,`ClassA` 包含 `a`、`b`、`c` 三个字段,`ClassB` 包含 `b`、`c`、`d` 三个字段。当使用 ObjectHelper 插件将 `ClassA` 实例的数据拷贝至 `ClassB` 实例时: +> +> - **`generate field mode=source`**:插件以 `ClassA` 的字段 `a`、`b`、`c` 为基础生成拷贝代码。若 `ClassB` 中不存在对应字段(如 `a`),则根据 `non-existent field generate annotation` 配置决定是否处理该字段。 +> - **`generate field mode=target`**:插件以 `ClassB` 的字段 `b`、`c`、`d` 为基准生成代码。若 `ClassA` 中无对应字段(如 `d`),同样由 `non-existent field generate annotation` 配置来决定是否生成相关代码或添加注释。 + +- `builder instance method`:用于插件判断当前类是否支持builder模式,配置的是一个正则表达式。如果你的builder类生成的方法名与插件默认生成的不同,可以在设置中更改: + +### 快捷键配置 -- `generate field mode = target` 代表以方法返回类型的字段为基础生成对象拷贝; - `generate field mode = source` 代表以方法入参类型的字段为基础生成对象拷贝。 +对象拷贝的快捷键默认是 `Alt+Insert`,如果该快捷键无效,可以在 `settings->keymap` 中搜索 “Generate” 关键字查看具体的快捷键: -- `non-existent field generate annotation = enable` 代表当目标字段在源对象中不存在时,是否以注释的形式生成代码,如果为 `disable`,则代表不生成这一个字段拷贝代码。 +![](https://image.bigcoder.cn/20220916173117.png) ## 未来功能支持计划 @@ -63,8 +86,8 @@ object-helper插件未来功能支持计划: - [x] Class 转 XML(Class To XML) - [x] 个性化配置 - [x] Object Copy Method 功能支持 Builder 模式 -- [ ] Object Copy Method 功能支持 Lambda 表达式 +- [x] Object Copy 功能支持 Lambda 表达式 - [ ] JSON 转 Class(JSON To Class) -- [ ] Class 转 Protobuf IDL(JSON To Class) -- [ ] All Setter -- [ ] 菜单分组显示 +- [ ] Class 转 Protobuf IDL(JSON To Protobuf) +- [ ] Class 转 Baiji(Class To Baiji) +- [ ] 菜单分组显示 \ No newline at end of file From 7dde10fd16d5e6f847c04e9adf2d2574a51d2662 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 14 Jun 2025 11:33:07 +0800 Subject: [PATCH 20/21] fix: plugin config panel --- .../plugin/objecthelper/action/ClassToJsonAction.java | 2 +- .../objecthelper/action/ClassToThriftIDLAction.java | 2 +- .../plugin/objecthelper/action/ClassToXMLAction.java | 2 +- .../objecthelper/action/ObjectCopyMethodAction.java | 2 +- .../objecthelper/common/enums/FunctionSwitchEnum.java | 4 ++-- .../plugin/objecthelper/config/PluginConfigModel.java | 8 ++++---- 6 files changed, 10 insertions(+), 10 deletions(-) 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 7341f6b..206af16 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToJsonAction.java @@ -30,7 +30,7 @@ public void actionPerformed(@NotNull AnActionEvent anAction) { @Override public boolean actionShow(AnActionEvent anActionEvent) { - return PluginConfigState.getInstance().getJsonSwitch() == FunctionSwitchEnum.OPEN + return PluginConfigState.getInstance().getJsonSwitch() == FunctionSwitchEnum.ENABLE && getOperatePsiClass(anActionEvent) != null; } 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 d25b2bd..24f28e1 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToThriftIDLAction.java @@ -31,7 +31,7 @@ public void actionPerformed(@NotNull AnActionEvent anActionEvent) { @Override public boolean actionShow(@NotNull AnActionEvent anActionEvent) { - return PluginConfigState.getInstance().getThriftSwitch() == FunctionSwitchEnum.OPEN + return PluginConfigState.getInstance().getThriftSwitch() == FunctionSwitchEnum.ENABLE && 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 14cc32a..16ca662 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ClassToXMLAction.java @@ -28,7 +28,7 @@ public void actionPerformed(@NotNull AnActionEvent anAction) { @Override public boolean actionShow(@NotNull AnActionEvent anActionEvent) { - return PluginConfigState.getInstance().getXmlSwitch() == FunctionSwitchEnum.OPEN + return PluginConfigState.getInstance().getXmlSwitch() == FunctionSwitchEnum.ENABLE && getOperatePsiClass(anActionEvent) != null; } 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 8b8fe9e..00452f8 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyMethodAction.java @@ -25,7 +25,7 @@ public void actionPerformed(AnActionEvent anActionEvent) { @Override public boolean actionShow(AnActionEvent anActionEvent) { - return PluginConfigState.getInstance().getObjectCopySwitch() == FunctionSwitchEnum.OPEN + return PluginConfigState.getInstance().getObjectCopySwitch() == FunctionSwitchEnum.ENABLE && check(PsiUtils.getCursorPsiMethod(anActionEvent)); } 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 index 866c40f..f7a6ebe 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FunctionSwitchEnum.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/common/enums/FunctionSwitchEnum.java @@ -5,8 +5,8 @@ * @date: 2023-12-24 **/ public enum FunctionSwitchEnum implements CommonEnum { - OPEN("open"), - CLOSE("close"), + ENABLE("enable"), + DISABLE("disable"), ; private String code; 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 e136cbb..8dde736 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/config/PluginConfigModel.java @@ -14,19 +14,19 @@ public class PluginConfigModel { /** * 是否开启 Class To Json 功能,默认为开启状态 */ - private FunctionSwitchEnum jsonSwitch = FunctionSwitchEnum.OPEN; + private FunctionSwitchEnum jsonSwitch = FunctionSwitchEnum.ENABLE; /** * 是否开启 Class To Thrift IDL 功能,默认为开启状态 */ - private FunctionSwitchEnum thriftSwitch = FunctionSwitchEnum.OPEN; + private FunctionSwitchEnum thriftSwitch = FunctionSwitchEnum.ENABLE; /** * 是否开启 Class To XML 功能,默认为开启状态 */ - private FunctionSwitchEnum xmlSwitch = FunctionSwitchEnum.OPEN; + private FunctionSwitchEnum xmlSwitch = FunctionSwitchEnum.ENABLE; /** * 是否开启 Object Copy Method 功能,默认为开启状态 */ - private FunctionSwitchEnum objectCopySwitch = FunctionSwitchEnum.OPEN; + private FunctionSwitchEnum objectCopySwitch = FunctionSwitchEnum.ENABLE; /** * Object Copy Method 功能中,以Source/Target对象为基础生成字段拷贝 */ From f8cca7501fb6e2590acdb8b448f4e4906d6cc960 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 21 Jun 2025 22:02:20 +0800 Subject: [PATCH 21/21] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E9=97=AE=E9=A2=98=EF=BC=8C=E6=94=B9=E5=96=84=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E4=BD=93=E9=AA=8C=201.=20=E4=BF=AE=E5=A4=8D=20Class?= =?UTF-8?q?=20To=20Json=20=E5=AF=B9boolean=E7=B1=BB=E5=9E=8B=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=94=AF=E6=8C=81=202.=20=E6=96=B0=E5=A2=9E=20Class?= =?UTF-8?q?=20To=20Json=20=E5=AF=B9Map=E7=B1=BB=E5=9E=8B=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=94=AF=E6=8C=81=203.=20=E4=BC=98=E5=8C=96=20Object=20Copy=20?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E4=BB=A3=E7=A0=81=E4=BD=93=E9=AA=8C=204.=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8F=92=E4=BB=B6=E5=85=BC=E5=AE=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- build.gradle | 9 +- .../action/AbstractClassAnAction.java | 7 + .../objecthelper/action/ObjectCopyAction.java | 124 ++++++++++++---- .../common/constant/JavaClassName.java | 2 + .../common/util/PsiTypeUtils.java | 5 + .../AbstractDataObjectGenerator.java | 134 +++++++++++------- .../objecthelper/ui/ClassSearchDialog.java | 83 ++++++++--- src/main/resources/META-INF/plugin.xml | 4 +- 9 files changed, 272 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index 4ab3a4e..d4be63d 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@
      - + - +
      JetBrains Intellij ObjectHelper 插件致力于消除开发者重复性的低效工作,助力开发者将更多精力聚焦于核心业务逻辑开发,显著提升开发效率。 diff --git a/build.gradle b/build.gradle index 731142b..44ee143 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'cn.bigcoder.plugin' -version '1.4.0' +version '1.4.1' repositories { mavenCentral() @@ -28,10 +28,13 @@ intellij { plugins = ['com.intellij.java'] } patchPluginXml { - sinceBuild = '211' + sinceBuild = '231' untilBuild = '301.*' changeNotes = """ - 1. new feature: Object Copy support lambda and common scene. + 1.Fixed the support for boolean type fields in class to json conversion. + 2.Added support for Map type fields in class to json conversion. + 3.Optimized the code experience of the Object Copy function. + 4.Optimized the plugin compatibility. """ } test { diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/AbstractClassAnAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/AbstractClassAnAction.java index 365eeb0..0fe3612 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/AbstractClassAnAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/AbstractClassAnAction.java @@ -2,6 +2,7 @@ import static cn.bigcoder.plugin.objecthelper.common.util.PsiUtils.setActionInvisible; +import com.intellij.openapi.actionSystem.ActionUpdateThread; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import org.jetbrains.annotations.NotNull; @@ -25,4 +26,10 @@ public void update(@NotNull AnActionEvent anActionEvent) { } super.update(anActionEvent); } + + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.BGT; + } + } diff --git a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyAction.java b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyAction.java index 55f8358..6e8f918 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyAction.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/action/ObjectCopyAction.java @@ -9,6 +9,7 @@ import cn.bigcoder.plugin.objecthelper.generator.Generator; import cn.bigcoder.plugin.objecthelper.generator.copy.SmartObjectCopyGenerator; import cn.bigcoder.plugin.objecthelper.ui.ClassSearchDialog; +import com.intellij.openapi.actionSystem.ActionUpdateThread; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.CaretModel; @@ -22,6 +23,7 @@ public class ObjectCopyAction extends AbstractClassAnAction { + @Override public void actionPerformed(@NotNull AnActionEvent anAction) { PsiClass sourcePsiClass = getOperatePsiClass(anAction); @@ -62,6 +64,10 @@ public void actionPerformed(@NotNull AnActionEvent anAction) { * @param copyCodeStr */ private void insertCode(Project project, String copyCodeStr) { + // 检查代码末尾是否有换行符,没有则添加 + if (!copyCodeStr.endsWith("\n")) { + copyCodeStr += "\n"; + } Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); if (editor == null) { return; @@ -69,43 +75,113 @@ private void insertCode(Project project, String copyCodeStr) { CaretModel caretModel = editor.getCaretModel(); int offset = caretModel.getOffset(); Document document = editor.getDocument(); - // 删除光标所在的变量 - int startOffset = findVariableStartOffset(document, offset); - int endOffset = findVariableEndOffset(document, offset); - if (startOffset >= 0 && endOffset >= 0) { + + // 获取当前光标所在行号 + int lineNumber = document.getLineNumber(offset); + int lineStartOffset = document.getLineStartOffset(lineNumber); + int lineEndOffset = document.getLineEndOffset(lineNumber); + + // 检查当前行在光标之后是否有非空白字符 + CharSequence lineText = document.getCharsSequence().subSequence(offset, lineEndOffset); + boolean hasNonWhitespaceAfterCursor = !lineText.toString().trim().isEmpty(); + + // 获取当前行的缩进 + String indent = getLineIndent(document, lineNumber); + // 判断当前行是否为方法头 + String fullLineText = document.getCharsSequence().subSequence(lineStartOffset, lineEndOffset).toString(); + if (isMethodHeader(fullLineText)) { + // 若是方法头,缩进增加一格,假设一格为 4 个空格 + indent += " "; + } + + // 为插入的代码添加缩进 + String indentedCopyCodeStr = addIndentToCode(copyCodeStr, indent); + + if (!hasNonWhitespaceAfterCursor) { + // 如果光标之后没有非空白字符,删除当前行 WriteCommandAction.runWriteCommandAction(project, () -> { - document.deleteString(startOffset, endOffset); + document.deleteString(lineStartOffset, lineEndOffset); }); + offset = lineStartOffset; + } else { + // 如果光标之后有非空白字符,将插入位置移动到下一行开头 + int nextLineStart = document.getLineStartOffset(lineNumber + 1); + offset = nextLineStart; } + int finalOffset = offset; WriteCommandAction.runWriteCommandAction(project, () -> { - document.insertString(offset, copyCodeStr); + document.insertString(finalOffset, indentedCopyCodeStr); }); } - private int findVariableStartOffset(Document document, int offset) { - int start = offset; - while (start > 0) { - char c = document.getCharsSequence().charAt(start - 1); - if (!Character.isJavaIdentifierPart(c)) { - break; - } - start--; + /** + * 获取指定行的缩进 + * @param document 文档对象 + * @param lineNumber 行号 + * @return 缩进字符串 + */ + private String getLineIndent(Document document, int lineNumber) { + int lineStartOffset = document.getLineStartOffset(lineNumber); + int lineEndOffset = document.getLineEndOffset(lineNumber); + CharSequence lineText = document.getCharsSequence().subSequence(lineStartOffset, lineEndOffset); + int indentLength = 0; + while (indentLength < lineText.length() && Character.isWhitespace(lineText.charAt(indentLength))) { + indentLength++; + } + return lineText.subSequence(0, indentLength).toString(); + } + + /** + * 判断当前行是否为方法头 + * @param lineText 当前行的文本内容 + * @return 如果是方法头返回 true,否则返回 false + */ + private boolean isMethodHeader(String lineText) { + // 去除注释内容,避免注释中的括号影响判断 + lineText = removeComments(lineText); + // 去除前后空白字符 + lineText = lineText.trim(); + // 简单判断,包含 ( 和 ) 且不包含 ; 认为是方法头 + return lineText.contains("(") && lineText.contains(")") && !lineText.contains(";"); + } + + + /** + * 移除字符串中的注释内容 + * @param lineText 包含注释的字符串 + * @return 移除注释后的字符串 + */ + private String removeComments(String lineText) { + // 移除单行注释 + int singleCommentIndex = lineText.indexOf("//"); + if (singleCommentIndex != -1) { + lineText = lineText.substring(0, singleCommentIndex); } - return start; + // 移除多行注释开始标记之后的内容(简单处理,不处理嵌套情况) + int multiCommentStartIndex = lineText.indexOf("/*"); + if (multiCommentStartIndex != -1) { + lineText = lineText.substring(0, multiCommentStartIndex); + } + return lineText; } - private int findVariableEndOffset(Document document, int offset) { - int end = offset; - int length = document.getTextLength(); - while (end < length) { - char c = document.getCharsSequence().charAt(end); - if (!Character.isJavaIdentifierPart(c)) { - break; + /** + * 为代码的每一行添加缩进 + * @param code 原始代码 + * @param indent 缩进字符串 + * @return 添加缩进后的代码 + */ + private String addIndentToCode(String code, String indent) { + StringBuilder indentedCode = new StringBuilder(); + String[] lines = code.split("\\r?\\n"); + for (int i = 0; i < lines.length; i++) { + indentedCode.append(indent).append(lines[i]); + if (i < lines.length - 1) { + indentedCode.append("\n"); } - end++; } - return end; + return indentedCode.toString(); } @Override 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 297cf03..a1d4c22 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 @@ -10,6 +10,7 @@ public class JavaClassName { public static final String LONG_TYPE = "java.lang.Long"; public static final String SHORT_TYPE = "java.lang.Short"; public static final String BYTE_TYPE = "java.lang.Byte"; + public static final String BOOLEAN_TYPE = "java.lang.Boolean"; public static final String DOUBLE_TYPE = "java.lang.Double"; public static final String FLOAT_TYPE = "java.lang.Float"; public static final String DATE_TYPE = "java.util.Date"; @@ -22,6 +23,7 @@ public class JavaClassName { 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 BASE_BOOL_TYPE = "boolean"; 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 9dccef7..ea71389 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 @@ -43,6 +43,8 @@ public class PsiTypeUtils { DATA_TYPES.add(LOCAL_DATE_TYPE); DATA_TYPES.add(LOCAL_DATE_TIME_TYPE); DATA_TYPES.add(BIG_DECIMAL); + DATA_TYPES.add(BOOLEAN_TYPE); + DATA_TYPES.add(BASE_BOOL_TYPE); } /** @@ -76,6 +78,9 @@ public static Object getDataTypeDefaultValue(String canonicalText) { case FLOAT_TYPE: case BASE_FLOAT_TYPE: return 1.1f; + case BOOLEAN_TYPE: + case BASE_BOOL_TYPE: + return true; case DATE_TYPE: return DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"); case LOCAL_DATE_TYPE: 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 d490bfe..4d88424 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/generator/AbstractDataObjectGenerator.java @@ -1,5 +1,6 @@ package cn.bigcoder.plugin.objecthelper.generator; +import cn.bigcoder.plugin.objecthelper.common.constant.JavaClassName; import cn.bigcoder.plugin.objecthelper.common.util.PsiTypeUtils; import cn.bigcoder.plugin.objecthelper.common.util.PsiUtils; import com.google.common.collect.Maps; @@ -23,66 +24,91 @@ **/ public abstract class AbstractDataObjectGenerator implements Generator { - private PsiClass psiClass; + private PsiClass psiClass; - public AbstractDataObjectGenerator(PsiClass psiClass) { - this.psiClass = psiClass; - } - - /** - * 保存已经解析过的自定义类型名称,防止出现递归嵌套的情况 - */ - private Set recursiveCache = Sets.newHashSet(); + public AbstractDataObjectGenerator(PsiClass psiClass) { + this.psiClass = psiClass; + } - protected Map processFields() { - return processFields(psiClass); - } + /** + * 保存已经解析过的自定义类型名称,防止出现递归嵌套的情况 + */ + private Set recursiveCache = Sets.newHashSet(); - protected Map processFields(PsiClass psiClass) { - Map result = Maps.newLinkedHashMap(); - // 当前类所有字段 - List allPsiFields = PsiUtils.getAllPsiFields(psiClass); - if (CollectionUtils.isEmpty(allPsiFields)) { - return result; + protected Map processFields() { + return processFields(psiClass); } - for (PsiField psiField : allPsiFields) { - result.put(psiField.getName(), processField(psiField.getType())); + + protected Map processFields(PsiClass psiClass) { + Map result = Maps.newLinkedHashMap(); + // 当前类所有字段 + List allPsiFields = PsiUtils.getAllPsiFields(psiClass); + if (CollectionUtils.isEmpty(allPsiFields)) { + return result; + } + for (PsiField psiField : allPsiFields) { + // 过滤掉静态字段 + if (!psiField.hasModifierProperty(com.intellij.psi.PsiModifier.STATIC)) { + result.put(psiField.getName(), processField(psiField.getType())); + } + } + return result; } - 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)) { + 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()); + if (arrayContentClass == null) { + return list; + } + 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.isMapType(psiType)) { + // 如果是 Map 类型 + Map map = Maps.newHashMap(); + PsiType[] parameters = ((PsiClassReferenceType) psiType).getParameters(); + if (ArrayUtils.isNotEmpty(parameters) && parameters.length >= 2) { + // 获取键和值的泛型类型 + PsiType keyType = parameters[0]; + PsiType valueType = parameters[1]; + Object keyDefaultValue; + // 判断 key 类型是否为 String + if (JavaClassName.STRING_TYPE.equals(keyType.getCanonicalText())) { + keyDefaultValue = "key"; + } else { + keyDefaultValue = processField(keyType); + } + Object valueDefaultValue = processField(valueType); + map.put(keyDefaultValue, valueDefaultValue); + } + defaultValue = map; + } 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; - } - //获取泛型 - 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/main/java/cn/bigcoder/plugin/objecthelper/ui/ClassSearchDialog.java b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ClassSearchDialog.java index 7e49766..94e978a 100644 --- a/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ClassSearchDialog.java +++ b/src/main/java/cn/bigcoder/plugin/objecthelper/ui/ClassSearchDialog.java @@ -10,24 +10,24 @@ import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBTextField; import com.intellij.util.ArrayUtil; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Timer; import java.util.TimerTask; -import javax.swing.DefaultListCellRenderer; -import javax.swing.JComponent; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import org.jetbrains.annotations.Nullable; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; public class ClassSearchDialog extends DialogWrapper { @@ -36,11 +36,13 @@ public class ClassSearchDialog extends DialogWrapper { private JBList classList; private PsiClass selectedClass; private Timer timer; - private static final int DEBOUNCE_DELAY = 500; // 防抖延迟时间,单位:毫秒 + private static final int DEBOUNCE_DELAY = 800; // 防抖延迟时间,单位:毫秒 // 定义默认宽度,可按需调整 private static final int DEFAULT_WIDTH = 700; // 定义默认高度,可按需调整 private static final int DEFAULT_HEIGHT = 600; + private JLabel loadingLabel; + private Map> searchCache = new HashMap<>(); public ClassSearchDialog(@Nullable Project project, String title) { super(project); @@ -57,7 +59,6 @@ protected void init() { SwingUtilities.invokeLater(() -> classNameField.requestFocusInWindow()); } - @Nullable @Override protected JComponent createCenterPanel() { @@ -71,9 +72,17 @@ protected JComponent createCenterPanel() { classList = new JBList<>(); classList.setCellRenderer(new ClassListCellRenderer()); JBScrollPane scrollPane = new JBScrollPane(classList); - panel.add(scrollPane, BorderLayout.CENTER); - // 输入框文本变化监听,添加防抖机制 + // 创建加载提示标签 + loadingLabel = new JLabel("Loading...", SwingConstants.CENTER); + loadingLabel.setVisible(false); // 初始状态隐藏 + + JPanel listPanel = new JPanel(new BorderLayout()); + listPanel.add(scrollPane, BorderLayout.CENTER); + listPanel.add(loadingLabel, BorderLayout.SOUTH); + + panel.add(listPanel, BorderLayout.CENTER); + classNameField.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { @@ -141,7 +150,6 @@ public void keyTyped(KeyEvent e) { return panel; } - private void debounceUpdateClassList() { if (timer != null) { timer.cancel(); @@ -150,11 +158,55 @@ private void debounceUpdateClassList() { timer.schedule(new TimerTask() { @Override public void run() { - SwingUtilities.invokeLater(() -> updateClassList()); + // 显示加载提示 + SwingUtilities.invokeLater(() -> loadingLabel.setVisible(true)); + // 异步执行搜索操作 + SwingWorker, Void> worker = new SwingWorker<>() { + @Override + protected List doInBackground() { + return updateClassListInBackground(); + } + + @Override + protected void done() { + try { + List matchedClasses = get(); + SwingUtilities.invokeLater(() -> { + updateClassListUI(matchedClasses); + // 隐藏加载提示 + loadingLabel.setVisible(false); + }); + } catch (Exception e) { + e.printStackTrace(); + // 出现异常也隐藏加载提示 + SwingUtilities.invokeLater(() -> loadingLabel.setVisible(false)); + } + } + }; + worker.execute(); } }, DEBOUNCE_DELAY); } + private List updateClassListInBackground() { + String query = classNameField.getText().trim(); + if (!query.isEmpty()) { + if (searchCache.containsKey(query)) { + return searchCache.get(query); + } + List matchedClasses = PsiUtils.matchPsiClassByName(this.project, query); + // 按优先级排序 + matchedClasses.sort(this::compareClasses); + searchCache.put(query, matchedClasses); + return matchedClasses; + } + return Collections.emptyList(); + } + + private void updateClassListUI(List matchedClasses) { + classList.setListData(ArrayUtil.toObjectArray(matchedClasses, PsiClass.class)); + } + private void updateClassList() { String query = classNameField.getText().trim(); if (!query.isEmpty()) { @@ -273,5 +325,4 @@ private String highlightMatches(String input, String query) { return result.toString(); } } - } \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 21b6ba4..9bdb6dd 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -6,8 +6,10 @@ GitHub -
    52. Copy the object
    53. +
    54. Object Copy Method
    55. +
    56. Object Copy
    57. +
    58. Class to JSON
    59. Class to Thrift IDL