[
  {
    "path": ".gitignore",
    "content": "*.iml\n\nlog.roo\n.idea/\nout/\n.DS_Store\n.gradle/\ngradle/\nbuild/\nout/"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# free-mybatis-plugin\n\n## Changes:\n\n- Compatible with Intellij IC edition.\n- Not to warn static method or the method with mybatis provider annotation. \n- Remove MyBatis Generator."
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n    repositories {\n        maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }\n        mavenLocal()\n        mavenCentral()\n    }\n}\n\nplugins {\n    id 'org.jetbrains.intellij' version '1.2.1'\n}\n\ngroup = 'cn.wuzhizhan.idea.mybatis'\nversion = '2021.12.09'\n\napply plugin: 'java'\nsourceCompatibility = 1.8\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    testCompile group: 'junit', name: 'junit', version: '4.12'\n}\n\nbuildPlugin {\n    buildSearchableOptions.enabled = false\n}\n\nintellij {\n    version = \"IC-2019.1\"\n    pluginName = 'free-mybatis-plugin'\n    sameSinceUntilBuild = false\n    patchPluginXml {\n        untilBuild = \"299.*\"\n        changeNotes = \"\"\"\n            <ul>\n            <li>Fix deprecated api alert</li>\n            </ul>\n         \"\"\"\n    }\n}\n\ntasks.withType(JavaCompile) {\n    options.encoding = \"UTF-8\"\n}\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\n@rem you may not use this file except in compliance with the License.\n@rem You may obtain a copy of the License at\n@rem\n@rem      https://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto execute\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto execute\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = 'free-mybatis-plugin'\n\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/action/MybatisTypedHandler.java",
    "content": "package com.wuzhizhan.mybatis.action;\n\nimport com.intellij.codeInsight.AutoPopupController;\nimport com.intellij.codeInsight.editorActions.TypedHandlerDelegate;\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiFile;\nimport com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;\nimport com.wuzhizhan.mybatis.util.DomUtils;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class MybatisTypedHandler extends TypedHandlerDelegate {\n\n    @Override\n    public Result checkAutoPopup(char charTyped, final Project project, final Editor editor, PsiFile file) {\n        if (charTyped == '.' && DomUtils.isMybatisFile(file)) {\n            autoPopupParameter(project, editor);\n            return Result.STOP;\n        }\n        return super.checkAutoPopup(charTyped, project, editor, file);\n    }\n\n    @Override\n    public Result charTyped(char c, final Project project, @NotNull final Editor editor, @NotNull PsiFile file) {\n        int index = editor.getCaretModel().getOffset() - 2;\n        PsiFile topLevelFile = InjectedLanguageUtil.getTopLevelFile(file);\n        boolean parameterCase = c == '{' &&\n                index >= 0 &&\n                editor.getDocument().getText().charAt(index) == '#' &&\n//                file instanceof SqlFile &&\n                DomUtils.isMybatisFile(topLevelFile);\n        if (parameterCase) {\n            autoPopupParameter(project, editor);\n            return Result.STOP;\n        }\n        return super.charTyped(c, project, editor, file);\n    }\n\n    private static void autoPopupParameter(final Project project, final Editor editor) {\n        AutoPopupController.getInstance(project).autoPopupMemberLookup(editor, psiFile -> true);\n    }\n\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/AliasClassReference.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Collections2;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiReferenceBase;\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\n\n/**\n * @author yanglin\n */\npublic class AliasClassReference extends PsiReferenceBase<XmlAttributeValue> {\n\n    private Function<AliasDesc, String> function = new Function<AliasDesc, String>() {\n        @Override\n        public String apply(AliasDesc input) {\n            return input.getAlias();\n        }\n    };\n\n    public AliasClassReference(@NotNull XmlAttributeValue element) {\n        super(element, true);\n    }\n\n    @Nullable\n    @Override\n    public PsiElement resolve() {\n        XmlAttributeValue attributeValue = getElement();\n        return AliasFacade.getInstance(attributeValue.getProject()).findPsiClass(attributeValue, attributeValue.getValue()).orElse(null);\n    }\n\n    @NotNull\n    @Override\n    public Object[] getVariants() {\n        AliasFacade aliasFacade = AliasFacade.getInstance(getElement().getProject());\n        Collection<String> result = Collections2.transform(aliasFacade.getAliasDescs(getElement()), function);\n        return result.toArray(new String[result.size()]);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/AliasDesc.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.intellij.psi.PsiClass;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class AliasDesc {\n\n    private PsiClass clazz;\n\n    private String alias;\n\n    public AliasDesc() {\n    }\n\n    public static AliasDesc create(@NotNull PsiClass psiClass, @NotNull String alias) {\n        return new AliasDesc(psiClass, alias);\n    }\n\n    public AliasDesc(PsiClass clazz, String alias) {\n        this.clazz = clazz;\n        this.alias = alias;\n    }\n\n    public PsiClass getClazz() {\n        return clazz;\n    }\n\n    public void setClazz(PsiClass clazz) {\n        this.clazz = clazz;\n    }\n\n    public String getAlias() {\n        return alias;\n    }\n\n    public void setAlias(String alias) {\n        this.alias = alias;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n\n        AliasDesc aliasDesc = (AliasDesc) o;\n\n        if (alias != null ? !alias.equalsIgnoreCase(aliasDesc.alias) : aliasDesc.alias != null) {\n            return false;\n        }\n        if (clazz != null ? !clazz.equals(aliasDesc.clazz) : aliasDesc.clazz != null) {\n            return false;\n        }\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = clazz != null ? clazz.hashCode() : 0;\n        result = 31 * result + (alias != null ? alias.hashCode() : 0);\n        return result;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/AliasFacade.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.google.common.collect.Lists;\nimport com.intellij.openapi.components.ServiceManager;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.JavaPsiFacade;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.search.GlobalSearchScope;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic class AliasFacade {\n\n    private Project project;\n\n    private JavaPsiFacade javaPsiFacade;\n\n    private List<AliasResolver> resolvers;\n\n    public static final AliasFacade getInstance(@NotNull Project project) {\n        return ServiceManager.getService(project, AliasFacade.class);\n    }\n\n    public AliasFacade(Project project) {\n        this.project = project;\n        this.resolvers = Lists.newArrayList();\n        this.javaPsiFacade = JavaPsiFacade.getInstance(project);\n        initResolvers();\n    }\n\n    private void initResolvers() {\n        try {\n            Class.forName(\"com.intellij.spring.model.utils.SpringModelUtils\");\n            this.registerResolver(AliasResolverFactory.createBeanResolver(project));\n        } catch (ClassNotFoundException e) {\n        }\n        this.registerResolver(AliasResolverFactory.createSingleAliasResolver(project));\n        this.registerResolver(AliasResolverFactory.createConfigPackageResolver(project));\n        this.registerResolver(AliasResolverFactory.createAnnotationResolver(project));\n        this.registerResolver(AliasResolverFactory.createInnerAliasResolver(project));\n    }\n\n    @NotNull\n    public Optional<PsiClass> findPsiClass(@Nullable PsiElement element, @NotNull String shortName) {\n        PsiClass clazz = javaPsiFacade.findClass(shortName, GlobalSearchScope.allScope(project));\n        if (null != clazz) {\n            return Optional.of(clazz);\n        }\n        for (AliasResolver resolver : resolvers) {\n            for (AliasDesc desc : resolver.getClassAliasDescriptions(element)) {\n                if (shortName.equalsIgnoreCase(desc.getAlias())) {\n                    return Optional.of(desc.getClazz());\n                }\n            }\n        }\n        return Optional.empty();\n    }\n\n    @NotNull\n    public Collection<AliasDesc> getAliasDescs(@Nullable PsiElement element) {\n        ArrayList<AliasDesc> result = Lists.newArrayList();\n        for (AliasResolver resolver : resolvers) {\n            result.addAll(resolver.getClassAliasDescriptions(element));\n        }\n        return result;\n    }\n\n    public Optional<AliasDesc> findAliasDesc(@Nullable PsiClass clazz) {\n        if (clazz == null) {\n            return Optional.empty();\n        }\n        for (AliasResolver resolver : resolvers) {\n            for (AliasDesc desc : resolver.getClassAliasDescriptions(clazz)) {\n                if (clazz.equals(desc.getClazz())) {\n                    return Optional.of(desc);\n                }\n            }\n        }\n        return Optional.empty();\n    }\n\n    public void registerResolver(@NotNull AliasResolver resolver) {\n        this.resolvers.add(resolver);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/AliasResolver.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiElement;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Optional;\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic abstract class AliasResolver {\n\n    protected Project project;\n\n    public AliasResolver(Project project) {\n        this.project = project;\n    }\n\n    @NotNull\n    protected Optional<AliasDesc> addAliasDesc(@NotNull Set<AliasDesc> descs, @Nullable PsiClass clazz, @Nullable String alias) {\n        if (null == alias || !JavaUtils.isModelClazz(clazz)) {\n            return Optional.empty();\n        }\n        AliasDesc desc = new AliasDesc();\n        descs.add(desc);\n        desc.setClazz(clazz);\n        desc.setAlias(alias);\n        return Optional.of(desc);\n    }\n\n    @NotNull\n    public abstract Set<AliasDesc> getClassAliasDescriptions(@Nullable PsiElement element);\n\n    public Project getProject() {\n        return project;\n    }\n\n    public void setProject(Project project) {\n        this.project = project;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/AliasResolverFactory.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.intellij.openapi.project.Project;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class AliasResolverFactory {\n\n    @NotNull\n    public static AliasResolver createInnerAliasResolver(@NotNull Project project) {\n        return new InnerAliasResolver(project);\n    }\n\n    @NotNull\n    public static AliasResolver createAnnotationResolver(@NotNull Project project) {\n        return new AnnotationAliasResolver(project);\n    }\n\n    @NotNull\n    public static AliasResolver createBeanResolver(@NotNull Project project) {\n        return new BeanAliasResolver(project);\n    }\n\n    @NotNull\n    public static AliasResolver createConfigPackageResolver(@NotNull Project project) {\n        return new ConfigPackageAliasResolver(project);\n    }\n\n    @NotNull\n    public static AliasResolver createSingleAliasResolver(@NotNull Project project) {\n        return new SingleAliasResolver(project);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/AnnotationAliasResolver.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Collections2;\nimport com.google.common.collect.Sets;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.search.GlobalSearchScope;\nimport com.intellij.psi.search.searches.AnnotatedElementsSearch;\nimport com.wuzhizhan.mybatis.annotation.Annotation;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Optional;\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic class AnnotationAliasResolver extends AliasResolver {\n\n    private static final Function FUN = new Function<PsiClass, AliasDesc>() {\n        @Override\n        public AliasDesc apply(PsiClass psiClass) {\n            Optional<String> txt = JavaUtils.getAnnotationValueText(psiClass, Annotation.ALIAS);\n            if (!txt.isPresent()) return null;\n            AliasDesc ad = new AliasDesc();\n            ad.setAlias(txt.get());\n            ad.setClazz(psiClass);\n            return ad;\n        }\n    };\n\n    public AnnotationAliasResolver(Project project) {\n        super(project);\n    }\n\n    public static final AnnotationAliasResolver getInstance(@NotNull Project project) {\n        return project.getComponent(AnnotationAliasResolver.class);\n    }\n\n    @NotNull\n    @Override\n    public Set<AliasDesc> getClassAliasDescriptions(@Nullable PsiElement element) {\n        Optional<PsiClass> clazz = Annotation.ALIAS.toPsiClass(project);\n        if (clazz.isPresent()) {\n            Collection<PsiClass> res = AnnotatedElementsSearch.searchPsiClasses(clazz.get(), GlobalSearchScope.allScope(project)).findAll();\n            return Sets.newHashSet(Collections2.transform(res, FUN));\n        }\n        return Collections.emptySet();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/BeanAliasResolver.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.google.common.collect.Sets;\nimport com.intellij.openapi.module.ModuleManager;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiElement;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic class BeanAliasResolver extends PackageAliasResolver {\n\n    private static final String MAPPER_ALIAS_PACKAGE_CLASS = \"org.mybatis.spring.SqlSessionFactoryBean\";\n    private static final String MAPPER_ALIAS_PROPERTY = \"typeAliasesPackage\";\n    private ModuleManager moduleManager;\n\n    public BeanAliasResolver(Project project) {\n        super(project);\n        this.moduleManager = ModuleManager.getInstance(project);\n    }\n\n    @NotNull\n    @Override\n    public Collection<String> getPackages(@Nullable PsiElement element) {\n        Set<String> res = Sets.newHashSet();\n//        for (Module module : moduleManager.getModules()) {\n//            for (CommonSpringModel springModel : springManager.getCombinedModel(module).getRelatedModels()) {\n//                addPackages(res, springModel);\n//            }\n//        }\n        return res;\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/ConfigPackageAliasResolver.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.google.common.collect.Lists;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.util.Processor;\nimport com.wuzhizhan.mybatis.dom.model.Package;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\n\n/**\n * @author yanglin\n */\npublic class ConfigPackageAliasResolver extends PackageAliasResolver {\n\n    public ConfigPackageAliasResolver(Project project) {\n        super(project);\n    }\n\n    @NotNull\n    @Override\n    public Collection<String> getPackages(@Nullable PsiElement element) {\n        final ArrayList<String> result = Lists.newArrayList();\n        MapperUtils.processConfiguredPackage(project, new Processor<com.wuzhizhan.mybatis.dom.model.Package>() {\n            @Override\n            public boolean process(Package pkg) {\n                result.add(pkg.getName().getStringValue());\n                return true;\n            }\n        });\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/InnerAliasResolver.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.google.common.collect.ImmutableSet;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiElement;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic class InnerAliasResolver extends AliasResolver {\n\n    private final Set<AliasDesc> innerAliasDescs = ImmutableSet.of(\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.String\").get(), \"string\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.Byte\").get(), \"byte\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.Long\").get(), \"long\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.Short\").get(), \"short\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.Integer\").get(), \"int\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.Integer\").get(), \"integer\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.Double\").get(), \"double\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.Float\").get(), \"float\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.Boolean\").get(), \"boolean\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.util.Date\").get(), \"date\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.math.BigDecimal\").get(), \"decimal\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.lang.Object\").get(), \"object\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.util.Map\").get(), \"map\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.util.HashMap\").get(), \"hashmap\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.util.List\").get(), \"list\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.util.ArrayList\").get(), \"arraylist\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.util.Collection\").get(), \"collection\"),\n            AliasDesc.create(JavaUtils.findClazz(project, \"java.util.Iterator\").get(), \"iterator\")\n    );\n\n    public InnerAliasResolver(Project project) {\n        super(project);\n    }\n\n    @NotNull\n    @Override\n    public Set<AliasDesc> getClassAliasDescriptions(@Nullable PsiElement element) {\n        return innerAliasDescs;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/PackageAliasResolver.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.google.common.collect.Sets;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.JavaPsiFacade;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiPackage;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic abstract class PackageAliasResolver extends AliasResolver {\n\n    private JavaPsiFacade javaPsiFacade;\n\n    public PackageAliasResolver(Project project) {\n        super(project);\n        this.javaPsiFacade = JavaPsiFacade.getInstance(project);\n    }\n\n    @NotNull\n    @Override\n    public Set<AliasDesc> getClassAliasDescriptions(@Nullable PsiElement element) {\n        Set<AliasDesc> result = Sets.newHashSet();\n        for (String pkgName : getPackages(element)) {\n            if (null == pkgName) {\n                continue;\n            }\n            PsiPackage pkg = javaPsiFacade.findPackage(pkgName);\n            if (null != pkg) {\n                addAliasDesc(result, pkg);\n                for (PsiPackage tmp : pkg.getSubPackages()) {\n                    addAliasDesc(result, tmp);\n                }\n            }\n        }\n        return result;\n    }\n\n    private void addAliasDesc(Set<AliasDesc> result, PsiPackage pkg) {\n        for (PsiClass clazz : pkg.getClasses()) {\n            addAliasDesc(result, clazz, clazz.getName());\n        }\n    }\n\n    @NotNull\n    public abstract Collection<String> getPackages(@Nullable PsiElement element);\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/alias/SingleAliasResolver.java",
    "content": "package com.wuzhizhan.mybatis.alias;\n\nimport com.google.common.collect.Sets;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.util.Processor;\nimport com.wuzhizhan.mybatis.dom.model.TypeAlias;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic class SingleAliasResolver extends AliasResolver {\n\n    public SingleAliasResolver(Project project) {\n        super(project);\n    }\n\n    @NotNull\n    @Override\n    public Set<AliasDesc> getClassAliasDescriptions(@Nullable PsiElement element) {\n        final Set<AliasDesc> result = Sets.newHashSet();\n        MapperUtils.processConfiguredTypeAliases(project, new Processor<TypeAlias>() {\n            @Override\n            public boolean process(TypeAlias typeAlias) {\n                addAliasDesc(result, typeAlias.getType().getValue(), typeAlias.getAlias().getStringValue());\n                return true;\n            }\n        });\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/annotation/Annotation.java",
    "content": "package com.wuzhizhan.mybatis.annotation;\n\nimport com.google.common.collect.ImmutableSet;\nimport com.google.common.collect.Iterables;\nimport com.google.common.collect.Maps;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.JavaPsiFacade;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.search.GlobalSearchScope;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\n\n/**\n * Simple implementation\n *\n * @author yanglin\n */\npublic class Annotation implements Cloneable {\n\n    public static final Annotation PARAM = new Annotation(\"@Param\", \"org.apache.ibatis.annotations.Param\");\n\n    public static final Annotation SELECT = new Annotation(\"@Select\", \"org.apache.ibatis.annotations.Select\");\n\n    public static final Annotation UPDATE = new Annotation(\"@Update\", \"org.apache.ibatis.annotations.Update\");\n\n    public static final Annotation INSERT = new Annotation(\"@Insert\", \"org.apache.ibatis.annotations.Insert\");\n\n    public static final Annotation DELETE = new Annotation(\"@Delete\", \"org.apache.ibatis.annotations.Delete\");\n\n    public static final Annotation ALIAS = new Annotation(\"@Alias\", \"org.apache.ibatis.type.Alias\");\n\n    public static final Annotation AUTOWIRED = new Annotation(\"@Autowired\", \"org.springframework.beans.factory.annotation.Autowired\");\n\n    public static final Annotation RESOURCE = new Annotation(\"@Resource\", \"javax.annotation.Resource\");\n\n    public static final Annotation SelectProvider = new Annotation(\"@SelectProvider\", \"org.apache.ibatis.annotations.SelectProvider\");\n    public static final Annotation InsertProvider = new Annotation(\"@InsertProvider\", \"org.apache.ibatis.annotations.InsertProvider\");\n    public static final Annotation DeleteProvider = new Annotation(\"@DeleteProvider\", \"org.apache.ibatis.annotations.DeleteProvider\");\n    public static final Annotation UpdateProvider = new Annotation(\"@UpdateProvider\", \"org.apache.ibatis.annotations.UpdateProvider\");\n\n    public static final Set<Annotation> STATEMENT_SYMMETRIES = ImmutableSet.of(SELECT, UPDATE, INSERT, DELETE,\n            SelectProvider, InsertProvider, DeleteProvider, UpdateProvider);\n\n    private final String label;\n\n    private final String qualifiedName;\n\n    private Map<String, AnnotationValue> attributePairs;\n\n    public interface AnnotationValue {\n    }\n\n    public static class StringValue implements AnnotationValue {\n\n        private String value;\n\n        public StringValue(@NotNull String value) {\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            return \"\\\"\" + value + \"\\\"\";\n        }\n\n    }\n\n    public Annotation(@NotNull String label, @NotNull String qualifiedName) {\n        this.label = label;\n        this.qualifiedName = qualifiedName;\n        attributePairs = Maps.newHashMap();\n    }\n\n    private Annotation addAttribute(String key, AnnotationValue value) {\n        this.attributePairs.put(key, value);\n        return this;\n    }\n\n    public Annotation withAttribute(@NotNull String key, @NotNull AnnotationValue value) {\n        Annotation copy = this.clone();\n        copy.attributePairs = Maps.newHashMap(this.attributePairs);\n        return copy.addAttribute(key, value);\n    }\n\n    public Annotation withValue(@NotNull AnnotationValue value) {\n        return withAttribute(\"value\", value);\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder(label);\n        if (!Iterables.isEmpty(attributePairs.entrySet())) {\n            builder.append(setupAttributeText());\n        }\n        return builder.toString();\n    }\n\n    private String setupAttributeText() {\n        Optional<String> singleValue = getSingleValue();\n        return singleValue.isPresent() ? singleValue.get() : getComplexValue();\n    }\n\n    private String getComplexValue() {\n        StringBuilder builder = new StringBuilder(\"(\");\n        for (String key : attributePairs.keySet()) {\n            builder.append(key);\n            builder.append(\" = \");\n            builder.append(attributePairs.get(key).toString());\n            builder.append(\", \");\n        }\n        builder.deleteCharAt(builder.length() - 1);\n        builder.deleteCharAt(builder.length() - 1);\n        builder.append(\")\");\n        return builder.toString();\n    }\n\n    @NotNull\n    public Optional<PsiClass> toPsiClass(@NotNull Project project) {\n        return Optional.ofNullable(JavaPsiFacade.getInstance(project).findClass(getQualifiedName(), GlobalSearchScope.allScope(project)));\n    }\n\n    private Optional<String> getSingleValue() {\n        try {\n            String value = Iterables.getOnlyElement(attributePairs.keySet());\n            StringBuilder builder = new StringBuilder(\"(\");\n            builder.append(attributePairs.get(value).toString());\n            builder.append(\")\");\n            return Optional.of(builder.toString());\n        } catch (Exception e) {\n            return Optional.empty();\n        }\n    }\n\n    @NotNull\n    public String getLabel() {\n        return label;\n    }\n\n    @NotNull\n    public String getQualifiedName() {\n        return qualifiedName;\n    }\n\n    @Override\n    protected Annotation clone() {\n        try {\n            return (Annotation) super.clone();\n        } catch (CloneNotSupportedException e) {\n            throw new IllegalStateException();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/contributor/JavaMenthodCompletionContributor.java",
    "content": "package com.wuzhizhan.mybatis.contributor;\n\nimport com.intellij.codeInsight.completion.CompletionContributor;\nimport com.intellij.codeInsight.completion.CompletionParameters;\nimport com.intellij.codeInsight.completion.CompletionResultSet;\nimport com.intellij.codeInsight.completion.CompletionType;\n\npublic class JavaMenthodCompletionContributor extends CompletionContributor {\n    @Override\n    public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet result) {\n        if (parameters.getCompletionType() != CompletionType.BASIC) {\n            return;\n        }\n\n        //todo\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/contributor/SqlParamCompletionContributor.java",
    "content": "package com.wuzhizhan.mybatis.contributor;\n\nimport com.intellij.codeInsight.completion.CompletionContributor;\nimport com.intellij.codeInsight.completion.CompletionParameters;\nimport com.intellij.codeInsight.completion.CompletionResultSet;\nimport com.intellij.codeInsight.completion.CompletionType;\nimport com.intellij.injected.editor.DocumentWindow;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiFile;\nimport com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;\nimport com.wuzhizhan.mybatis.dom.model.IdDomElement;\nimport com.wuzhizhan.mybatis.util.DomUtils;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\n\nimport java.util.Optional;\n\n\n/**\n * @author yanglin\n */\npublic class SqlParamCompletionContributor extends CompletionContributor {\n\n    @Override\n    public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet result) {\n        if (parameters.getCompletionType() != CompletionType.BASIC) {\n            return;\n        }\n\n        PsiElement position = parameters.getPosition();\n        PsiFile topLevelFile = InjectedLanguageUtil.getTopLevelFile(position);\n        if (DomUtils.isMybatisFile(topLevelFile)) {\n            if (shouldAddElement(position.getContainingFile(), parameters.getOffset())) {\n                process(topLevelFile, result, position);\n            }\n        }\n    }\n\n    private void process(PsiFile xmlFile, CompletionResultSet result, PsiElement position) {\n        DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(position);\n        if (null != documentWindow) {\n            int offset = documentWindow.injectedToHost(position.getTextOffset());\n            Optional<IdDomElement> idDomElement = MapperUtils.findParentIdDomElement(xmlFile.findElementAt(offset));\n            if (idDomElement.isPresent()) {\n                TestParamContributor.addElementForPsiParameter(position.getProject(), result, idDomElement.get());\n                result.stopHere();\n            }\n        }\n    }\n\n    private boolean shouldAddElement(PsiFile file, int offset) {\n        String text = file.getText();\n        for (int i = offset - 1; i > 0; i--) {\n            char c = text.charAt(i);\n            if (c == '{' && text.charAt(i - 1) == '#') return true;\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/contributor/TestParamContributor.java",
    "content": "package com.wuzhizhan.mybatis.contributor;\n\nimport com.intellij.codeInsight.completion.*;\nimport com.intellij.codeInsight.lookup.LookupElement;\nimport com.intellij.codeInsight.lookup.LookupElementBuilder;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.patterns.XmlPatterns;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiMethod;\nimport com.intellij.psi.PsiParameter;\nimport com.intellij.util.ProcessingContext;\nimport com.wuzhizhan.mybatis.annotation.Annotation;\nimport com.wuzhizhan.mybatis.dom.model.IdDomElement;\nimport com.wuzhizhan.mybatis.util.Icons;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport com.wuzhizhan.mybatis.util.MybatisConstants;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic class TestParamContributor extends CompletionContributor {\n    private static final Logger logger = LoggerFactory.getLogger(TestParamContributor.class);\n\n    public TestParamContributor() {\n        extend(CompletionType.BASIC,\n                XmlPatterns.psiElement()\n                        .inside(XmlPatterns.xmlAttributeValue()\n                                .inside(XmlPatterns.xmlAttribute().withName(\"test\"))),\n                new CompletionProvider<CompletionParameters>() {\n                    @Override\n                    protected void addCompletions(\n                            @NotNull final CompletionParameters parameters,\n                            final ProcessingContext context,\n                            @NotNull final CompletionResultSet result) {\n                        final PsiElement position = parameters.getPosition();\n                        addElementForPsiParameter(\n                                position.getProject(),\n                                result,\n                                MapperUtils.findParentIdDomElement(position).orElse(null));\n                    }\n                });\n    }\n\n    static void addElementForPsiParameter(\n            @NotNull final Project project,\n            @NotNull final CompletionResultSet result,\n            @Nullable final IdDomElement element) {\n        if (element == null) {\n            return;\n        }\n\n        final PsiMethod method = JavaUtils.findMethod(project, element).orElse(null);\n\n        if (method == null) {\n            logger.info(\"psiMethod null\");\n            return;\n        }\n\n        final PsiParameter[] parameters = method.getParameterList().getParameters();\n\n        // For a single parameter MyBatis uses its name, while for a multitude they're\n        // named as param1, param2, etc. I'll check if the @Param annotation [value] is present\n        // and eventually I'll use its text.\n        if (parameters.length == 1) {\n            final PsiParameter parameter = parameters[0];\n            result.addElement(buildLookupElementWithIcon(\n                    parameter.getName(),\n                    parameter.getType().getPresentableText()));\n        } else {\n            for (int i = 0; i < parameters.length; i++) {\n                final PsiParameter parameter = parameters[i];\n                final Optional<String> value = JavaUtils.getAnnotationValueText(parameter, Annotation.PARAM);\n                result.addElement(buildLookupElementWithIcon(\n                        value.isPresent() ? value.get() : \"param\" + (i + 1),\n                        parameter.getType().getPresentableText()));\n            }\n        }\n    }\n\n    private static LookupElement buildLookupElementWithIcon(\n            final String parameterName,\n            final String parameterType) {\n        return PrioritizedLookupElement.withPriority(\n                LookupElementBuilder.create(parameterName)\n                        .withTypeText(parameterType)\n                        .withIcon(Icons.PARAM_COMPLETION_ICON),\n                MybatisConstants.PRIORITY);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/definitionsearch/MapperDefinitionSearch.java",
    "content": "package com.wuzhizhan.mybatis.definitionsearch;\n\nimport com.intellij.openapi.application.QueryExecutorBase;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiTypeParameterListOwner;\nimport com.intellij.psi.xml.XmlElement;\nimport com.intellij.util.Processor;\nimport com.intellij.util.xml.DomElement;\nimport com.wuzhizhan.mybatis.service.JavaService;\nimport org.jetbrains.annotations.NotNull;\n\n\n/**\n * @author yanglin\n */\npublic class MapperDefinitionSearch extends QueryExecutorBase<XmlElement, PsiElement> {\n\n    public MapperDefinitionSearch() {\n        super(true);\n    }\n\n    @Override\n    public void processQuery(@NotNull PsiElement queryParameters, @NotNull Processor<? super XmlElement> consumer) {\n        if (!(queryParameters instanceof PsiTypeParameterListOwner)) return;\n\n        Processor<DomElement> processor = domElement -> consumer.process(domElement.getXmlElement());\n\n        JavaService.getInstance(queryParameters.getProject()).process(queryParameters, processor);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/MapperBacktrackingUtils.java",
    "content": "package com.wuzhizhan.mybatis.dom;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.util.PsiTreeUtil;\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport com.intellij.psi.xml.XmlElement;\nimport com.intellij.psi.xml.XmlTag;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.DomUtil;\nimport com.wuzhizhan.mybatis.dom.model.Association;\nimport com.wuzhizhan.mybatis.dom.model.Collection;\nimport com.wuzhizhan.mybatis.dom.model.ParameterMap;\nimport com.wuzhizhan.mybatis.dom.model.ResultMap;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic final class MapperBacktrackingUtils {\n\n    private MapperBacktrackingUtils() {\n        throw new UnsupportedOperationException();\n    }\n\n    public static Optional<PsiClass> getPropertyClazz(XmlAttributeValue attributeValue) {\n        DomElement domElement = DomUtil.getDomElement(attributeValue);\n        if (null == domElement) {\n            return Optional.empty();\n        }\n\n        Collection collection = DomUtil.getParentOfType(domElement, Collection.class, true);\n        if (null != collection && !isWithinSameTag(collection, attributeValue)) {\n            return Optional.ofNullable(collection.getOfType().getValue());\n        }\n\n        Association association = DomUtil.getParentOfType(domElement, Association.class, true);\n        if (null != association && !isWithinSameTag(association, attributeValue)) {\n            return Optional.ofNullable(association.getJavaType().getValue());\n        }\n\n        ParameterMap parameterMap = DomUtil.getParentOfType(domElement, ParameterMap.class, true);\n        if (null != parameterMap && !isWithinSameTag(parameterMap, attributeValue)) {\n            return Optional.ofNullable(parameterMap.getType().getValue());\n        }\n\n        ResultMap resultMap = DomUtil.getParentOfType(domElement, ResultMap.class, true);\n        if (null != resultMap && !isWithinSameTag(resultMap, attributeValue)) {\n            return Optional.ofNullable(resultMap.getType().getValue());\n        }\n        return Optional.empty();\n    }\n\n    public static boolean isWithinSameTag(@NotNull DomElement domElement, @NotNull XmlElement xmlElement) {\n        XmlTag xmlTag = PsiTreeUtil.getParentOfType(xmlElement, XmlTag.class);\n        return null != xmlElement && domElement.getXmlTag().equals(xmlTag);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/converter/AliasConverter.java",
    "content": "package com.wuzhizhan.mybatis.dom.converter;\n\nimport com.intellij.openapi.util.text.StringUtil;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiReference;\nimport com.intellij.psi.search.GlobalSearchScope;\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport com.intellij.util.xml.*;\nimport com.wuzhizhan.mybatis.alias.AliasClassReference;\nimport com.wuzhizhan.mybatis.alias.AliasFacade;\nimport com.wuzhizhan.mybatis.util.MybatisConstants;\nimport org.jetbrains.annotations.NonNls;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\n/**\n * @author yanglin\n */\npublic class AliasConverter extends ConverterAdaptor<PsiClass> implements CustomReferenceConverter<PsiClass> {\n\n    private PsiClassConverter delegate = new PsiClassConverter();\n\n    @Nullable\n    @Override\n    public PsiClass fromString(@Nullable @NonNls String s, ConvertContext context) {\n        if (StringUtil.isEmptyOrSpaces(s)) return null;\n        if (!s.contains(MybatisConstants.DOT_SEPARATOR)) {\n            return AliasFacade.getInstance(context.getProject()).findPsiClass(context.getXmlElement(), s).orElse(null);\n        }\n        return DomJavaUtil.findClass(s.trim(), context.getFile(), context.getModule(), GlobalSearchScope.allScope(context.getProject()));\n    }\n\n    @Nullable\n    @Override\n    public String toString(@Nullable PsiClass psiClass, ConvertContext context) {\n        return delegate.toString(psiClass, context);\n    }\n\n    @NotNull\n    @Override\n    public PsiReference[] createReferences(GenericDomValue<PsiClass> value, PsiElement element, ConvertContext context) {\n        if (((XmlAttributeValue) element).getValue().contains(MybatisConstants.DOT_SEPARATOR)) {\n            return delegate.createReferences(value, element, context);\n        } else {\n            return new PsiReference[]{new AliasClassReference((XmlAttributeValue) element)};\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/converter/ConverterAdaptor.java",
    "content": "package com.wuzhizhan.mybatis.dom.converter;\n\nimport com.intellij.util.xml.ConvertContext;\nimport com.intellij.util.xml.ResolvingConverter;\nimport org.jetbrains.annotations.NonNls;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\n/**\n * @author yanglin\n */\npublic abstract class ConverterAdaptor<T> extends ResolvingConverter<T> {\n\n    @NotNull\n    @Override\n    public Collection<? extends T> getVariants(ConvertContext context) {\n        return Collections.emptyList();\n    }\n\n    @Nullable\n    @Override\n    public String toString(@Nullable T t, ConvertContext context) {\n//    throw new UnsupportedOperationException();\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public T fromString(@Nullable @NonNls String s, ConvertContext context) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/converter/DaoMethodConverter.java",
    "content": "package com.wuzhizhan.mybatis.dom.converter;\n\nimport com.intellij.psi.PsiMethod;\nimport com.intellij.util.xml.ConvertContext;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.jetbrains.annotations.NonNls;\nimport org.jetbrains.annotations.Nullable;\n\n/**\n * @author yanglin\n */\npublic class DaoMethodConverter extends ConverterAdaptor<PsiMethod> {\n\n    @Nullable\n    @Override\n    public PsiMethod fromString(@Nullable @NonNls String id, ConvertContext context) {\n        Mapper mapper = MapperUtils.getMapper(context.getInvocationElement());\n        return JavaUtils.findMethod(context.getProject(), MapperUtils.getNamespace(mapper), id).orElse(null);\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/converter/IdBasedTagConverter.java",
    "content": "package com.wuzhizhan.mybatis.dom.converter;\n\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Sets;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.openapi.util.TextRange;\nimport com.intellij.psi.ElementManipulators;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiReference;\nimport com.intellij.psi.PsiReferenceBase;\nimport com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider;\nimport com.intellij.psi.search.GlobalSearchScope;\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport com.intellij.util.xml.*;\nimport com.wuzhizhan.mybatis.dom.model.IdDomElement;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport com.wuzhizhan.mybatis.util.MybatisConstants;\nimport org.jetbrains.annotations.NonNls;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.*;\n\n/**\n * @author yanglin\n */\npublic abstract class IdBasedTagConverter extends ConverterAdaptor<XmlAttributeValue> implements CustomReferenceConverter<XmlAttributeValue> {\n\n    private final boolean crossMapperSupported;\n\n    public IdBasedTagConverter() {\n        this(true);\n    }\n\n    protected IdBasedTagConverter(boolean crossMapperSupported) {\n        this.crossMapperSupported = crossMapperSupported;\n    }\n\n    @Nullable\n    @Override\n    public XmlAttributeValue fromString(@Nullable @NonNls String value, ConvertContext context) {\n        return matchIdDomElement(selectStrategy(context).getValue(), value, context).orElse(null);\n    }\n\n    @NotNull\n    private Optional<XmlAttributeValue> matchIdDomElement(Collection<? extends IdDomElement> idDomElements, String value, ConvertContext context) {\n        Mapper contextMapper = MapperUtils.getMapper(context.getInvocationElement());\n        for (IdDomElement idDomElement : idDomElements) {\n            if (MapperUtils.getIdSignature(idDomElement).equals(value) ||\n                    MapperUtils.getIdSignature(idDomElement, contextMapper).equals(value)) {\n                return Optional.of(idDomElement.getId().getXmlAttributeValue());\n            }\n        }\n        return Optional.empty();\n    }\n\n    @Nullable\n    @Override\n    public String toString(@Nullable XmlAttributeValue xmlAttribute, ConvertContext context) {\n        DomElement domElement = DomUtil.getDomElement(xmlAttribute.getParent().getParent());\n        if (!(domElement instanceof IdDomElement)) {\n            return null;\n        }\n        Mapper contextMapper = MapperUtils.getMapper(context.getInvocationElement());\n        return MapperUtils.getIdSignature((IdDomElement) domElement, contextMapper);\n    }\n\n    private TraverseStrategy selectStrategy(ConvertContext context) {\n        return crossMapperSupported ? new CrossMapperStrategy(context) : new InsideMapperStrategy(context);\n    }\n\n    /**\n     * @param mapper  mapper in the project, null if {@link #crossMapperSupported} is false\n     * @param context the dom convert context\n     */\n    @NotNull\n    public abstract Collection<? extends IdDomElement> getComparisons(@Nullable Mapper mapper, ConvertContext context);\n\n    private abstract class TraverseStrategy {\n        protected ConvertContext context;\n\n        public TraverseStrategy(@NotNull ConvertContext context) {\n            this.context = context;\n        }\n\n        public abstract Collection<? extends IdDomElement> getValue();\n    }\n\n    private class InsideMapperStrategy extends TraverseStrategy {\n\n        public InsideMapperStrategy(@NotNull ConvertContext context) {\n            super(context);\n        }\n\n        @Override\n        public Collection<? extends IdDomElement> getValue() {\n            return getComparisons(null, context);\n        }\n\n    }\n\n    private class CrossMapperStrategy extends TraverseStrategy {\n\n        public CrossMapperStrategy(@NotNull ConvertContext context) {\n            super(context);\n        }\n\n        @Override\n        public Collection<? extends IdDomElement> getValue() {\n            List<IdDomElement> result = Lists.newArrayList();\n            for (Mapper mapper : MapperUtils.findMappers(context.getProject())) {\n                result.addAll(getComparisons(mapper, context));\n            }\n            return result;\n        }\n\n    }\n\n    @NotNull\n    @Override\n    public PsiReference[] createReferences(GenericDomValue<XmlAttributeValue> value, PsiElement element, ConvertContext context) {\n        return PsiClassConverter.createJavaClassReferenceProvider(value, null, new ValueReferenceProvider(context)).getReferencesByElement(element);\n    }\n\n    private class ValueReferenceProvider extends JavaClassReferenceProvider {\n\n        private ConvertContext context;\n\n        private ValueReferenceProvider(ConvertContext context) {\n            this.context = context;\n        }\n\n        @Nullable\n        @Override\n        public GlobalSearchScope getScope(Project project) {\n            return GlobalSearchScope.allScope(project);\n        }\n\n        /**\n         * It looks like hacking here, as it's a little hard to handle so many different cases as JetBrains does\n         */\n        @NotNull\n        @Override\n        public PsiReference[] getReferencesByString(String text, @NotNull PsiElement position, int offsetInPosition) {\n            List<PsiReference> refs = Lists.newArrayList(super.getReferencesByString(text, position, offsetInPosition));\n            ValueReference vr = new ValueReference(position, getTextRange(position), context, text);\n            if (!refs.isEmpty() && 0 != vr.getVariants().length) {\n                refs.remove(refs.size() - 1);\n                refs.add(vr);\n            }\n            return refs.toArray(new PsiReference[refs.size()]);\n        }\n\n        private TextRange getTextRange(PsiElement element) {\n            String text = element.getText();\n            int index = text.lastIndexOf(MybatisConstants.DOT_SEPARATOR);\n            return -1 == index ? ElementManipulators.getValueTextRange(element) : TextRange.create(text.substring(0, index).length() + 1, text.length() - 1);\n        }\n    }\n\n    private class ValueReference extends PsiReferenceBase<PsiElement> {\n\n        private ConvertContext context;\n        private String text;\n\n        public ValueReference(@NotNull PsiElement element, TextRange rng, ConvertContext context, String text) {\n            super(element, rng, false);\n            this.context = context;\n            this.text = text;\n        }\n\n        @Nullable\n        @Override\n        public PsiElement resolve() {\n            return IdBasedTagConverter.this.fromString(text, context);\n        }\n\n        @NotNull\n        @Override\n        public Object[] getVariants() {\n            Set<String> res = getElement().getText().contains(MybatisConstants.DOT_SEPARATOR) ? setupContextIdSignature() : setupGlobalIdSignature();\n            return res.toArray(new String[res.size()]);\n        }\n\n        private Set<String> setupContextIdSignature() {\n            Set<String> res = Sets.newHashSet();\n            String ns = text.substring(0, text.lastIndexOf(MybatisConstants.DOT_SEPARATOR));\n            for (IdDomElement ele : selectStrategy(context).getValue()) {\n                if (MapperUtils.getNamespace(ele).equals(ns)) {\n                    res.add(MapperUtils.getId(ele));\n                }\n            }\n            return res;\n        }\n\n        private Set<String> setupGlobalIdSignature() {\n            Mapper contextMapper = MapperUtils.getMapper(context.getInvocationElement());\n            Collection<? extends IdDomElement> idDomElements = selectStrategy(context).getValue();\n            Set<String> res = new HashSet<String>(idDomElements.size());\n            for (IdDomElement ele : idDomElements) {\n                res.add(MapperUtils.getIdSignature(ele, contextMapper));\n            }\n            return res;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/converter/ParameterMapConverter.java",
    "content": "package com.wuzhizhan.mybatis.dom.converter;\n\nimport com.intellij.util.xml.ConvertContext;\nimport com.wuzhizhan.mybatis.dom.model.IdDomElement;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\n\n/**\n * @author yanglin\n */\npublic class ParameterMapConverter extends IdBasedTagConverter {\n\n    @NotNull\n    @Override\n    public Collection<? extends IdDomElement> getComparisons(@Nullable Mapper mapper,\n                                                             ConvertContext context) {\n        return mapper.getParameterMaps();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/converter/PropertyConverter.java",
    "content": "package com.wuzhizhan.mybatis.dom.converter;\n\nimport com.intellij.psi.ElementManipulators;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiReference;\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport com.intellij.util.xml.*;\nimport com.wuzhizhan.mybatis.reference.ResultPropertyReferenceSet;\nimport org.jetbrains.annotations.NonNls;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\n/**\n * @author yanglin\n */\npublic class PropertyConverter extends ConverterAdaptor<XmlAttributeValue> implements CustomReferenceConverter<XmlAttributeValue> {\n\n    @NotNull\n    @Override\n    public PsiReference[] createReferences(GenericDomValue<XmlAttributeValue> value, PsiElement element, ConvertContext context) {\n        final String s = value.getStringValue();\n        if (s == null) {\n            return PsiReference.EMPTY_ARRAY;\n        }\n        return new ResultPropertyReferenceSet(s, element, ElementManipulators.getOffsetInElement(element)).getPsiReferences();\n    }\n\n    @Nullable\n    @Override\n    public XmlAttributeValue fromString(@Nullable @NonNls String s, ConvertContext context) {\n        DomElement ctxElement = context.getInvocationElement();\n        return ctxElement instanceof GenericAttributeValue ? ((GenericAttributeValue) ctxElement).getXmlAttributeValue() : null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/converter/ResultMapConverter.java",
    "content": "package com.wuzhizhan.mybatis.dom.converter;\n\nimport com.google.common.base.Predicate;\nimport com.google.common.collect.Collections2;\nimport com.intellij.util.xml.ConvertContext;\nimport com.intellij.util.xml.DomElement;\nimport com.wuzhizhan.mybatis.dom.model.IdDomElement;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.dom.model.ResultMap;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\n\n/**\n * @author yanglin\n */\npublic class ResultMapConverter extends IdBasedTagConverter {\n\n    @NotNull\n    @Override\n    public Collection<? extends IdDomElement> getComparisons(@Nullable Mapper mapper, ConvertContext context) {\n        DomElement invocationElement = context.getInvocationElement();\n        if (isContextElementOfResultMap(mapper, invocationElement)) {\n            return doFilterResultMapItself(mapper, (ResultMap) invocationElement.getParent());\n        } else {\n            return mapper.getResultMaps();\n        }\n    }\n\n    private boolean isContextElementOfResultMap(Mapper mapper, DomElement invocationElement) {\n        return MapperUtils.isMapperWithSameNamespace(MapperUtils.getMapper(invocationElement), mapper)\n                && invocationElement.getParent() instanceof ResultMap;\n    }\n\n    private Collection<? extends IdDomElement> doFilterResultMapItself(Mapper mapper, final ResultMap resultMap) {\n        return Collections2.filter(mapper.getResultMaps(), new Predicate<ResultMap>() {\n            @Override\n            public boolean apply(ResultMap input) {\n                return !MapperUtils.getId(input).equals(MapperUtils.getId(resultMap));\n            }\n        });\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/converter/SqlConverter.java",
    "content": "package com.wuzhizhan.mybatis.dom.converter;\n\nimport com.intellij.util.xml.ConvertContext;\nimport com.wuzhizhan.mybatis.dom.model.IdDomElement;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\n\n/**\n * @author yanglin\n */\npublic class SqlConverter extends IdBasedTagConverter {\n\n    @NotNull\n    @Override\n    public Collection<? extends IdDomElement> getComparisons(@Nullable Mapper mapper, ConvertContext context) {\n        return mapper.getSqls();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/description/ConfigurationDescription.java",
    "content": "package com.wuzhizhan.mybatis.dom.description;\n\nimport com.intellij.openapi.module.Module;\nimport com.intellij.psi.xml.XmlFile;\nimport com.intellij.util.xml.DomFileDescription;\nimport com.wuzhizhan.mybatis.dom.model.Configuration;\nimport com.wuzhizhan.mybatis.util.DomUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\n/**\n * @author yanglin\n */\npublic class ConfigurationDescription extends DomFileDescription<Configuration> {\n\n    public ConfigurationDescription() {\n        super(Configuration.class, \"configuration\");\n    }\n\n    @Override\n    public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) {\n        return DomUtils.isMybatisConfigurationFile(file);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/description/MapperDescription.java",
    "content": "package com.wuzhizhan.mybatis.dom.description;\n\nimport com.intellij.openapi.module.Module;\nimport com.intellij.psi.xml.XmlFile;\nimport com.intellij.util.xml.DomFileDescription;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.util.DomUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\n/**\n * @author yanglin\n */\npublic class MapperDescription extends DomFileDescription<Mapper> {\n\n    public MapperDescription() {\n        super(Mapper.class, \"mapper\");\n    }\n\n    @Override\n    public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) {\n        return DomUtils.isMybatisFile(file);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Arg.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\n\n/**\n * @author yanglin\n */\npublic interface Arg extends DomElement {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Association.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.wuzhizhan.mybatis.dom.converter.AliasConverter;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface Association extends GroupFour, ResultMapGroup, PropertyGroup {\n\n    @NotNull\n    @Attribute(\"javaType\")\n    @Convert(AliasConverter.class)\n    public GenericAttributeValue<PsiClass> getJavaType();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Bean.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.SubTagList;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface Bean extends DomElement {\n\n    @NotNull\n    @SubTagList(\"property\")\n    public List<BeanProperty> getBeanProperties();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/BeanProperty.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface BeanProperty extends DomElement {\n\n    @NotNull\n    @Attribute(\"name\")\n    public GenericAttributeValue<String> getName();\n\n    @NotNull\n    @Attribute(\"value\")\n    public GenericAttributeValue<String> getValue();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Beans.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.SubTagList;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface Beans extends DomElement {\n\n    @NotNull\n    @SubTagList(\"bean\")\n    public List<Bean> getBeans();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Bind.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\n\n/**\n * @author yanglin\n */\npublic interface Bind extends DomElement {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Cache.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.SubTagList;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface Cache extends DomElement {\n\n    @SubTagList(\"property\")\n    public List<Property> getProperties();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/CacheRef.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\n\n/**\n * @author yanglin\n */\npublic interface CacheRef extends DomElement {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Case.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Case extends GroupFour {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Choose.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.Required;\nimport com.intellij.util.xml.SubTag;\nimport com.intellij.util.xml.SubTagList;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface Choose extends DomElement {\n\n    @NotNull\n    @Required\n    @SubTagList(\"when\")\n    public List<When> getWhens();\n\n    @SubTag(\"otherwise\")\n    public Otherwise getOtherwise();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Collection.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.wuzhizhan.mybatis.dom.converter.AliasConverter;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface Collection extends GroupFour, ResultMapGroup, PropertyGroup {\n\n    @NotNull\n    @Attribute(\"ofType\")\n    @Convert(AliasConverter.class)\n    public GenericAttributeValue<PsiClass> getOfType();\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Configuration.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.SubTagList;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface Configuration extends DomElement {\n\n    @NotNull\n    @SubTagList(\"typeAliases\")\n    public List<TypeAliases> getTypeAliases();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Constructor.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.SubTagList;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface Constructor extends DomElement {\n\n    @SubTagList(\"arg\")\n    public List<Arg> getArgs();\n\n    @SubTagList(\"idArg\")\n    public List<IdArg> getIdArgs();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Delete.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Delete extends GroupTwo {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Discriminator.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.Required;\nimport com.intellij.util.xml.SubTagList;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface Discriminator extends DomElement {\n\n    @Required\n    @SubTagList(\"case\")\n    public List<Case> getCases();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Foreach.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Foreach extends GroupOne {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/GroupFour.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.SubTag;\nimport com.intellij.util.xml.SubTagList;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface GroupFour extends DomElement {\n\n    @SubTag(\"constructor\")\n    public Constructor getConstructor();\n\n    @SubTagList(\"id\")\n    public List<Id> getIds();\n\n    @SubTagList(\"result\")\n    public List<Result> getResults();\n\n    @SubTagList(\"association\")\n    public List<Association> getAssociations();\n\n    @SubTagList(\"collection\")\n    public List<Collection> getCollections();\n\n    @SubTag(\"discriminator\")\n    public Discriminator getDiscriminator();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/GroupOne.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.SubTagList;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface GroupOne extends DomElement {\n\n    @NotNull\n    @SubTagList(\"include\")\n    public List<Include> getIncludes();\n\n    @NotNull\n    @SubTagList(\"trim\")\n    public List<Trim> getTrims();\n\n    @NotNull\n    @SubTagList(\"where\")\n    public List<Where> getWheres();\n\n    @NotNull\n    @SubTagList(\"set\")\n    public List<Set> getSets();\n\n    @NotNull\n    @SubTagList(\"foreach\")\n    public List<Foreach> getForeachs();\n\n    @NotNull\n    @SubTagList(\"choose\")\n    public List<Choose> getChooses();\n\n    @NotNull\n    @SubTagList(\"if\")\n    public List<If> getIfs();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/GroupThree.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.SubTagList;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface GroupThree extends GroupTwo {\n\n    @SubTagList(\"selectKey\")\n    public List<SelectKey> getSelectKey();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/GroupTwo.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.xml.XmlTag;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.intellij.util.xml.SubTagList;\nimport com.wuzhizhan.mybatis.dom.converter.AliasConverter;\nimport com.wuzhizhan.mybatis.dom.converter.DaoMethodConverter;\nimport com.wuzhizhan.mybatis.dom.converter.ParameterMapConverter;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface GroupTwo extends GroupOne, IdDomElement {\n\n    @SubTagList(\"bind\")\n    public List<Bind> getBinds();\n\n    @NotNull\n    @Attribute(\"parameterMap\")\n    @Convert(ParameterMapConverter.class)\n    public GenericAttributeValue<XmlTag> getParameterMap();\n\n    @Attribute(\"id\")\n    @Convert(DaoMethodConverter.class)\n    public GenericAttributeValue<String> getId();\n\n    @NotNull\n    @Attribute(\"parameterType\")\n    @Convert(AliasConverter.class)\n    public GenericAttributeValue<PsiClass> getParameterType();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Id.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Id extends PropertyGroup {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/IdArg.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\n\n/**\n * @author yanglin\n */\npublic interface IdArg extends DomElement {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/IdDomElement.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.*;\n\n/**\n * @author yanglin\n */\npublic interface IdDomElement extends DomElement {\n\n    @Required\n    @NameValue\n    @Attribute(\"id\")\n    public GenericAttributeValue<String> getId();\n\n    public void setValue(String content);\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/If.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface If extends GroupOne {\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Include.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.xml.XmlTag;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.wuzhizhan.mybatis.dom.converter.SqlConverter;\n\n/**\n * @author yanglin\n */\npublic interface Include extends DomElement {\n\n    @Attribute(\"refid\")\n    @Convert(SqlConverter.class)\n    public GenericAttributeValue<XmlTag> getRefId();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Insert.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Insert extends GroupThree {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Mapper.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.*;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface Mapper extends DomElement {\n\n    @NotNull\n    @SubTagsList({\"insert\", \"update\", \"delete\", \"select\"})\n    public List<IdDomElement> getDaoElements();\n\n    @Required\n    @NameValue\n    @NotNull\n    @Attribute(\"namespace\")\n    public GenericAttributeValue<String> getNamespace();\n\n    @NotNull\n    @SubTagList(\"resultMap\")\n    public List<ResultMap> getResultMaps();\n\n    @NotNull\n    @SubTagList(\"parameterMap\")\n    public List<ParameterMap> getParameterMaps();\n\n    @NotNull\n    @SubTagList(\"sql\")\n    public List<Sql> getSqls();\n\n    @NotNull\n    @SubTagList(\"insert\")\n    public List<Insert> getInserts();\n\n    @NotNull\n    @SubTagList(\"update\")\n    public List<Update> getUpdates();\n\n    @NotNull\n    @SubTagList(\"delete\")\n    public List<Delete> getDeletes();\n\n    @NotNull\n    @SubTagList(\"select\")\n    public List<Select> getSelects();\n\n    @SubTagList(\"select\")\n    public Select addSelect();\n\n    @SubTagList(\"update\")\n    public Update addUpdate();\n\n    @SubTagList(\"insert\")\n    public Insert addInsert();\n\n    @SubTagList(\"delete\")\n    public Delete addDelete();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Otherwise.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Otherwise extends GroupOne {\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Package.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface Package extends DomElement {\n\n    @NotNull\n    @Attribute(\"name\")\n    public GenericAttributeValue<String> getName();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Parameter.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Parameter extends PropertyGroup {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/ParameterMap.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.intellij.util.xml.SubTagList;\nimport com.wuzhizhan.mybatis.dom.converter.AliasConverter;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface ParameterMap extends IdDomElement {\n\n    @NotNull\n    @Attribute(\"type\")\n    @Convert(AliasConverter.class)\n    public GenericAttributeValue<PsiClass> getType();\n\n    @SubTagList(\"parameter\")\n    public List<Parameter> getParameters();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Property.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\n\n/**\n * @author yanglin\n */\npublic interface Property extends DomElement {\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/PropertyGroup.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.wuzhizhan.mybatis.dom.converter.PropertyConverter;\n\n/**\n * @author yanglin\n */\npublic interface PropertyGroup extends DomElement {\n\n    @Attribute(\"property\")\n    @Convert(PropertyConverter.class)\n    GenericAttributeValue<XmlAttributeValue> getProperty();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Result.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Result extends PropertyGroup {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/ResultMap.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.wuzhizhan.mybatis.dom.converter.AliasConverter;\nimport com.wuzhizhan.mybatis.dom.converter.ResultMapConverter;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface ResultMap extends GroupFour, IdDomElement {\n\n    @NotNull\n    @Attribute(\"extends\")\n    @Convert(ResultMapConverter.class)\n    public GenericAttributeValue<XmlAttributeValue> getExtends();\n\n    @NotNull\n    @Attribute(\"type\")\n    @Convert(AliasConverter.class)\n    public GenericAttributeValue<PsiClass> getType();\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/ResultMapGroup.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.xml.XmlTag;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.wuzhizhan.mybatis.dom.converter.ResultMapConverter;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface ResultMapGroup extends DomElement {\n\n    @NotNull\n    @Attribute(\"resultMap\")\n    @Convert(ResultMapConverter.class)\n    public GenericAttributeValue<XmlTag> getResultMap();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Select.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.wuzhizhan.mybatis.dom.converter.AliasConverter;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface Select extends GroupTwo, ResultMapGroup {\n\n    @NotNull\n    @Attribute(\"resultType\")\n    @Convert(AliasConverter.class)\n    public GenericAttributeValue<PsiClass> getResultType();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/SelectKey.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.Convert;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.wuzhizhan.mybatis.dom.converter.AliasConverter;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface SelectKey extends GroupOne {\n    @NotNull\n    @Attribute(\"resultType\")\n    @Convert(AliasConverter.class)\n    GenericAttributeValue<PsiClass> getResultType();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Set.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Set extends GroupOne {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Sql.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Sql extends GroupOne, IdDomElement {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Trim.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Trim extends GroupOne {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/TypeAlias.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.util.xml.Attribute;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface TypeAlias extends DomElement {\n\n    @NotNull\n    @Attribute(\"type\")\n    public GenericAttributeValue<PsiClass> getType();\n\n    @NotNull\n    @Attribute(\"alias\")\n    public GenericAttributeValue<String> getAlias();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/TypeAliases.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.SubTagList;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic interface TypeAliases extends DomElement {\n\n    @NotNull\n    @SubTagList(\"typeAlias\")\n    public List<TypeAlias> getTypeAlias();\n\n    @NotNull\n    @SubTagList(\"package\")\n    public List<Package> getPackages();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Update.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Update extends GroupTwo {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/When.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface When extends GroupOne {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/dom/model/Where.java",
    "content": "package com.wuzhizhan.mybatis.dom.model;\n\n/**\n * @author yanglin\n */\npublic interface Where extends GroupOne {\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/generate/DeleteGenerator.java",
    "content": "package com.wuzhizhan.mybatis.generate;\n\nimport com.intellij.psi.PsiMethod;\nimport com.wuzhizhan.mybatis.dom.model.GroupTwo;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class DeleteGenerator extends StatementGenerator {\n\n    public DeleteGenerator(@NotNull String... patterns) {\n        super(patterns);\n    }\n\n    @NotNull\n    @Override\n    protected GroupTwo getTarget(@NotNull Mapper mapper, @NotNull PsiMethod method) {\n        return mapper.addDelete();\n    }\n\n    @NotNull\n    @Override\n    public String getId() {\n        return \"DeleteGenerator\";\n    }\n\n    @NotNull\n    @Override\n    public String getDisplayText() {\n        return \"Delete Statement\";\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/generate/GenerateModel.java",
    "content": "package com.wuzhizhan.mybatis.generate;\n\nimport java.util.Collection;\n\n/**\n * @author yanglin\n */\npublic abstract class GenerateModel {\n\n    public static final GenerateModel START_WITH_MODEL = new StartWithModel();\n\n    public static final GenerateModel END_WITH_MODEL = new EndWithModel();\n\n    public static final GenerateModel CONTAIN_MODEL = new ContainModel();\n\n    public static GenerateModel getInstance(String identifier) {\n        try {\n            return getInstance(Integer.valueOf(identifier));\n        } catch (Exception e) {\n            return START_WITH_MODEL;\n        }\n    }\n\n    public static GenerateModel getInstance(int identifier) {\n        switch (identifier) {\n            case 0:\n                return START_WITH_MODEL;\n            case 1:\n                return END_WITH_MODEL;\n            case 2:\n                return CONTAIN_MODEL;\n            default:\n                throw new AssertionError();\n        }\n    }\n\n    public boolean matchesAny(String[] patterns, String target) {\n        for (String pattern : patterns) {\n            if (apply(pattern, target)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public boolean matchesAny(Collection<String> patterns, String target) {\n        return matchesAny(patterns.toArray(new String[patterns.size()]), target);\n    }\n\n    protected abstract boolean apply(String pattern, String target);\n\n    public abstract int getIdentifier();\n\n    static class StartWithModel extends GenerateModel {\n\n        @Override\n        protected boolean apply(String pattern, String target) {\n            return target.startsWith(pattern);\n        }\n\n        @Override\n        public int getIdentifier() {\n            return 0;\n        }\n    }\n\n    static class EndWithModel extends GenerateModel {\n\n        @Override\n        protected boolean apply(String pattern, String target) {\n            return target.endsWith(pattern);\n        }\n\n        @Override\n        public int getIdentifier() {\n            return 1;\n        }\n    }\n\n    static class ContainModel extends GenerateModel {\n\n        @Override\n        protected boolean apply(String pattern, String target) {\n            return target.contains(pattern);\n        }\n\n        @Override\n        public int getIdentifier() {\n            return 2;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/generate/InsertGenerator.java",
    "content": "package com.wuzhizhan.mybatis.generate;\n\nimport com.intellij.psi.PsiMethod;\nimport com.wuzhizhan.mybatis.dom.model.GroupTwo;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class InsertGenerator extends StatementGenerator {\n\n    public InsertGenerator(@NotNull String... patterns) {\n        super(patterns);\n    }\n\n    @NotNull\n    @Override\n    protected GroupTwo getTarget(@NotNull Mapper mapper, @NotNull PsiMethod method) {\n        return mapper.addInsert();\n    }\n\n    @NotNull\n    @Override\n    public String getId() {\n        return \"InsertGenerator\";\n    }\n\n    @NotNull\n    @Override\n    public String getDisplayText() {\n        return \"Insert Statement\";\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/generate/SelectGenerator.java",
    "content": "package com.wuzhizhan.mybatis.generate;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiMethod;\nimport com.wuzhizhan.mybatis.dom.model.GroupTwo;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.dom.model.Select;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic class SelectGenerator extends StatementGenerator {\n\n    public SelectGenerator(@NotNull String... patterns) {\n        super(patterns);\n    }\n\n    @NotNull\n    @Override\n    protected GroupTwo getTarget(@NotNull Mapper mapper, @NotNull PsiMethod method) {\n        Select select = mapper.addSelect();\n        setupResultType(method, select);\n        return select;\n    }\n\n    private void setupResultType(PsiMethod method, Select select) {\n        Optional<PsiClass> clazz = StatementGenerator.getSelectResultType(method);\n        if (clazz.isPresent()) {\n            select.getResultType().setValue(clazz.get());\n        }\n    }\n\n    @NotNull\n    @Override\n    public String getId() {\n        return \"SelectGenerator\";\n    }\n\n    @NotNull\n    @Override\n    public String getDisplayText() {\n        return \"Select Statement\";\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/generate/StatementGenerator.java",
    "content": "package com.wuzhizhan.mybatis.generate;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.*;\nimport com.intellij.openapi.command.WriteCommandAction;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.openapi.ui.popup.JBPopupFactory;\nimport com.intellij.openapi.ui.popup.PopupStep;\nimport com.intellij.openapi.ui.popup.util.BaseListPopupStep;\nimport com.intellij.openapi.vfs.VirtualFile;\nimport com.intellij.psi.*;\nimport com.intellij.psi.impl.source.PsiClassReferenceType;\nimport com.intellij.psi.xml.XmlTag;\nimport com.intellij.util.CommonProcessors.CollectProcessor;\nimport com.wuzhizhan.mybatis.dom.model.GroupTwo;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.service.EditorService;\nimport com.wuzhizhan.mybatis.service.JavaService;\nimport com.wuzhizhan.mybatis.setting.MybatisSetting;\nimport com.wuzhizhan.mybatis.ui.ListSelectionListener;\nimport com.wuzhizhan.mybatis.ui.UiComponentFacade;\nimport com.wuzhizhan.mybatis.util.CollectionUtils;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic abstract class StatementGenerator {\n\n    public static final StatementGenerator UPDATE_GENERATOR = new UpdateGenerator(\"update\", \"modify\", \"set\");\n\n    public static final StatementGenerator SELECT_GENERATOR = new SelectGenerator(\"select\", \"get\", \"look\", \"find\", \"list\", \"search\", \"count\", \"query\");\n\n    public static final StatementGenerator DELETE_GENERATOR = new DeleteGenerator(\"del\", \"cancel\");\n\n    public static final StatementGenerator INSERT_GENERATOR = new InsertGenerator(\"insert\", \"add\", \"new\");\n\n    public static final Set<StatementGenerator> ALL = ImmutableSet.of(UPDATE_GENERATOR, SELECT_GENERATOR, DELETE_GENERATOR, INSERT_GENERATOR);\n\n    private static final Function<Mapper, String> FUN = new Function<Mapper, String>() {\n        @Override\n        public String apply(Mapper mapper) {\n            VirtualFile vf = mapper.getXmlTag().getContainingFile().getVirtualFile();\n            if (null == vf) return \"\";\n            return vf.getCanonicalPath();\n        }\n    };\n\n    public static Optional<PsiClass> getSelectResultType(@Nullable PsiMethod method) {\n        if (null == method) {\n            return Optional.empty();\n        }\n        PsiType returnType = method.getReturnType();\n        if (returnType instanceof PsiPrimitiveType && returnType != PsiType.VOID) {\n            return JavaUtils.findClazz(method.getProject(), ((PsiPrimitiveType) returnType).getBoxedTypeName());\n        } else if (returnType instanceof PsiClassReferenceType) {\n            PsiClassReferenceType type = (PsiClassReferenceType) returnType;\n            if (type.hasParameters()) {\n                PsiType[] parameters = type.getParameters();\n                if (parameters.length == 1) {\n                    type = (PsiClassReferenceType) parameters[0];\n                }\n            }\n            return Optional.ofNullable(type.resolve());\n        }\n        return Optional.empty();\n    }\n\n    private static void doGenerate(@NotNull final StatementGenerator generator, @NotNull final PsiMethod method) {\n        (new WriteCommandAction.Simple(method.getProject(), new PsiFile[]{method.getContainingFile()}) {\n            protected void run() throws Throwable {\n                generator.execute(method);\n            }\n        }).execute();\n    }\n\n    public static void applyGenerate(@Nullable final PsiMethod method) {\n        if (null == method) return;\n        final Project project = method.getProject();\n        final Object[] generators = getGenerators(method);\n        if (1 == generators.length) {\n            ((StatementGenerator) generators[0]).execute(method);\n        } else {\n            JBPopupFactory.getInstance().createListPopup(\n                    new BaseListPopupStep(\"[ Statement type for method: \" + method.getName() + \"]\", generators) {\n                        @Override\n                        public PopupStep onChosen(Object selectedValue, boolean finalChoice) {\n                            return this.doFinalStep(new Runnable() {\n                                public void run() {\n                                    WriteCommandAction.runWriteCommandAction(project, new Runnable() {\n                                        public void run() {\n                                            StatementGenerator.doGenerate((StatementGenerator) selectedValue, method);\n                                        }\n                                    });\n                                }\n                            });\n                        }\n                    }\n            ).showInFocusCenter();\n        }\n    }\n\n    @NotNull\n    public static StatementGenerator[] getGenerators(@NotNull PsiMethod method) {\n        GenerateModel model = MybatisSetting.getInstance().getStatementGenerateModel();\n        String target = method.getName();\n        List<StatementGenerator> result = Lists.newArrayList();\n        for (StatementGenerator generator : ALL) {\n            if (model.matchesAny(generator.getPatterns(), target)) {\n                result.add(generator);\n            }\n        }\n        return CollectionUtils.isNotEmpty(result) ? result.toArray(new StatementGenerator[result.size()]) : ALL.toArray(new StatementGenerator[ALL.size()]);\n    }\n\n    private Set<String> patterns;\n\n    public StatementGenerator(@NotNull String... patterns) {\n        this.patterns = Sets.newHashSet(patterns);\n    }\n\n    public void execute(@NotNull final PsiMethod method) {\n        PsiClass psiClass = method.getContainingClass();\n        if (null == psiClass) return;\n        CollectProcessor processor = new CollectProcessor();\n        JavaService.getInstance(method.getProject()).process(psiClass, processor);\n        final List<Mapper> mappers = Lists.newArrayList(processor.getResults());\n        if (1 == mappers.size()) {\n            setupTag(method, (Mapper) Iterables.getOnlyElement(mappers, (Object) null));\n        } else if (mappers.size() > 1) {\n            Collection<String> paths = Collections2.transform(mappers, FUN);\n            UiComponentFacade.getInstance(method.getProject()).showListPopup(\"Choose target mapper xml to generate\", new ListSelectionListener() {\n                @Override\n                public void selected(int index) {\n                    setupTag(method, mappers.get(index));\n                }\n\n                @Override\n                public boolean isWriteAction() {\n                    return true;\n                }\n            }, paths.toArray(new String[paths.size()]));\n        }\n    }\n\n    private void setupTag(PsiMethod method, Mapper mapper) {\n        GroupTwo target = getTarget(mapper, method);\n        target.getId().setStringValue(method.getName());\n        target.setValue(\" \");\n        XmlTag tag = target.getXmlTag();\n        int offset = tag.getTextOffset() + tag.getTextLength() - tag.getName().length() + 1;\n        EditorService editorService = EditorService.getInstance(method.getProject());\n        editorService.format(tag.getContainingFile(), tag);\n        editorService.scrollTo(tag, offset);\n    }\n\n    @Override\n    public String toString() {\n        return this.getDisplayText();\n    }\n\n    @NotNull\n    protected abstract GroupTwo getTarget(@NotNull Mapper mapper, @NotNull PsiMethod method);\n\n    @NotNull\n    public abstract String getId();\n\n    @NotNull\n    public abstract String getDisplayText();\n\n    public Set<String> getPatterns() {\n        return patterns;\n    }\n\n    public void setPatterns(Set<String> patterns) {\n        this.patterns = patterns;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/generate/UpdateGenerator.java",
    "content": "package com.wuzhizhan.mybatis.generate;\n\nimport com.intellij.psi.PsiMethod;\nimport com.wuzhizhan.mybatis.dom.model.GroupTwo;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class UpdateGenerator extends StatementGenerator {\n\n    public UpdateGenerator(@NotNull String... patterns) {\n        super(patterns);\n    }\n\n    @NotNull\n    @Override\n    protected GroupTwo getTarget(@NotNull Mapper mapper, @NotNull PsiMethod method) {\n        return mapper.addUpdate();\n    }\n\n    @NotNull\n    @Override\n    public String getId() {\n        return \"UpdateGenerator\";\n    }\n\n    @NotNull\n    @Override\n    public String getDisplayText() {\n        return \"Update Statement\";\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/inspection/GenericQuickFix.java",
    "content": "package com.wuzhizhan.mybatis.inspection;\n\nimport com.intellij.codeInspection.LocalQuickFix;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic abstract class GenericQuickFix implements LocalQuickFix {\n\n    @NotNull\n    @Override\n    public String getFamilyName() {\n        return getName();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/inspection/MapperInspection.java",
    "content": "package com.wuzhizhan.mybatis.inspection;\n\nimport com.intellij.codeInspection.BaseJavaLocalInspectionTool;\nimport com.intellij.codeInspection.ProblemDescriptor;\n\n/**\n * @author yanglin\n */\npublic abstract class MapperInspection extends BaseJavaLocalInspectionTool {\n\n    public static final ProblemDescriptor[] EMPTY_ARRAY = new ProblemDescriptor[0];\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/inspection/MapperMethodInspection.java",
    "content": "package com.wuzhizhan.mybatis.inspection;\n\nimport com.intellij.codeInspection.InspectionManager;\nimport com.intellij.codeInspection.LocalQuickFix;\nimport com.intellij.codeInspection.ProblemDescriptor;\nimport com.intellij.codeInspection.ProblemHighlightType;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiIdentifier;\nimport com.intellij.psi.PsiMethod;\nimport com.intellij.psi.PsiModifier;\nimport com.intellij.util.xml.DomElement;\nimport com.wuzhizhan.mybatis.annotation.Annotation;\nimport com.wuzhizhan.mybatis.dom.model.Select;\nimport com.wuzhizhan.mybatis.generate.StatementGenerator;\nimport com.wuzhizhan.mybatis.locator.MapperLocator;\nimport com.wuzhizhan.mybatis.service.JavaService;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic class MapperMethodInspection extends MapperInspection {\n    @Nullable\n    @Override\n    public ProblemDescriptor[] checkMethod(\n            @NotNull final PsiMethod method,\n            @NotNull final InspectionManager manager,\n            final boolean isOnTheFly) {\n        if (!MapperLocator.getInstance(method.getProject()).process(method) ||\n                JavaUtils.isAnyAnnotationPresent(method, Annotation.STATEMENT_SYMMETRIES)\n                || method.getModifierList().hasModifierProperty(PsiModifier.STATIC)) {\n            return EMPTY_ARRAY;\n        }\n\n        final List<ProblemDescriptor> problems = createProblemDescriptors(method, manager, isOnTheFly);\n        return problems.toArray(new ProblemDescriptor[0]);\n    }\n\n    private List<ProblemDescriptor> createProblemDescriptors(\n            final PsiMethod method,\n            final InspectionManager manager,\n            final boolean isOnTheFly) {\n        final List<ProblemDescriptor> problems = new ArrayList<>(2);\n        Optional<ProblemDescriptor> optionalProblem = checkStatementExists(method, manager, isOnTheFly);\n\n        if (optionalProblem.isPresent()) {\n            problems.add(optionalProblem.get());\n        }\n\n        optionalProblem = checkResultType(method, manager, isOnTheFly);\n\n        if (optionalProblem.isPresent()) {\n            problems.add(optionalProblem.get());\n        }\n\n        return problems;\n    }\n\n    private Optional<ProblemDescriptor> checkResultType(\n            final PsiMethod method,\n            final InspectionManager manager,\n            final boolean isOnTheFly) {\n        final Optional<DomElement> optionalDomElement =\n                JavaService.getInstance(method.getProject())\n                        .findStatement(method);\n\n        if (!optionalDomElement.isPresent()) {\n            return Optional.empty();\n        }\n\n        final DomElement domElement = optionalDomElement.get();\n\n        if (domElement instanceof Select) {\n            final Select selectStatement = (Select) domElement;\n\n            if (selectStatement.getResultMap().getValue() != null) {\n                return Optional.empty();\n            }\n\n            final Optional<PsiClass> methodResultType = StatementGenerator.getSelectResultType(method);\n            final PsiClass selectResultType = selectStatement.getResultType().getValue();\n            final PsiIdentifier methodName = method.getNameIdentifier();\n\n            if (methodName != null) {\n                if (methodResultType.isPresent()) {\n                    if (selectResultType == null ||\n                            (selectResultType.getQualifiedName() != null\n                                    && !selectResultType.getQualifiedName().equals(methodResultType.get().getQualifiedName())\n                                    && !selectResultType.isInheritor(methodResultType.get(), true))) {\n\n                        return Optional.of(\n                                manager.createProblemDescriptor(\n                                        methodName,\n                                        \"Result type doesn't match for Select id=\\\"#ref\\\"\",\n                                        new ResultTypeQuickFix(selectStatement, methodResultType.get()),\n                                        ProblemHighlightType.GENERIC_ERROR,\n                                        isOnTheFly));\n\n                    }\n                }\n                if (!methodResultType.isPresent() && selectResultType != null) {\n                    return Optional.of(\n                            manager.createProblemDescriptor(\n                                    methodName,\n                                    \"Result type doesn't match for Select id=\\\"#ref\\\"\",\n                                    (LocalQuickFix) null,\n                                    ProblemHighlightType.GENERIC_ERROR,\n                                    isOnTheFly));\n                }\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    private Optional<ProblemDescriptor> checkStatementExists(\n            final PsiMethod method,\n            final InspectionManager manager,\n            final boolean isOnTheFly) {\n        final PsiIdentifier methodName = method.getNameIdentifier();\n\n        if (method.hasModifierProperty(PsiModifier.DEFAULT)) {\n            return Optional.empty();\n        }\n\n        if (!JavaService.getInstance(method.getProject()).findStatement(method).isPresent() && null != methodName) {\n            return Optional.of(manager.createProblemDescriptor(\n                    methodName,\n                    \"Statement with id=\\\"#ref\\\" not defined in mapper XML\",\n                    new StatementNotExistsQuickFix(method),\n                    ProblemHighlightType.GENERIC_ERROR,\n                    isOnTheFly));\n        }\n\n        return Optional.empty();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/inspection/MapperXmlInspection.java",
    "content": "package com.wuzhizhan.mybatis.inspection;\n\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.highlighting.BasicDomElementsInspection;\nimport com.intellij.util.xml.highlighting.DomElementAnnotationHolder;\nimport com.intellij.util.xml.highlighting.DomHighlightingHelper;\n\n/**\n * @author yanglin\n */\npublic class MapperXmlInspection extends BasicDomElementsInspection<DomElement> {\n\n    public MapperXmlInspection() {\n        super(DomElement.class);\n    }\n\n    @Override\n    protected void checkDomElement(DomElement element, DomElementAnnotationHolder holder, DomHighlightingHelper helper) {\n        super.checkDomElement(element, holder, helper);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/inspection/ResultTypeQuickFix.java",
    "content": "package com.wuzhizhan.mybatis.inspection;\n\nimport com.intellij.codeInspection.ProblemDescriptor;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.util.xml.GenericAttributeValue;\nimport com.wuzhizhan.mybatis.dom.model.Select;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class ResultTypeQuickFix extends GenericQuickFix {\n\n    private Select select;\n    private PsiClass target;\n\n    public ResultTypeQuickFix(@NotNull Select select, @NotNull PsiClass target) {\n        this.select = select;\n        this.target = target;\n    }\n\n    @NotNull\n    @Override\n    public String getName() {\n        return \"Correct resultType\";\n    }\n\n    @Override\n    public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {\n        GenericAttributeValue<PsiClass> resultType = select.getResultType();\n        resultType.setValue(target);\n    }\n\n    @NotNull\n    public PsiClass getTarget() {\n        return target;\n    }\n\n    public void setTarget(@NotNull PsiClass target) {\n        this.target = target;\n    }\n\n    @NotNull\n    public Select getSelect() {\n        return select;\n    }\n\n    public void setSelect(@NotNull Select select) {\n        this.select = select;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/inspection/StatementNotExistsQuickFix.java",
    "content": "package com.wuzhizhan.mybatis.inspection;\n\nimport com.intellij.codeInspection.ProblemDescriptor;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiMethod;\nimport com.wuzhizhan.mybatis.generate.StatementGenerator;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class StatementNotExistsQuickFix extends GenericQuickFix {\n\n    private PsiMethod method;\n\n    public StatementNotExistsQuickFix(@NotNull PsiMethod method) {\n        this.method = method;\n    }\n\n    @NotNull\n    @Override\n    public String getName() {\n        return \"MybatisGenerator statement\";\n    }\n\n    @Override\n    public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {\n        StatementGenerator.applyGenerate(method);\n    }\n\n    @NotNull\n    public PsiMethod getMethod() {\n        return method;\n    }\n\n    public void setMethod(@NotNull PsiMethod method) {\n        this.method = method;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/intention/GenerateMapperChooser.java",
    "content": "package com.wuzhizhan.mybatis.intention;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.util.PsiTreeUtil;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class GenerateMapperChooser extends JavaFileIntentionChooser {\n\n    public static final JavaFileIntentionChooser INSTANCE = new GenerateMapperChooser();\n\n    @Override\n    public boolean isAvailable(@NotNull PsiElement element) {\n        if (isPositionOfInterfaceDeclaration(element)) {\n            PsiClass clazz = PsiTreeUtil.getParentOfType(element, PsiClass.class);\n            if (null != clazz) {\n                return !isTargetPresentInXml(clazz);\n            }\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/intention/GenerateMapperIntention.java",
    "content": "package com.wuzhizhan.mybatis.intention;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Collections2;\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Maps;\nimport com.intellij.codeInsight.hint.HintManager;\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.module.Module;\nimport com.intellij.openapi.module.ModuleUtil;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.openapi.util.io.FileUtil;\nimport com.intellij.openapi.vfs.VirtualFile;\nimport com.intellij.psi.*;\nimport com.intellij.psi.util.PsiTreeUtil;\nimport com.intellij.util.IncorrectOperationException;\nimport com.wuzhizhan.mybatis.service.EditorService;\nimport com.wuzhizhan.mybatis.template.MybatisFileTemplateDescriptorFactory;\nimport com.wuzhizhan.mybatis.ui.ClickableListener;\nimport com.wuzhizhan.mybatis.ui.ListSelectionListener;\nimport com.wuzhizhan.mybatis.ui.UiComponentFacade;\nimport com.wuzhizhan.mybatis.util.CollectionUtils;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.io.File;\nimport java.util.*;\n\n/**\n * @author yanglin\n */\npublic class GenerateMapperIntention extends GenericIntention {\n\n    public GenerateMapperIntention() {\n        super(GenerateMapperChooser.INSTANCE);\n    }\n\n    @NotNull\n    @Override\n    public String getText() {\n        return \"[Mybatis] MybatisGenerator mapper of xml\";\n    }\n\n    @Override\n    public boolean startInWriteAction() {\n        return false;\n    }\n\n    @Override\n    public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {\n        PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());\n        PsiClass clazz = PsiTreeUtil.getParentOfType(element, PsiClass.class);\n        Collection<PsiDirectory> directories = MapperUtils.findMapperDirectories(project);\n        if (CollectionUtils.isEmpty(directories)) {\n            handleChooseNewFolder(project, editor, clazz);\n        } else {\n            handleMutilDirectories(project, editor, clazz, directories);\n        }\n    }\n\n    private void handleMutilDirectories(Project project,\n                                        final Editor editor,\n                                        final PsiClass clazz,\n                                        Collection<PsiDirectory> directories) {\n        final Map<String, PsiDirectory> pathMap = getPathMap(directories);\n        final ArrayList<String> keys = Lists.newArrayList(pathMap.keySet());\n        ListSelectionListener popupListener = new ListSelectionListener() {\n            @Override\n            public void selected(int index) {\n                processGenerate(editor, clazz, pathMap.get(keys.get(index)));\n            }\n\n            @Override\n            public boolean isWriteAction() {\n                return true;\n            }\n        };\n        UiComponentFacade uiComponentFacade = UiComponentFacade.getInstance(project);\n        uiComponentFacade.showListPopupWithSingleClickable(\"Choose folder\",\n                popupListener,\n                \"Choose another\",\n                getChooseFolderListener(editor, clazz),\n                getPathTextForShown(project, keys, pathMap));\n    }\n\n    private ClickableListener getChooseFolderListener(final Editor editor, final PsiClass clazz) {\n        final Project project = clazz.getProject();\n        return new ClickableListener() {\n            @Override\n            public void clicked() {\n                handleChooseNewFolder(project, editor, clazz);\n            }\n\n            @Override\n            public boolean isWriteAction() {\n                return false;\n            }\n        };\n    }\n\n    private void handleChooseNewFolder(Project project, Editor editor, PsiClass clazz) {\n        UiComponentFacade uiComponentFacade = UiComponentFacade.getInstance(project);\n        VirtualFile baseDir = project.getBaseDir();\n        VirtualFile vf = uiComponentFacade.showSingleFolderSelectionDialog(\"Select target folder\", baseDir, baseDir);\n        if (null != vf) {\n            processGenerate(editor, clazz, PsiManager.getInstance(project).findDirectory(vf));\n        }\n    }\n\n    private String[] getPathTextForShown(Project project, List<String> paths, final Map<String, PsiDirectory> pathMap) {\n        Collections.sort(paths);\n        final String projectBasePath = project.getBasePath();\n        Collection<String> result = Lists.newArrayList(Collections2.transform(paths, new Function<String, String>() {\n            @Override\n            public String apply(String input) {\n                String relativePath = FileUtil.getRelativePath(projectBasePath, input, File.separatorChar);\n                Module module = ModuleUtil.findModuleForPsiElement(pathMap.get(input));\n                return null == module ? relativePath : (\"[\" + module.getName() + \"] \" + relativePath);\n            }\n        }));\n        return result.toArray(new String[result.size()]);\n    }\n\n    private Map<String, PsiDirectory> getPathMap(Collection<PsiDirectory> directories) {\n        Map<String, PsiDirectory> result = Maps.newHashMap();\n        for (PsiDirectory directory : directories) {\n            String presentableUrl = directory.getVirtualFile().getPresentableUrl();\n            if (presentableUrl != null) {\n                result.put(presentableUrl, directory);\n            }\n        }\n        return result;\n    }\n\n    private void processGenerate(Editor editor, PsiClass clazz, PsiDirectory directory) {\n        if (null == directory) {\n            return;\n        }\n        if (!directory.isWritable()) {\n            HintManager.getInstance().showErrorHint(editor, \"Target directory is not writable\");\n            return;\n        }\n        try {\n            Properties properties = new Properties();\n            properties.setProperty(\"NAMESPACE\", clazz.getQualifiedName());\n            PsiElement psiFile = MapperUtils.createMapperFromFileTemplate(MybatisFileTemplateDescriptorFactory.MYBATIS_MAPPER_XML_TEMPLATE,\n                    clazz.getName(), directory, properties);\n            EditorService.getInstance(clazz.getProject()).scrollTo(psiFile, 0);\n        } catch (Exception e) {\n            HintManager.getInstance().showErrorHint(editor, \"Failed: \" + e.getCause());\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/intention/GenerateParamAnnotationIntention.java",
    "content": "package com.wuzhizhan.mybatis.intention;\n\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiFile;\nimport com.intellij.psi.PsiMethod;\nimport com.intellij.psi.PsiParameter;\nimport com.intellij.psi.util.PsiTreeUtil;\nimport com.intellij.util.IncorrectOperationException;\nimport com.wuzhizhan.mybatis.service.AnnotationService;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class GenerateParamAnnotationIntention extends GenericIntention {\n\n    public GenerateParamAnnotationIntention() {\n        super(GenerateParamChooser.INSTANCE);\n    }\n\n    @NotNull\n    @Override\n    public String getText() {\n        return \"[Mybatis] MybatisGenerator @Param\";\n    }\n\n    @Override\n    public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {\n        PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());\n        PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class);\n        AnnotationService annotationService = AnnotationService.getInstance(project);\n        if (null != parameter) {\n            annotationService.addAnnotationWithParameterName(parameter);\n        } else {\n            PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class);\n            if (null != method) {\n                annotationService.addAnnotationWithParameterNameForMethodParameters(method);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/intention/GenerateParamChooser.java",
    "content": "package com.wuzhizhan.mybatis.intention;\n\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiMethod;\nimport com.intellij.psi.PsiParameter;\nimport com.intellij.psi.util.PsiTreeUtil;\nimport com.wuzhizhan.mybatis.annotation.Annotation;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class GenerateParamChooser extends JavaFileIntentionChooser {\n\n    public static final JavaFileIntentionChooser INSTANCE = new GenerateParamChooser();\n\n    @Override\n    public boolean isAvailable(@NotNull PsiElement element) {\n        PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class);\n        PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class);\n        return (null != parameter && !JavaUtils.isAnnotationPresent(parameter, Annotation.PARAM)) ||\n                (null != method && !JavaUtils.isAllParameterWithAnnotation(method, Annotation.PARAM));\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/intention/GenerateStatementChooser.java",
    "content": "package com.wuzhizhan.mybatis.intention;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiMethod;\nimport com.intellij.psi.util.PsiTreeUtil;\nimport com.wuzhizhan.mybatis.annotation.Annotation;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class GenerateStatementChooser extends JavaFileIntentionChooser {\n\n    public static final JavaFileIntentionChooser INSTANCE = new GenerateStatementChooser();\n\n    @Override\n    public boolean isAvailable(@NotNull PsiElement element) {\n        if (!isPositionOfMethodDeclaration(element)) {\n            return false;\n        }\n        PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class);\n        PsiClass clazz = PsiTreeUtil.getParentOfType(element, PsiClass.class);\n        return null != method && null != clazz &&\n                !JavaUtils.isAnyAnnotationPresent(method, Annotation.STATEMENT_SYMMETRIES) &&\n                !isTargetPresentInXml(method) &&\n                isTargetPresentInXml(clazz);\n    }\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/intention/GenerateStatementIntention.java",
    "content": "package com.wuzhizhan.mybatis.intention;\n\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiFile;\nimport com.intellij.psi.PsiMethod;\nimport com.intellij.psi.util.PsiTreeUtil;\nimport com.intellij.util.IncorrectOperationException;\nimport com.wuzhizhan.mybatis.generate.StatementGenerator;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class GenerateStatementIntention extends GenericIntention {\n\n    public GenerateStatementIntention() {\n        super(GenerateStatementChooser.INSTANCE);\n    }\n\n    @NotNull\n    @Override\n    public String getText() {\n        return \"[Mybatis] MybatisGenerator new statement\";\n    }\n\n    @Override\n    public void invoke(@NotNull final Project project, Editor editor, PsiFile file) throws IncorrectOperationException {\n        PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());\n        StatementGenerator.applyGenerate(PsiTreeUtil.getParentOfType(element, PsiMethod.class));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/intention/GenericIntention.java",
    "content": "package com.wuzhizhan.mybatis.intention;\n\nimport com.intellij.codeInsight.intention.IntentionAction;\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiFile;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic abstract class GenericIntention implements IntentionAction {\n\n    protected IntentionChooser chooser;\n\n    public GenericIntention(@NotNull IntentionChooser chooser) {\n        this.chooser = chooser;\n    }\n\n    @NotNull\n    @Override\n    public String getFamilyName() {\n        return getText();\n    }\n\n    @Override\n    public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {\n        return chooser.isAvailable(project, editor, file);\n    }\n\n    @Override\n    public boolean startInWriteAction() {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/intention/IntentionChooser.java",
    "content": "package com.wuzhizhan.mybatis.intention;\n\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiFile;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic interface IntentionChooser {\n\n    public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file);\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/intention/JavaFileIntentionChooser.java",
    "content": "package com.wuzhizhan.mybatis.intention;\n\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.*;\nimport com.wuzhizhan.mybatis.service.JavaService;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic abstract class JavaFileIntentionChooser implements IntentionChooser {\n\n    @Override\n    public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {\n        if (!(file instanceof PsiJavaFile))\n            return false;\n        PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());\n        return null != element && JavaUtils.isElementWithinInterface(element) && isAvailable(element);\n    }\n\n    public abstract boolean isAvailable(@NotNull PsiElement element);\n\n    public boolean isPositionOfParameterDeclaration(@NotNull PsiElement element) {\n        return element.getParent() instanceof PsiParameter;\n    }\n\n    public boolean isPositionOfMethodDeclaration(@NotNull PsiElement element) {\n        return element.getParent() instanceof PsiMethod;\n    }\n\n    public boolean isPositionOfInterfaceDeclaration(@NotNull PsiElement element) {\n        return element.getParent() instanceof PsiClass;\n    }\n\n    public boolean isTargetPresentInXml(@NotNull PsiElement element) {\n        return JavaService.getInstance(element.getProject()).findWithFindFirstProcessor(element).isPresent();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/locator/LocateStrategy.java",
    "content": "package com.wuzhizhan.mybatis.locator;\n\nimport com.intellij.psi.PsiClass;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic abstract class LocateStrategy {\n\n    public abstract boolean apply(@NotNull PsiClass clazz);\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/locator/MapperLocator.java",
    "content": "package com.wuzhizhan.mybatis.locator;\n\nimport com.intellij.openapi.components.ServiceManager;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiMethod;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\n/**\n * @author yanglin\n */\npublic class MapperLocator {\n\n    public static LocateStrategy dfltLocateStrategy = new PackageLocateStrategy();\n\n    public static MapperLocator getInstance(@NotNull Project project) {\n        return ServiceManager.getService(project, MapperLocator.class);\n    }\n\n    public boolean process(@Nullable PsiMethod method) {\n        return null != method && process(method.getContainingClass());\n    }\n\n    public boolean process(@Nullable PsiClass clazz) {\n        return null != clazz && JavaUtils.isElementWithinInterface(clazz) && dfltLocateStrategy.apply(clazz);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/locator/MapperXmlPackageProvider.java",
    "content": "package com.wuzhizhan.mybatis.locator;\n\nimport com.google.common.collect.Sets;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.*;\nimport com.intellij.psi.search.GlobalSearchScope;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic class MapperXmlPackageProvider extends PackageProvider {\n\n    @NotNull\n    @Override\n    public Set<PsiPackage> getPackages(@NotNull Project project) {\n        HashSet<PsiPackage> res = Sets.newHashSet();\n        Collection<Mapper> mappers = MapperUtils.findMappers(project);\n        JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);\n        for (Mapper mapper : mappers) {\n            String namespace = MapperUtils.getNamespace(mapper);\n            PsiClass clazz = javaPsiFacade.findClass(namespace, GlobalSearchScope.allScope(project));\n            if (null != clazz) {\n                PsiFile file = clazz.getContainingFile();\n                if (file instanceof PsiJavaFile) {\n                    String packageName = ((PsiJavaFile) file).getPackageName();\n                    PsiPackage pkg = javaPsiFacade.findPackage(packageName);\n                    if (null != pkg) {\n                        res.add(pkg);\n                    }\n                }\n            }\n        }\n        return res;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/locator/PackageLocateStrategy.java",
    "content": "package com.wuzhizhan.mybatis.locator;\n\nimport com.intellij.psi.JavaPsiFacade;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiJavaFile;\nimport com.intellij.psi.PsiPackage;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class PackageLocateStrategy extends LocateStrategy {\n\n    private PackageProvider provider = new MapperXmlPackageProvider();\n\n    @Override\n    public boolean apply(@NotNull PsiClass clazz) {\n        String packageName = ((PsiJavaFile) clazz.getContainingFile()).getPackageName();\n        PsiPackage pkg = JavaPsiFacade.getInstance(clazz.getProject()).findPackage(packageName);\n        for (PsiPackage tmp : provider.getPackages(clazz.getProject())) {\n            if (tmp.equals(pkg)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/locator/PackageProvider.java",
    "content": "package com.wuzhizhan.mybatis.locator;\n\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiPackage;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic abstract class PackageProvider {\n\n    @NotNull\n    public abstract Set<PsiPackage> getPackages(@NotNull Project project);\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/provider/InjectionLineMarkerProvider.java",
    "content": "package com.wuzhizhan.mybatis.provider;\n\nimport com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;\nimport com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;\nimport com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;\nimport com.intellij.openapi.editor.markup.GutterIconRenderer;\nimport com.intellij.psi.*;\nimport com.intellij.psi.impl.source.PsiClassReferenceType;\nimport com.wuzhizhan.mybatis.annotation.Annotation;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.util.Icons;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.Collection;\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic class InjectionLineMarkerProvider extends RelatedItemLineMarkerProvider {\n\n    @Override\n    protected void collectNavigationMarkers(@NotNull PsiElement element, @NotNull Collection<? super RelatedItemLineMarkerInfo> result) {\n        if (!(element instanceof PsiField)) return;\n        PsiField field = (PsiField) element;\n        if (!isTargetField(field)) return;\n\n        PsiType type = field.getType();\n        if (!(type instanceof PsiClassReferenceType)) return;\n\n        Optional<PsiClass> clazz = JavaUtils.findClazz(element.getProject(), type.getCanonicalText());\n        if (!clazz.isPresent()) return;\n\n        PsiClass psiClass = clazz.get();\n        Optional<Mapper> mapper = MapperUtils.findFirstMapper(element.getProject(), psiClass);\n        if (!mapper.isPresent()) return;\n\n        NavigationGutterIconBuilder<PsiElement> builder =\n                NavigationGutterIconBuilder.create(Icons.SPRING_INJECTION_ICON)\n                        .setAlignment(GutterIconRenderer.Alignment.CENTER)\n                        .setTarget(psiClass)\n                        .setTooltipTitle(\"Data access object found - \" + psiClass.getQualifiedName());\n        result.add(builder.createLineMarkerInfo(field.getNameIdentifier()));\n    }\n\n    private boolean isTargetField(PsiField field) {\n        if (JavaUtils.isAnnotationPresent(field, Annotation.AUTOWIRED)) {\n            return true;\n        }\n        Optional<PsiAnnotation> resourceAnno = JavaUtils.getPsiAnnotation(field, Annotation.RESOURCE);\n        if (resourceAnno.isPresent()) {\n            PsiAnnotationMemberValue nameValue = resourceAnno.get().findAttributeValue(\"name\");\n            String name = nameValue.getText().replaceAll(\"\\\"\", \"\");\n            return StringUtils.isBlank(name) || name.equals(field.getName());\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/provider/MapperLineMarkerProvider.java",
    "content": "package com.wuzhizhan.mybatis.provider;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Collections2;\nimport com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;\nimport com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;\nimport com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;\nimport com.intellij.openapi.editor.markup.GutterIconRenderer;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiNameIdentifierOwner;\nimport com.intellij.psi.xml.XmlTag;\nimport com.intellij.util.CommonProcessors;\nimport com.intellij.util.xml.DomElement;\nimport com.wuzhizhan.mybatis.dom.model.IdDomElement;\nimport com.wuzhizhan.mybatis.service.JavaService;\nimport com.wuzhizhan.mybatis.util.Icons;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.Collection;\n\n/**\n * @author yanglin\n */\npublic class MapperLineMarkerProvider extends RelatedItemLineMarkerProvider {\n\n    private static final Function<DomElement, XmlTag> FUN = new Function<DomElement, XmlTag>() {\n        @Override\n        public XmlTag apply(DomElement domElement) {\n            return domElement.getXmlTag();\n        }\n    };\n\n    @Override\n    protected void collectNavigationMarkers(@NotNull PsiElement element, @NotNull Collection<? super RelatedItemLineMarkerInfo> result) {\n        if (element instanceof PsiNameIdentifierOwner && JavaUtils.isElementWithinInterface(element)) {\n            CommonProcessors.CollectProcessor<IdDomElement> processor = new CommonProcessors.CollectProcessor<IdDomElement>();\n            JavaService.getInstance(element.getProject()).process(element, processor);\n            Collection<IdDomElement> results = processor.getResults();\n            if (!results.isEmpty()) {\n                NavigationGutterIconBuilder<PsiElement> builder =\n                        NavigationGutterIconBuilder.create(Icons.MAPPER_LINE_MARKER_ICON)\n                                .setAlignment(GutterIconRenderer.Alignment.CENTER)\n                                .setTargets(Collections2.transform(results, FUN))\n                                .setTooltipTitle(\"Navigation to target in mapper xml\");\n                result.add(builder.createLineMarkerInfo(((PsiNameIdentifierOwner) element).getNameIdentifier()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/provider/MarkerProviderAdaptor.java",
    "content": "package com.wuzhizhan.mybatis.provider;\n\nimport com.intellij.codeInsight.daemon.LineMarkerInfo;\nimport com.intellij.codeInsight.daemon.LineMarkerProvider;\nimport com.intellij.psi.PsiElement;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * @author yanglin\n */\npublic abstract class MarkerProviderAdaptor implements LineMarkerProvider {\n\n    @Override\n    public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {\n\n    }\n\n    @Nullable\n    @Override\n    public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/provider/SimpleLineMarkerProvider.java",
    "content": "package com.wuzhizhan.mybatis.provider;\n\nimport com.intellij.codeHighlighting.Pass;\nimport com.intellij.codeInsight.daemon.GutterIconNavigationHandler;\nimport com.intellij.codeInsight.daemon.LineMarkerInfo;\nimport com.intellij.openapi.editor.markup.GutterIconRenderer;\nimport com.intellij.pom.Navigatable;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.util.Function;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport javax.swing.*;\nimport java.awt.event.MouseEvent;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic abstract class SimpleLineMarkerProvider<F extends PsiElement, T> extends MarkerProviderAdaptor {\n\n    @Override\n    public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Nullable\n    @Override\n    public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {\n        if (!isTheElement(element)) return null;\n\n        Optional<T> processResult = apply((F) element);\n        return processResult.isPresent() ? new LineMarkerInfo<F>(\n                (F) element,\n                element.getTextRange(),\n                getIcon(),\n                getTooltipProvider(processResult.get()),\n                getNavigationHandler(processResult.get()),\n                GutterIconRenderer.Alignment.CENTER\n        ) : null;\n    }\n\n    private Function<F, String> getTooltipProvider(final T target) {\n        return new Function<F, String>() {\n            @Override\n            public String fun(F from) {\n                return getTooltip(from, target);\n            }\n        };\n    }\n\n    private GutterIconNavigationHandler<F> getNavigationHandler(final T target) {\n        return new GutterIconNavigationHandler<F>() {\n            @Override\n            public void navigate(MouseEvent e, F from) {\n                getNavigatable(from, target).navigate(true);\n            }\n        };\n    }\n\n    public abstract boolean isTheElement(@NotNull PsiElement element);\n\n    @NotNull\n    public abstract Optional<T> apply(@NotNull F from);\n\n    @NotNull\n    public abstract Navigatable getNavigatable(@NotNull F from, @NotNull T target);\n\n    @NotNull\n    public abstract String getTooltip(@NotNull F from, @NotNull T target);\n\n    @NotNull\n    public abstract Icon getIcon();\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/provider/StatementLineMarkerProvider.java",
    "content": "package com.wuzhizhan.mybatis.provider;\n\nimport com.google.common.collect.ImmutableList;\nimport com.intellij.pom.Navigatable;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiMethod;\nimport com.intellij.psi.xml.XmlTag;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.DomUtil;\nimport com.wuzhizhan.mybatis.dom.model.*;\nimport com.wuzhizhan.mybatis.util.Icons;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.jetbrains.annotations.NotNull;\n\nimport javax.swing.*;\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic class StatementLineMarkerProvider extends SimpleLineMarkerProvider<XmlTag, PsiMethod> {\n\n    private static final ImmutableList<Class<? extends GroupTwo>> TARGET_TYPES = ImmutableList.of(\n            Select.class,\n            Update.class,\n            Insert.class,\n            Delete.class\n    );\n\n    @Override\n    public boolean isTheElement(@NotNull PsiElement element) {\n        return element instanceof XmlTag\n                && MapperUtils.isElementWithinMybatisFile(element)\n                && isTargetType(element);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @NotNull\n    @Override\n    public Optional<PsiMethod> apply(@NotNull XmlTag from) {\n        DomElement domElement = DomUtil.getDomElement(from);\n        return null == domElement ? Optional.empty() : JavaUtils.findMethod(from.getProject(), (IdDomElement) domElement);\n    }\n\n    private boolean isTargetType(PsiElement element) {\n        DomElement domElement = DomUtil.getDomElement(element);\n        for (Class<?> clazz : TARGET_TYPES) {\n            if (clazz.isInstance(domElement))\n                return true;\n        }\n        return false;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @NotNull\n    @Override\n    public Navigatable getNavigatable(@NotNull XmlTag from, @NotNull PsiMethod target) {\n        return (Navigatable) target.getNavigationElement();\n    }\n\n    @NotNull\n    @Override\n    public String getTooltip(@NotNull XmlTag from, @NotNull PsiMethod target) {\n        return \"Data access object found - \" + target.getContainingClass().getQualifiedName();\n    }\n\n    @NotNull\n    @Override\n    public Icon getIcon() {\n        return Icons.STATEMENT_LINE_MARKER_ICON;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/refactoring/MapperRefactoringProvider.java",
    "content": "package com.wuzhizhan.mybatis.refactoring;\n\nimport com.intellij.openapi.application.ApplicationManager;\nimport com.intellij.openapi.vfs.VirtualFile;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.refactoring.listeners.RefactoringElementListener;\nimport com.intellij.refactoring.listeners.RefactoringElementListenerProvider;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.io.IOException;\nimport java.util.Collection;\n\n/**\n * @author yanglin\n */\npublic class MapperRefactoringProvider implements RefactoringElementListenerProvider {\n\n    @Nullable\n    @Override\n    public RefactoringElementListener getListener(final PsiElement element) {\n        if (!(element instanceof PsiClass)) return null;\n        return new RefactoringElementListener() {\n            @Override\n            public void elementMoved(@NotNull PsiElement newElement) {\n            }\n\n            @Override\n            public void elementRenamed(@NotNull final PsiElement newElement) {\n                if (newElement instanceof PsiClass) {\n                    ApplicationManager.getApplication().runWriteAction(new Runnable() {\n                        @Override\n                        public void run() {\n                            renameMapperXml((PsiClass) element, (PsiClass) newElement);\n                        }\n                    });\n                }\n            }\n        };\n    }\n\n    private void renameMapperXml(@NotNull final PsiClass oldClazz, @NotNull final PsiClass newClazz) {\n        Collection<Mapper> mappers = MapperUtils.findMappers(oldClazz.getProject(), oldClazz);\n        try {\n            for (Mapper mapper : mappers) {\n                VirtualFile vf = mapper.getXmlTag().getOriginalElement().getContainingFile().getVirtualFile();\n                if (null != vf) {\n                    vf.rename(MapperRefactoringProvider.this, newClazz.getName() + \".\" + vf.getExtension());\n                }\n            }\n        } catch (IOException e) {\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/reference/ContextPsiFieldReference.java",
    "content": "package com.wuzhizhan.mybatis.reference;\n\nimport com.intellij.openapi.util.TextRange;\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiReference;\nimport com.intellij.psi.PsiReferenceBase;\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport com.wuzhizhan.mybatis.dom.MapperBacktrackingUtils;\nimport com.wuzhizhan.mybatis.service.JavaService;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport com.wuzhizhan.mybatis.util.MybatisConstants;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic class ContextPsiFieldReference extends PsiReferenceBase<XmlAttributeValue> {\n\n    protected ContextReferenceSetResolver resolver;\n\n    protected int index;\n\n    public ContextPsiFieldReference(XmlAttributeValue element, TextRange range, int index) {\n        super(element, range, false);\n        this.index = index;\n        resolver = ReferenceSetResolverFactory.createPsiFieldResolver(element);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Nullable\n    @Override\n    public PsiElement resolve() {\n        Optional<PsiElement> resolved = resolver.resolve(index);\n        return resolved.orElse(null);\n    }\n\n    @NotNull\n    @Override\n    public Object[] getVariants() {\n        Optional<PsiClass> clazz = getTargetClazz();\n        return clazz.isPresent() ? JavaUtils.findSettablePsiFields(clazz.get()) : PsiReference.EMPTY_ARRAY;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private Optional<PsiClass> getTargetClazz() {\n        if (getElement().getValue().contains(MybatisConstants.DOT_SEPARATOR)) {\n            int ind = 0 == index ? 0 : index - 1;\n            Optional<PsiElement> resolved = resolver.resolve(ind);\n            if (resolved.isPresent()) {\n                return JavaService.getInstance(myElement.getProject()).getReferenceClazzOfPsiField(resolved.get());\n            }\n        } else {\n            return MapperBacktrackingUtils.getPropertyClazz(myElement);\n        }\n        return Optional.empty();\n    }\n\n    public ContextReferenceSetResolver getResolver() {\n        return resolver;\n    }\n\n    public void setResolver(ContextReferenceSetResolver resolver) {\n        this.resolver = resolver;\n    }\n\n    public int getIndex() {\n        return index;\n    }\n\n    public void setIndex(int index) {\n        this.index = index;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/reference/ContextReferenceSetResolver.java",
    "content": "package com.wuzhizhan.mybatis.reference;\n\nimport com.google.common.base.Splitter;\nimport com.google.common.collect.Iterables;\nimport com.google.common.collect.Lists;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiElement;\nimport com.wuzhizhan.mybatis.util.MybatisConstants;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic abstract class ContextReferenceSetResolver<F extends PsiElement, K extends PsiElement> {\n\n    private static final Splitter SPLITTER = Splitter.on(MybatisConstants.DOT_SEPARATOR);\n\n    protected Project project;\n\n    protected F element;\n\n    protected List<String> texts;\n\n    protected ContextReferenceSetResolver(@NotNull F element) {\n        this.element = element;\n        this.project = element.getProject();\n        this.texts = Lists.newArrayList(SPLITTER.split(getText()));\n    }\n\n    @NotNull\n    public final Optional<? extends PsiElement> resolve(int index) {\n        Optional<K> startElement = getStartElement();\n        return startElement.isPresent() ? (texts.size() > 1 ? parseNext(startElement, texts, index) : startElement) : Optional.empty();\n    }\n\n    private Optional<K> parseNext(Optional<K> current, List<String> texts, int index) {\n        int ind = 1;\n        while (current.isPresent() && ind <= index) {\n            String text = texts.get(ind);\n            if (text.contains(\" \")) {\n                return Optional.empty();\n            }\n            current = resolve(current.get(), text);\n            ind++;\n        }\n        return current;\n    }\n\n    public Optional<K> getStartElement() {\n        return getStartElement(Iterables.getFirst(texts, null));\n    }\n\n    @NotNull\n    public abstract Optional<K> getStartElement(@Nullable String firstText);\n\n    @NotNull\n    public abstract String getText();\n\n    @NotNull\n    public abstract Optional<K> resolve(@NotNull K current, @NotNull String text);\n\n    public F getElement() {\n        return element;\n    }\n\n    public void setElement(F element) {\n        this.element = element;\n    }\n\n    public Project getProject() {\n        return project;\n    }\n\n    public void setProject(Project project) {\n        this.project = project;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/reference/PsiFieldReferenceSetResolver.java",
    "content": "package com.wuzhizhan.mybatis.reference;\n\nimport com.intellij.psi.PsiClass;\nimport com.intellij.psi.PsiField;\nimport com.intellij.psi.PsiType;\nimport com.intellij.psi.impl.source.PsiClassReferenceType;\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport com.wuzhizhan.mybatis.dom.MapperBacktrackingUtils;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic class PsiFieldReferenceSetResolver extends ContextReferenceSetResolver<XmlAttributeValue, PsiField> {\n\n    protected PsiFieldReferenceSetResolver(XmlAttributeValue from) {\n        super(from);\n    }\n\n    @NotNull\n    @Override\n    public String getText() {\n        return getElement().getValue();\n    }\n\n    @NotNull\n    @Override\n    public Optional<PsiField> resolve(@NotNull PsiField current, @NotNull String text) {\n        PsiType type = current.getType();\n        if (type instanceof PsiClassReferenceType && !((PsiClassReferenceType) type).hasParameters()) {\n            PsiClass clazz = ((PsiClassReferenceType) type).resolve();\n            if (null != clazz) {\n                return JavaUtils.findSettablePsiField(clazz, text);\n            }\n        }\n        return Optional.empty();\n    }\n\n    @NotNull\n    @Override\n    public Optional<PsiField> getStartElement(@Nullable String firstText) {\n        Optional<PsiClass> clazz = MapperBacktrackingUtils.getPropertyClazz(getElement());\n        return clazz.flatMap(psiClass -> JavaUtils.findSettablePsiField(psiClass, firstText));\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/reference/ReferenceSetResolverFactory.java",
    "content": "package com.wuzhizhan.mybatis.reference;\n\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic final class ReferenceSetResolverFactory {\n\n    private ReferenceSetResolverFactory() {\n        throw new UnsupportedOperationException();\n    }\n\n    public static <F extends XmlAttributeValue> ContextReferenceSetResolver createPsiFieldResolver(@NotNull F target) {\n        return new PsiFieldReferenceSetResolver(target);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/reference/ResultPropertyReferenceSet.java",
    "content": "package com.wuzhizhan.mybatis.reference;\n\nimport com.intellij.openapi.util.TextRange;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiReference;\nimport com.intellij.psi.util.ReferenceSetBase;\nimport com.intellij.psi.xml.XmlAttributeValue;\nimport org.jetbrains.annotations.NonNls;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\n/**\n * @author yanglin\n */\npublic class ResultPropertyReferenceSet extends ReferenceSetBase<PsiReference> {\n\n    public ResultPropertyReferenceSet(String text, @NotNull PsiElement element, int offset) {\n        super(text, element, offset, DOT_SEPARATOR);\n    }\n\n    @Nullable\n    @NonNls\n    @Override\n    protected PsiReference createReference(TextRange range, int index) {\n        XmlAttributeValue element = (XmlAttributeValue) getElement();\n        return null == element ? null : new ContextPsiFieldReference(element, range, index);\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/service/AnnotationService.java",
    "content": "package com.wuzhizhan.mybatis.service;\n\nimport com.intellij.openapi.components.ServiceManager;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.*;\nimport com.intellij.psi.codeStyle.JavaCodeStyleManager;\nimport com.wuzhizhan.mybatis.annotation.Annotation;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class AnnotationService {\n\n    private Project project;\n\n    public AnnotationService(Project project) {\n        this.project = project;\n    }\n\n    public static AnnotationService getInstance(@NotNull Project project) {\n        return ServiceManager.getService(project, AnnotationService.class);\n    }\n\n    public void addAnnotation(@NotNull PsiModifierListOwner parameter, @NotNull Annotation annotation) {\n        PsiModifierList modifierList = parameter.getModifierList();\n        if (JavaUtils.isAnnotationPresent(parameter, annotation) || null == modifierList) {\n            return;\n        }\n        JavaService.getInstance(parameter.getProject()).importClazz((PsiJavaFile) parameter.getContainingFile(), annotation.getQualifiedName());\n\n        PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();\n        PsiAnnotation psiAnnotation = elementFactory.createAnnotationFromText(annotation.toString(), parameter);\n        modifierList.add(psiAnnotation);\n        JavaCodeStyleManager.getInstance(project).shortenClassReferences(psiAnnotation.getParent());\n    }\n\n    public void addAnnotationWithParameterNameForMethodParameters(@NotNull PsiMethod method) {\n        PsiParameterList parameterList = method.getParameterList();\n        if (null == parameterList) {\n            return;\n        }\n        PsiParameter[] parameters = parameterList.getParameters();\n        for (PsiParameter param : parameters) {\n            addAnnotationWithParameterName(param);\n        }\n    }\n\n    public void addAnnotationWithParameterName(@NotNull PsiParameter parameter) {\n        String name = parameter.getName();\n        if (null != name) {\n            AnnotationService.getInstance(parameter.getProject()).addAnnotation(parameter, Annotation.PARAM.withValue(new Annotation.StringValue(name)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/service/EditorService.java",
    "content": "package com.wuzhizhan.mybatis.service;\n\nimport com.intellij.codeInsight.navigation.NavigationUtil;\nimport com.intellij.formatting.FormatTextRanges;\nimport com.intellij.openapi.components.ServiceManager;\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.editor.ScrollType;\nimport com.intellij.openapi.fileEditor.FileEditorManager;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiElement;\nimport com.intellij.psi.PsiFile;\nimport com.intellij.psi.codeStyle.CodeStyleSettingsManager;\nimport com.intellij.psi.impl.source.codeStyle.CodeFormatterFacade;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author yanglin\n */\npublic class EditorService {\n\n    private Project project;\n\n    private FileEditorManager fileEditorManager;\n\n    private CodeFormatterFacade codeFormatterFacade;\n\n    public EditorService(Project project) {\n        this.project = project;\n        this.fileEditorManager = FileEditorManager.getInstance(project);\n    }\n\n    public static EditorService getInstance(@NotNull Project project) {\n        return ServiceManager.getService(project, EditorService.class);\n    }\n\n    public void format(@NotNull PsiFile file, @NotNull PsiElement element) {\n        this.codeFormatterFacade = new CodeFormatterFacade(CodeStyleSettingsManager.getSettings(element.getProject()), element.getLanguage());\n        codeFormatterFacade.processText(file, new FormatTextRanges(element.getTextRange(), true), true);\n    }\n\n    public void scrollTo(@NotNull PsiElement element, int offset) {\n        NavigationUtil.activateFileWithPsiElement(element, true);\n        Editor editor = fileEditorManager.getSelectedTextEditor();\n        if (null != editor) {\n            editor.getCaretModel().moveToOffset(offset);\n            editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/service/JavaService.java",
    "content": "package com.wuzhizhan.mybatis.service;\n\nimport com.intellij.openapi.components.ServiceManager;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.*;\nimport com.intellij.psi.impl.source.PsiClassReferenceType;\nimport com.intellij.util.CommonProcessors;\nimport com.intellij.util.Processor;\nimport com.intellij.util.xml.DomElement;\nimport com.wuzhizhan.mybatis.dom.model.IdDomElement;\nimport com.wuzhizhan.mybatis.dom.model.Mapper;\nimport com.wuzhizhan.mybatis.util.JavaUtils;\nimport com.wuzhizhan.mybatis.util.MapperUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic class JavaService {\n\n    private Project project;\n\n    private JavaPsiFacade javaPsiFacade;\n\n    private EditorService editorService;\n\n    public JavaService(Project project) {\n        this.project = project;\n        this.javaPsiFacade = JavaPsiFacade.getInstance(project);\n        this.editorService = EditorService.getInstance(project);\n    }\n\n    public static JavaService getInstance(@NotNull Project project) {\n        return ServiceManager.getService(project, JavaService.class);\n    }\n\n    public Optional<PsiClass> getReferenceClazzOfPsiField(@NotNull PsiElement field) {\n        if (!(field instanceof PsiField)) {\n            return Optional.empty();\n        }\n        PsiType type = ((PsiField) field).getType();\n        return type instanceof PsiClassReferenceType ? Optional.ofNullable(((PsiClassReferenceType) type).resolve()) : Optional.empty();\n    }\n\n    public Optional<DomElement> findStatement(@Nullable PsiMethod method) {\n        CommonProcessors.FindFirstProcessor<DomElement> processor = new CommonProcessors.FindFirstProcessor<DomElement>();\n        process(method, processor);\n        return processor.isFound() ? Optional.ofNullable(processor.getFoundValue()) : Optional.empty();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void process(@NotNull PsiMethod psiMethod, @NotNull Processor<IdDomElement> processor) {\n        PsiClass psiClass = psiMethod.getContainingClass();\n        if (null == psiClass) return;\n        String id = psiClass.getQualifiedName() + \".\" + psiMethod.getName();\n        for (Mapper mapper : MapperUtils.findMappers(psiMethod.getProject())) {\n            for (IdDomElement idDomElement : mapper.getDaoElements()) {\n                if (MapperUtils.getIdSignature(idDomElement).equals(id)) {\n                    processor.process(idDomElement);\n                }\n            }\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void process(@NotNull PsiClass clazz, @NotNull Processor<Mapper> processor) {\n        String ns = clazz.getQualifiedName();\n        for (Mapper mapper : MapperUtils.findMappers(clazz.getProject())) {\n            if (MapperUtils.getNamespace(mapper).equals(ns)) {\n                processor.process(mapper);\n            }\n        }\n    }\n\n    public void process(@NotNull PsiElement target, @NotNull Processor processor) {\n        if (target instanceof PsiMethod) {\n            process((PsiMethod) target, processor);\n        } else if (target instanceof PsiClass) {\n            process((PsiClass) target, processor);\n        }\n    }\n\n    public <T> Optional<T> findWithFindFirstProcessor(@NotNull PsiElement target) {\n        CommonProcessors.FindFirstProcessor<T> processor = new CommonProcessors.FindFirstProcessor<T>();\n        process(target, processor);\n        return Optional.ofNullable(processor.getFoundValue());\n    }\n\n    public void importClazz(PsiJavaFile file, String clazzName) {\n        if (!JavaUtils.hasImportClazz(file, clazzName)) {\n            Optional<PsiClass> clazz = JavaUtils.findClazz(project, clazzName);\n            PsiImportList importList = file.getImportList();\n            if (clazz.isPresent() && null != importList) {\n                PsiElementFactory elementFactory = javaPsiFacade.getElementFactory();\n                PsiImportStatement statement = elementFactory.createImportStatement(clazz.get());\n                importList.add(statement);\n                editorService.format(file, statement);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/service/TableInfoService.java",
    "content": "package com.wuzhizhan.mybatis.service;\n\nimport com.intellij.openapi.components.ServiceManager;\nimport com.intellij.openapi.project.Project;\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * 日期 2018-11-30\n *\n * @author 吴志展\n */\npublic class TableInfoService {\n    public static TableInfoService getInstance(@NotNull Project project) {\n        return ServiceManager.getService(project, TableInfoService.class);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/setting/MybatisConfigurable.java",
    "content": "package com.wuzhizhan.mybatis.setting;\n\nimport com.google.common.base.Joiner;\nimport com.google.common.base.Splitter;\nimport com.google.common.collect.Sets;\nimport com.intellij.openapi.options.ConfigurationException;\nimport com.intellij.openapi.options.SearchableConfigurable;\nimport com.wuzhizhan.mybatis.generate.GenerateModel;\nimport org.jetbrains.annotations.Nls;\nimport org.jetbrains.annotations.Nullable;\n\nimport javax.swing.*;\n\nimport static com.wuzhizhan.mybatis.generate.StatementGenerator.*;\n\n/**\n * @author yanglin\n */\npublic class MybatisConfigurable implements SearchableConfigurable {\n\n    private MybatisSetting mybatisSetting;\n\n    private MybatisSettingForm mybatisSettingForm;\n\n    private String separator = \";\";\n\n    private Splitter splitter = Splitter.on(separator).omitEmptyStrings().trimResults();\n\n    private Joiner joiner = Joiner.on(separator);\n\n    public MybatisConfigurable() {\n        mybatisSetting = MybatisSetting.getInstance();\n    }\n\n    @Override\n    public String getId() {\n        return \"Mybatis\";\n    }\n\n    @Override\n    public Runnable enableSearch(String option) {\n        return null;\n    }\n\n    @Nls\n    @Override\n    public String getDisplayName() {\n        return \"Free Mybatis\";\n    }\n\n    @Nullable\n    @Override\n    public String getHelpTopic() {\n        return getId();\n    }\n\n    @Nullable\n    @Override\n    public JComponent createComponent() {\n        if (null == mybatisSettingForm) {\n            this.mybatisSettingForm = new MybatisSettingForm();\n        }\n        return mybatisSettingForm.mainPanel;\n    }\n\n    @Override\n    public boolean isModified() {\n        return mybatisSetting.getStatementGenerateModel().getIdentifier() != mybatisSettingForm.modelComboBox.getSelectedIndex()\n                || !joiner.join(INSERT_GENERATOR.getPatterns()).equals(mybatisSettingForm.insertPatternTextField.getText())\n                || !joiner.join(DELETE_GENERATOR.getPatterns()).equals(mybatisSettingForm.deletePatternTextField.getText())\n                || !joiner.join(UPDATE_GENERATOR.getPatterns()).equals(mybatisSettingForm.updatePatternTextField.getText())\n                || !joiner.join(SELECT_GENERATOR.getPatterns()).equals(mybatisSettingForm.selectPatternTextField.getText());\n    }\n\n    @Override\n    public void apply() throws ConfigurationException {\n        mybatisSetting.setStatementGenerateModel(GenerateModel.getInstance(mybatisSettingForm.modelComboBox.getSelectedIndex()));\n        INSERT_GENERATOR.setPatterns(Sets.newHashSet(splitter.split(mybatisSettingForm.insertPatternTextField.getText())));\n        DELETE_GENERATOR.setPatterns(Sets.newHashSet(splitter.split(mybatisSettingForm.deletePatternTextField.getText())));\n        UPDATE_GENERATOR.setPatterns(Sets.newHashSet(splitter.split(mybatisSettingForm.updatePatternTextField.getText())));\n        SELECT_GENERATOR.setPatterns(Sets.newHashSet(splitter.split(mybatisSettingForm.selectPatternTextField.getText())));\n    }\n\n    @Override\n    public void reset() {\n        mybatisSettingForm.modelComboBox.setSelectedIndex(mybatisSetting.getStatementGenerateModel().getIdentifier());\n        mybatisSettingForm.insertPatternTextField.setText(joiner.join(INSERT_GENERATOR.getPatterns()));\n        mybatisSettingForm.deletePatternTextField.setText(joiner.join(DELETE_GENERATOR.getPatterns()));\n        mybatisSettingForm.updatePatternTextField.setText(joiner.join(UPDATE_GENERATOR.getPatterns()));\n        mybatisSettingForm.selectPatternTextField.setText(joiner.join(SELECT_GENERATOR.getPatterns()));\n    }\n\n    @Override\n    public void disposeUIResources() {\n        mybatisSettingForm.mainPanel = null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/setting/MybatisSetting.java",
    "content": "package com.wuzhizhan.mybatis.setting;\n\nimport com.google.gson.Gson;\nimport com.google.gson.reflect.TypeToken;\nimport com.intellij.openapi.components.PersistentStateComponent;\nimport com.intellij.openapi.components.ServiceManager;\nimport com.intellij.openapi.components.State;\nimport com.intellij.openapi.components.Storage;\nimport com.wuzhizhan.mybatis.generate.GenerateModel;\nimport com.wuzhizhan.mybatis.generate.StatementGenerator;\nimport org.jdom.Element;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.lang.reflect.Type;\nimport java.util.Set;\n\nimport static com.wuzhizhan.mybatis.generate.StatementGenerator.*;\n\n/**\n * @author yanglin\n */\n@State(\n        name = \"MybatisSettings\",\n        storages = @Storage(file = \"$APP_CONFIG$/mybatis.xml\"))\npublic class MybatisSetting implements PersistentStateComponent<Element> {\n\n    private GenerateModel statementGenerateModel;\n\n    private Gson gson = new Gson();\n\n    private Type gsonTypeToken = new TypeToken<Set<String>>() {\n    }.getType();\n\n    public MybatisSetting() {\n        statementGenerateModel = GenerateModel.START_WITH_MODEL;\n    }\n\n    public static MybatisSetting getInstance() {\n        return ServiceManager.getService(MybatisSetting.class);\n    }\n\n    @Nullable\n    @Override\n    public Element getState() {\n        Element element = new Element(\"MybatisSettings\");\n        element.setAttribute(INSERT_GENERATOR.getId(), gson.toJson(INSERT_GENERATOR.getPatterns()));\n        element.setAttribute(DELETE_GENERATOR.getId(), gson.toJson(DELETE_GENERATOR.getPatterns()));\n        element.setAttribute(UPDATE_GENERATOR.getId(), gson.toJson(UPDATE_GENERATOR.getPatterns()));\n        element.setAttribute(SELECT_GENERATOR.getId(), gson.toJson(SELECT_GENERATOR.getPatterns()));\n        element.setAttribute(\"statementGenerateModel\", String.valueOf(statementGenerateModel.getIdentifier()));\n        return element;\n    }\n\n    @Override\n    public void loadState(Element state) {\n        loadState(state, INSERT_GENERATOR);\n        loadState(state, DELETE_GENERATOR);\n        loadState(state, UPDATE_GENERATOR);\n        loadState(state, SELECT_GENERATOR);\n        statementGenerateModel = GenerateModel.getInstance(state.getAttributeValue(\"statementGenerateModel\"));\n    }\n\n    private void loadState(Element state, StatementGenerator generator) {\n        String attribute = state.getAttributeValue(generator.getId());\n        if (null != attribute) {\n            generator.setPatterns((Set<String>) gson.fromJson(attribute, gsonTypeToken));\n        }\n    }\n\n    public GenerateModel getStatementGenerateModel() {\n        return statementGenerateModel;\n    }\n\n    public void setStatementGenerateModel(GenerateModel statementGenerateModel) {\n        this.statementGenerateModel = statementGenerateModel;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/setting/MybatisSettingForm.form",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<form xmlns=\"http://www.intellij.com/uidesigner/form/\" version=\"1\" bind-to-class=\"com.wuzhizhan.mybatis.setting.MybatisSettingForm\">\n  <grid id=\"27dc6\" layout-manager=\"GridLayoutManager\" row-count=\"1\" column-count=\"1\" same-size-horizontally=\"false\" same-size-vertically=\"false\" hgap=\"-1\" vgap=\"-1\">\n    <margin top=\"0\" left=\"0\" bottom=\"0\" right=\"0\"/>\n    <constraints>\n      <xy x=\"20\" y=\"20\" width=\"500\" height=\"400\"/>\n    </constraints>\n    <properties/>\n    <border type=\"none\"/>\n    <children>\n      <grid id=\"d1e28\" binding=\"mainPanel\" layout-manager=\"GridLayoutManager\" row-count=\"7\" column-count=\"2\" same-size-horizontally=\"false\" same-size-vertically=\"false\" hgap=\"-1\" vgap=\"-1\">\n        <margin top=\"0\" left=\"0\" bottom=\"0\" right=\"0\"/>\n        <constraints>\n          <grid row=\"0\" column=\"0\" row-span=\"1\" col-span=\"1\" vsize-policy=\"3\" hsize-policy=\"3\" anchor=\"0\" fill=\"3\" indent=\"0\" use-parent-layout=\"false\"/>\n        </constraints>\n        <properties/>\n        <border type=\"none\" title=\"New Mapper Pattern Keywords\"/>\n        <children>\n          <component id=\"fb090\" class=\"javax.swing.JLabel\">\n            <constraints>\n              <grid row=\"2\" column=\"0\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"0\" anchor=\"8\" fill=\"0\" indent=\"0\" use-parent-layout=\"false\"/>\n            </constraints>\n            <properties>\n              <text value=\"Insert\"/>\n            </properties>\n          </component>\n          <component id=\"4d53e\" class=\"javax.swing.JTextField\" binding=\"insertPatternTextField\">\n            <constraints>\n              <grid row=\"2\" column=\"1\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"6\" anchor=\"8\" fill=\"1\" indent=\"0\" use-parent-layout=\"false\">\n                <preferred-size width=\"150\" height=\"-1\"/>\n              </grid>\n            </constraints>\n            <properties/>\n          </component>\n          <component id=\"45bc\" class=\"javax.swing.JLabel\">\n            <constraints>\n              <grid row=\"3\" column=\"0\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"0\" anchor=\"8\" fill=\"0\" indent=\"0\" use-parent-layout=\"false\"/>\n            </constraints>\n            <properties>\n              <text value=\"Delete\"/>\n            </properties>\n          </component>\n          <component id=\"6a666\" class=\"javax.swing.JTextField\" binding=\"deletePatternTextField\">\n            <constraints>\n              <grid row=\"3\" column=\"1\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"6\" anchor=\"8\" fill=\"1\" indent=\"0\" use-parent-layout=\"false\">\n                <preferred-size width=\"150\" height=\"-1\"/>\n              </grid>\n            </constraints>\n            <properties/>\n          </component>\n          <component id=\"52010\" class=\"javax.swing.JLabel\">\n            <constraints>\n              <grid row=\"4\" column=\"0\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"0\" anchor=\"8\" fill=\"0\" indent=\"0\" use-parent-layout=\"false\"/>\n            </constraints>\n            <properties>\n              <text value=\"Update\"/>\n            </properties>\n          </component>\n          <component id=\"de343\" class=\"javax.swing.JTextField\" binding=\"updatePatternTextField\">\n            <constraints>\n              <grid row=\"4\" column=\"1\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"6\" anchor=\"8\" fill=\"1\" indent=\"0\" use-parent-layout=\"false\">\n                <preferred-size width=\"150\" height=\"-1\"/>\n              </grid>\n            </constraints>\n            <properties/>\n          </component>\n          <component id=\"29a0b\" class=\"javax.swing.JLabel\">\n            <constraints>\n              <grid row=\"5\" column=\"0\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"0\" anchor=\"8\" fill=\"0\" indent=\"0\" use-parent-layout=\"false\"/>\n            </constraints>\n            <properties>\n              <text value=\"Select\"/>\n            </properties>\n          </component>\n          <component id=\"2b145\" class=\"javax.swing.JTextField\" binding=\"selectPatternTextField\">\n            <constraints>\n              <grid row=\"5\" column=\"1\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"6\" anchor=\"8\" fill=\"1\" indent=\"0\" use-parent-layout=\"false\">\n                <preferred-size width=\"150\" height=\"-1\"/>\n              </grid>\n            </constraints>\n            <properties/>\n          </component>\n          <component id=\"4f3c9\" class=\"javax.swing.JLabel\">\n            <constraints>\n              <grid row=\"0\" column=\"1\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"0\" anchor=\"8\" fill=\"0\" indent=\"0\" use-parent-layout=\"false\"/>\n            </constraints>\n            <properties>\n              <text value=\"Patterns should be separated with &quot;;&quot;\"/>\n            </properties>\n          </component>\n          <component id=\"f7906\" class=\"javax.swing.JComboBox\" binding=\"modelComboBox\">\n            <constraints>\n              <grid row=\"1\" column=\"1\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"2\" anchor=\"8\" fill=\"1\" indent=\"0\" use-parent-layout=\"false\"/>\n            </constraints>\n            <properties>\n              <model>\n                <item value=\"startWith\"/>\n                <item value=\"endWith\"/>\n                <item value=\"contain\"/>\n              </model>\n            </properties>\n          </component>\n          <vspacer id=\"98e49\">\n            <constraints>\n              <grid row=\"6\" column=\"1\" row-span=\"1\" col-span=\"1\" vsize-policy=\"6\" hsize-policy=\"1\" anchor=\"0\" fill=\"2\" indent=\"0\" use-parent-layout=\"false\"/>\n            </constraints>\n          </vspacer>\n          <component id=\"7d563\" class=\"javax.swing.JLabel\">\n            <constraints>\n              <grid row=\"1\" column=\"0\" row-span=\"1\" col-span=\"1\" vsize-policy=\"0\" hsize-policy=\"0\" anchor=\"8\" fill=\"0\" indent=\"0\" use-parent-layout=\"false\"/>\n            </constraints>\n            <properties>\n              <text value=\"Model\"/>\n            </properties>\n          </component>\n        </children>\n      </grid>\n    </children>\n  </grid>\n</form>\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/setting/MybatisSettingForm.java",
    "content": "package com.wuzhizhan.mybatis.setting;\n\nimport javax.swing.*;\n\n/**\n * @author yanglin\n */\npublic class MybatisSettingForm {\n\n    public JTextField insertPatternTextField;\n\n    public JTextField deletePatternTextField;\n\n    public JTextField updatePatternTextField;\n\n    public JTextField selectPatternTextField;\n\n    public JPanel mainPanel;\n\n    public JComboBox modelComboBox;\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/template/MybatisFileTemplateDescriptorFactory.java",
    "content": "package com.wuzhizhan.mybatis.template;\n\nimport com.intellij.ide.fileTemplates.FileTemplateDescriptor;\nimport com.intellij.ide.fileTemplates.FileTemplateGroupDescriptor;\nimport com.intellij.ide.fileTemplates.FileTemplateGroupDescriptorFactory;\nimport com.wuzhizhan.mybatis.util.Icons;\n\n/**\n * @author yanglin\n */\npublic class MybatisFileTemplateDescriptorFactory implements FileTemplateGroupDescriptorFactory {\n\n    public static final String MYBATIS_MAPPER_XML_TEMPLATE = \"Mybatis Mapper.xml\";\n\n    @Override\n    public FileTemplateGroupDescriptor getFileTemplatesDescriptor() {\n        FileTemplateGroupDescriptor group = new FileTemplateGroupDescriptor(\"Mybatis\", Icons.MYBATIS_LOGO);\n        group.addTemplate(new FileTemplateDescriptor(MYBATIS_MAPPER_XML_TEMPLATE, Icons.MYBATIS_LOGO));\n        return group;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/ui/ClickableListener.java",
    "content": "package com.wuzhizhan.mybatis.ui;\n\n/**\n * @author yanglin\n */\npublic interface ClickableListener extends ExecutableListener {\n\n    public void clicked();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/ui/ExecutableListener.java",
    "content": "package com.wuzhizhan.mybatis.ui;\n\n/**\n * @author yanglin\n */\npublic interface ExecutableListener {\n\n    public boolean isWriteAction();\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/ui/ListSelectionListener.java",
    "content": "package com.wuzhizhan.mybatis.ui;\n\n/**\n * @author yanglin\n */\npublic interface ListSelectionListener extends ExecutableListener {\n\n    public void selected(int index);\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/ui/UiComponentFacade.java",
    "content": "package com.wuzhizhan.mybatis.ui;\n\nimport com.intellij.openapi.application.Application;\nimport com.intellij.openapi.application.ApplicationManager;\nimport com.intellij.openapi.editor.Editor;\nimport com.intellij.openapi.fileChooser.FileChooser;\nimport com.intellij.openapi.fileChooser.FileChooserDescriptor;\nimport com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;\nimport com.intellij.openapi.fileEditor.FileEditorManager;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.openapi.ui.popup.JBPopup;\nimport com.intellij.openapi.ui.popup.PopupChooserBuilder;\nimport com.intellij.openapi.vfs.VirtualFile;\nimport com.intellij.ui.components.JBCheckBox;\nimport com.intellij.ui.components.JBList;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\n\n/**\n * @author yanglin\n */\npublic final class UiComponentFacade {\n\n    private Project project;\n\n    private FileEditorManager fileEditorManager;\n\n    private UiComponentFacade(Project project) {\n        this.project = project;\n        this.fileEditorManager = FileEditorManager.getInstance(project);\n    }\n\n    public static UiComponentFacade getInstance(@NotNull Project project) {\n        return new UiComponentFacade(project);\n    }\n\n    public VirtualFile showSingleFolderSelectionDialog(@NotNull String title,\n                                                       @Nullable VirtualFile toSelect,\n                                                       @Nullable VirtualFile... roots) {\n        final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();\n        descriptor.setTitle(title);\n        if (null != roots) {\n            descriptor.setRoots(roots);\n        }\n        return FileChooser.chooseFile(descriptor, project, toSelect);\n    }\n\n    public JBPopup showListPopupWithSingleClickable(@NotNull String popupTitle,\n                                                    @NotNull ListSelectionListener popupListener,\n                                                    @NotNull String clickableTitle,\n                                                    @Nullable final ClickableListener clickableListener,\n                                                    @NotNull Object[] objs) {\n        PopupChooserBuilder builder = createListPopupBuilder(popupTitle, popupListener, objs);\n        JBCheckBox checkBox = new JBCheckBox(clickableTitle);\n        builder.setSouthComponent(checkBox);\n        final JBPopup popup = builder.createPopup();\n        if (null != clickableListener) {\n            final Runnable runnable = new Runnable() {\n                @Override\n                public void run() {\n                    clickableListener.clicked();\n                }\n            };\n            checkBox.addActionListener(new ActionListener() {\n                @Override\n                public void actionPerformed(ActionEvent e) {\n                    popup.dispose();\n                    setActionForExecutableListener(runnable, clickableListener);\n                }\n            });\n        }\n        setPositionForShown(popup);\n        return popup;\n    }\n\n    public JBPopup showListPopup(@NotNull String title,\n                                 @Nullable final ListSelectionListener listener,\n                                 @NotNull Object[] objs) {\n        PopupChooserBuilder builder = createListPopupBuilder(title, listener, objs);\n        JBPopup popup = builder.createPopup();\n        setPositionForShown(popup);\n        return popup;\n    }\n\n    private void setPositionForShown(JBPopup popup) {\n        Editor editor = fileEditorManager.getSelectedTextEditor();\n        if (null != editor) {\n            popup.showInBestPositionFor(editor);\n        } else {\n            popup.showCenteredInCurrentWindow(project);\n        }\n    }\n\n    private void setActionForExecutableListener(Runnable runnable, ExecutableListener listener) {\n        final Application application = ApplicationManager.getApplication();\n        if (listener.isWriteAction()) {\n            application.runWriteAction(runnable);\n        } else {\n            application.runReadAction(runnable);\n        }\n    }\n\n    public PopupChooserBuilder createListPopupBuilder(@NotNull String title,\n                                                      @Nullable final ListSelectionListener listener,\n                                                      @NotNull Object... objs) {\n        final JBList list = new JBList(objs);\n        PopupChooserBuilder builder = new PopupChooserBuilder(list);\n        builder.setTitle(title);\n        if (null != listener) {\n            final Runnable runnable = new Runnable() {\n                @Override\n                public void run() {\n                    listener.selected(list.getSelectedIndex());\n                }\n            };\n            builder.setItemChoosenCallback(new Runnable() {\n                @Override\n                public void run() {\n                    setActionForExecutableListener(runnable, listener);\n                }\n            });\n        }\n        return builder;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/util/ArrayUtils.java",
    "content": "package com.wuzhizhan.mybatis.util;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Optional;\n\n/**\n * @author yanglin\n */\npublic final class ArrayUtils {\n\n    private ArrayUtils() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NotNull\n    public static <T> Optional<T> getOnlyElement(@Nullable T[] target, @NotNull T defValue) {\n        return Optional.ofNullable(getOnlyElement(target).orElse(defValue));\n    }\n\n    @NotNull\n    public static <T> Optional<T> getOnlyElement(@Nullable T[] target) {\n        return (null == target || 1 != target.length) ? Optional.empty() : Optional.ofNullable(target[0]);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/util/CollectionUtils.java",
    "content": "package com.wuzhizhan.mybatis.util;\n\nimport java.util.Collection;\n\n/**\n * @author yanglin\n */\npublic final class CollectionUtils {\n\n    private CollectionUtils() {\n        throw new UnsupportedOperationException();\n    }\n\n    public static boolean isEmpty(Collection collection) {\n        return null == collection || 0 == collection.size();\n    }\n\n    public static boolean isNotEmpty(Collection collection) {\n        return !isEmpty(collection);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/util/DomUtils.java",
    "content": "package com.wuzhizhan.mybatis.util;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Collections2;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.PsiFile;\nimport com.intellij.psi.search.GlobalSearchScope;\nimport com.intellij.psi.xml.XmlFile;\nimport com.intellij.psi.xml.XmlTag;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.DomFileElement;\nimport com.intellij.util.xml.DomService;\nimport org.jetbrains.annotations.NonNls;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\nimport java.util.List;\n\npublic final class DomUtils {\n\n    private DomUtils() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NotNull\n    @NonNls\n    public static <T extends DomElement> Collection<T> findDomElements(@NotNull Project project, Class<T> clazz) {\n        GlobalSearchScope scope = GlobalSearchScope.allScope(project);\n        List<DomFileElement<T>> elements = DomService.getInstance().getFileElements(clazz, project, scope);\n        return Collections2.transform(elements, new Function<DomFileElement<T>, T>() {\n            @Override\n            public T apply(DomFileElement<T> input) {\n                return input.getRootElement();\n            }\n        });\n    }\n\n    public static boolean isMybatisFile(@Nullable PsiFile file) {\n        if (!isXmlFile(file)) {\n            return false;\n        }\n        XmlTag rootTag = ((XmlFile) file).getRootTag();\n        return null != rootTag && rootTag.getName().equals(\"mapper\");\n    }\n\n    public static boolean isMybatisConfigurationFile(@NotNull PsiFile file) {\n        if (!isXmlFile(file)) {\n            return false;\n        }\n        XmlTag rootTag = ((XmlFile) file).getRootTag();\n        return null != rootTag && rootTag.getName().equals(\"configuration\");\n    }\n\n    public static boolean isBeansFile(@NotNull PsiFile file) {\n        if (!isXmlFile(file)) {\n            return false;\n        }\n        XmlTag rootTag = ((XmlFile) file).getRootTag();\n        return null != rootTag && rootTag.getName().equals(\"beans\");\n    }\n\n    static boolean isXmlFile(@NotNull PsiFile file) {\n        return file instanceof XmlFile;\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/util/Icons.java",
    "content": "package com.wuzhizhan.mybatis.util;\n\nimport com.intellij.openapi.util.IconLoader;\nimport com.intellij.util.PlatformIcons;\n\nimport javax.swing.*;\n\n/**\n * @author yanglin\n */\npublic interface Icons {\n\n    Icon MYBATIS_LOGO = IconLoader.getIcon(\"/javaee/persistenceId.png\");\n\n    Icon PARAM_COMPLETION_ICON = PlatformIcons.PARAMETER_ICON;\n\n    Icon MAPPER_LINE_MARKER_ICON = IconLoader.getIcon(\"/images/mapper_method.png\");\n\n    Icon STATEMENT_LINE_MARKER_ICON = IconLoader.getIcon(\"/images/statement.png\");\n\n    Icon SPRING_INJECTION_ICON = IconLoader.getIcon(\"/images/injection.png\");\n}"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/util/JTextFieldHintListener.java",
    "content": "package com.wuzhizhan.mybatis.util;\n\nimport javax.swing.*;\nimport java.awt.*;\nimport java.awt.event.FocusEvent;\nimport java.awt.event.FocusListener;\n\n/**\n * 输入框提示\n * Created by kangtian on 2018/8/3.\n */\npublic class JTextFieldHintListener implements FocusListener {\n    private String hintText;\n    private JTextField textField;\n\n    public JTextFieldHintListener(JTextField jTextField, String hintText) {\n        this.textField = jTextField;\n        this.hintText = hintText;\n        jTextField.setText(hintText);  //默认直接显示\n        jTextField.setForeground(Color.GRAY);\n    }\n\n    @Override\n    public void focusGained(FocusEvent e) {\n        //获取焦点时，清空提示内容\n        String temp = textField.getText();\n        if (temp.equals(hintText)) {\n            textField.setText(\"\");\n            textField.setForeground(Color.BLACK);\n        }\n\n    }\n\n    @Override\n    public void focusLost(FocusEvent e) {\n        //失去焦点时，没有输入内容，显示提示内容\n        String temp = textField.getText();\n        if (temp.equals(\"\")) {\n            textField.setForeground(Color.GRAY);\n            textField.setText(hintText);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/util/JavaUtils.java",
    "content": "package com.wuzhizhan.mybatis.util;\n\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.*;\nimport com.intellij.psi.search.GlobalSearchScope;\nimport com.intellij.psi.util.PropertyUtil;\nimport com.intellij.psi.util.PsiTreeUtil;\nimport com.wuzhizhan.mybatis.annotation.Annotation;\nimport com.wuzhizhan.mybatis.dom.model.IdDomElement;\nimport org.apache.commons.lang.ArrayUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\n\n/**\n * @author yanglin\n */\npublic final class JavaUtils {\n\n    private JavaUtils() {\n        throw new UnsupportedOperationException();\n    }\n\n    public static boolean isModelClazz(@Nullable PsiClass clazz) {\n        return null != clazz && !clazz.isAnnotationType() && !clazz.isInterface() && !clazz.isEnum() && clazz.isValid();\n    }\n\n    @NotNull\n    public static Optional<PsiField> findSettablePsiField(\n            @NotNull final PsiClass clazz,\n            @Nullable final String propertyName) {\n        final PsiField field = PropertyUtil.findPropertyField(clazz, propertyName, false);\n        return field != null ? Optional.of(field) : Optional.empty();\n    }\n\n    @NotNull\n    public static PsiField[] findSettablePsiFields(final @NotNull PsiClass clazz) {\n        final PsiField[] fields = clazz.getAllFields();\n        final List<PsiField> settableFields = new ArrayList<>(fields.length);\n\n        for (final PsiField f : fields) {\n            final PsiModifierList modifiers = f.getModifierList();\n\n            if (modifiers != null && (\n                    modifiers.hasModifierProperty(PsiModifier.STATIC) ||\n                            modifiers.hasModifierProperty(PsiModifier.FINAL))) {\n                continue;\n            }\n\n            settableFields.add(f);\n        }\n\n        return settableFields.toArray(new PsiField[0]);\n    }\n\n    public static boolean isElementWithinInterface(@Nullable PsiElement element) {\n        if (element instanceof PsiClass && ((PsiClass) element).isInterface()) {\n            return true;\n        }\n        PsiClass type = PsiTreeUtil.getParentOfType(element, PsiClass.class);\n        return Optional.ofNullable(type).isPresent() && type.isInterface();\n    }\n\n    @NotNull\n    public static Optional<PsiClass> findClazz(@NotNull Project project, @NotNull String clazzName) {\n        return Optional.ofNullable(JavaPsiFacade.getInstance(project).findClass(clazzName, GlobalSearchScope.allScope(project)));\n    }\n\n    @NotNull\n    public static Optional<PsiMethod> findMethod(@NotNull Project project, @Nullable String clazzName, @Nullable String methodName) {\n        if (StringUtils.isBlank(clazzName) && StringUtils.isBlank(methodName)) {\n            return Optional.empty();\n        }\n        Optional<PsiClass> clazz = findClazz(project, clazzName);\n        if (clazz.isPresent()) {\n            PsiMethod[] methods = clazz.get().findMethodsByName(methodName, true);\n            return ArrayUtils.isEmpty(methods) ? Optional.empty() : Optional.of(methods[0]);\n        }\n        return Optional.empty();\n    }\n\n    @NotNull\n    public static Optional<PsiMethod> findMethod(@NotNull Project project, @NotNull IdDomElement element) {\n        return findMethod(project, MapperUtils.getNamespace(element), MapperUtils.getId(element));\n    }\n\n    public static boolean isAnnotationPresent(@NotNull PsiModifierListOwner target, @NotNull Annotation annotation) {\n        PsiModifierList modifierList = target.getModifierList();\n        return null != modifierList && null != modifierList.findAnnotation(annotation.getQualifiedName());\n    }\n\n    @NotNull\n    public static Optional<PsiAnnotation> getPsiAnnotation(@NotNull PsiModifierListOwner target, @NotNull Annotation annotation) {\n        PsiModifierList modifierList = target.getModifierList();\n        return null == modifierList ? Optional.empty() : Optional.ofNullable(modifierList.findAnnotation(annotation.getQualifiedName()));\n    }\n\n    @NotNull\n    public static Optional<PsiAnnotationMemberValue> getAnnotationAttributeValue(@NotNull PsiModifierListOwner target,\n                                                                                 @NotNull Annotation annotation,\n                                                                                 @NotNull String attrName) {\n        if (!isAnnotationPresent(target, annotation)) {\n            return Optional.empty();\n        }\n        Optional<PsiAnnotation> psiAnnotation = getPsiAnnotation(target, annotation);\n        return psiAnnotation.isPresent() ? Optional.ofNullable(psiAnnotation.get().findAttributeValue(attrName)) : Optional.empty();\n    }\n\n    @NotNull\n    public static Optional<PsiAnnotationMemberValue> getAnnotationValue(@NotNull PsiModifierListOwner target, @NotNull Annotation annotation) {\n        return getAnnotationAttributeValue(target, annotation, \"value\");\n    }\n\n    public static Optional<String> getAnnotationValueText(@NotNull PsiModifierListOwner target, @NotNull Annotation annotation) {\n        Optional<PsiAnnotationMemberValue> annotationValue = getAnnotationValue(target, annotation);\n        return annotationValue.isPresent() ? Optional.of(annotationValue.get().getText().replaceAll(\"\\\"\", \"\")) : Optional.empty();\n    }\n\n    public static boolean isAnyAnnotationPresent(@NotNull PsiModifierListOwner target, @NotNull Set<Annotation> annotations) {\n        for (Annotation annotation : annotations) {\n            if (isAnnotationPresent(target, annotation)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static boolean isAllParameterWithAnnotation(@NotNull PsiMethod method, @NotNull Annotation annotation) {\n        PsiParameter[] parameters = method.getParameterList().getParameters();\n        for (PsiParameter parameter : parameters) {\n            if (!isAnnotationPresent(parameter, annotation)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public static boolean hasImportClazz(@NotNull PsiJavaFile file, @NotNull String clazzName) {\n        PsiImportList importList = file.getImportList();\n        if (null == importList) {\n            return false;\n        }\n        PsiImportStatement[] statements = importList.getImportStatements();\n        for (PsiImportStatement tmp : statements) {\n            if (null != tmp && tmp.getQualifiedName().equals(clazzName)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/util/MapperUtils.java",
    "content": "package com.wuzhizhan.mybatis.util;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Collections2;\nimport com.google.common.collect.Lists;\nimport com.intellij.ide.fileTemplates.FileTemplate;\nimport com.intellij.ide.fileTemplates.FileTemplateManager;\nimport com.intellij.ide.fileTemplates.FileTemplateUtil;\nimport com.intellij.openapi.project.Project;\nimport com.intellij.psi.*;\nimport com.intellij.psi.xml.XmlElement;\nimport com.intellij.util.Processor;\nimport com.intellij.util.xml.DomElement;\nimport com.intellij.util.xml.DomUtil;\nimport com.wuzhizhan.mybatis.dom.model.*;\nimport org.jetbrains.annotations.NonNls;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.Collection;\nimport java.util.*;\n\n\n/**\n * @author yanglin\n */\npublic final class MapperUtils {\n\n    private MapperUtils() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NotNull\n    public static Optional<IdDomElement> findParentIdDomElement(@Nullable PsiElement element) {\n        DomElement domElement = DomUtil.getDomElement(element);\n        if (null == domElement) {\n            return Optional.empty();\n        }\n        if (domElement instanceof IdDomElement) {\n            return Optional.of((IdDomElement) domElement);\n        }\n        return Optional.ofNullable(DomUtil.getParentOfType(domElement, IdDomElement.class, true));\n    }\n\n    public static PsiElement createMapperFromFileTemplate(@NotNull String fileTemplateName,\n                                                          @NotNull String fileName,\n                                                          @NotNull PsiDirectory directory,\n                                                          @Nullable Properties pops) throws Exception {\n        FileTemplate fileTemplate = FileTemplateManager.getInstance().getJ2eeTemplate(fileTemplateName);\n        return FileTemplateUtil.createFromTemplate(fileTemplate, fileName, pops, directory);\n    }\n\n    @NotNull\n    public static Collection<PsiDirectory> findMapperDirectories(@NotNull Project project) {\n        return Collections2.transform(findMappers(project), new Function<Mapper, PsiDirectory>() {\n            @Override\n            public PsiDirectory apply(Mapper input) {\n                return input.getXmlElement().getContainingFile().getContainingDirectory();\n            }\n        });\n    }\n\n    public static boolean isElementWithinMybatisFile(@NotNull PsiElement element) {\n        PsiFile psiFile = element.getContainingFile();\n        return element instanceof XmlElement && DomUtils.isMybatisFile(psiFile);\n    }\n\n    @NotNull\n    @NonNls\n    public static Collection<Mapper> findMappers(@NotNull Project project) {\n        return DomUtils.findDomElements(project, Mapper.class);\n    }\n\n    @NotNull\n    @NonNls\n    public static Collection<Mapper> findMappers(@NotNull Project project, @NotNull String namespace) {\n        List<Mapper> result = Lists.newArrayList();\n        for (Mapper mapper : findMappers(project)) {\n            if (getNamespace(mapper).equals(namespace)) {\n                result.add(mapper);\n            }\n        }\n        return result;\n    }\n\n    @NotNull\n    public static Collection<Mapper> findMappers(@NotNull Project project, @NotNull PsiClass clazz) {\n        return JavaUtils.isElementWithinInterface(clazz) ? findMappers(project, clazz.getQualifiedName()) : Collections.<Mapper>emptyList();\n    }\n\n    @NotNull\n    public static Collection<Mapper> findMappers(@NotNull Project project, @NotNull PsiMethod method) {\n        PsiClass clazz = method.getContainingClass();\n        return null == clazz ? Collections.<Mapper>emptyList() : findMappers(project, clazz);\n    }\n\n    @NotNull\n    @NonNls\n    public static Optional<Mapper> findFirstMapper(@NotNull Project project, @NotNull String namespace) {\n        Collection<Mapper> mappers = findMappers(project, namespace);\n        return CollectionUtils.isEmpty(mappers) ? Optional.empty() : Optional.of(mappers.iterator().next());\n    }\n\n    @NotNull\n    @NonNls\n    public static Optional<Mapper> findFirstMapper(@NotNull Project project, @NotNull PsiClass clazz) {\n        String qualifiedName = clazz.getQualifiedName();\n        return null != qualifiedName ? findFirstMapper(project, qualifiedName) : Optional.empty();\n    }\n\n    @NotNull\n    @NonNls\n    public static Optional<Mapper> findFirstMapper(@NotNull Project project, @NotNull PsiMethod method) {\n        PsiClass containingClass = method.getContainingClass();\n        return null != containingClass ? findFirstMapper(project, containingClass) : Optional.empty();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @NotNull\n    @NonNls\n    public static Mapper getMapper(@NotNull DomElement element) {\n        Optional<Mapper> optional = Optional.ofNullable(DomUtil.getParentOfType(element, Mapper.class, true));\n        if (optional.isPresent()) {\n            return optional.get();\n        } else {\n            throw new IllegalArgumentException(\"Unknown element\");\n        }\n    }\n\n    @NotNull\n    @NonNls\n    public static String getNamespace(@NotNull Mapper mapper) {\n        String ns = mapper.getNamespace().getStringValue();\n        return null == ns ? \"\" : ns;\n    }\n\n    @NotNull\n    @NonNls\n    public static String getNamespace(@NotNull DomElement element) {\n        return getNamespace(getMapper(element));\n    }\n\n    @NonNls\n    public static boolean isMapperWithSameNamespace(@Nullable Mapper mapper, @Nullable Mapper target) {\n        return null != mapper && null != target && getNamespace(mapper).equals(getNamespace(target));\n    }\n\n    @Nullable\n    @NonNls\n    public static <T extends IdDomElement> String getId(@NotNull T domElement) {\n        return domElement.getId().getRawText();\n    }\n\n    @NotNull\n    @NonNls\n    public static <T extends IdDomElement> String getIdSignature(@NotNull T domElement) {\n        return getNamespace(domElement) + \".\" + getId(domElement);\n    }\n\n    @NotNull\n    @NonNls\n    public static <T extends IdDomElement> String getIdSignature(@NotNull T domElement, @NotNull Mapper mapper) {\n        Mapper contextMapper = getMapper(domElement);\n        String id = getId(domElement);\n        if (id == null) {\n            id = \"\";\n        }\n        String idsignature = getIdSignature(domElement);\n        //getIdSignature(domElement)\n        return isMapperWithSameNamespace(contextMapper, mapper) ? id : idsignature;\n    }\n\n    public static void processConfiguredTypeAliases(@NotNull Project project, @NotNull Processor<TypeAlias> processor) {\n        for (Configuration conf : getMybatisConfigurations(project)) {\n            for (TypeAliases tas : conf.getTypeAliases()) {\n                for (TypeAlias ta : tas.getTypeAlias()) {\n                    String stringValue = ta.getAlias().getStringValue();\n                    if (null != stringValue && !processor.process(ta)) {\n                        return;\n                    }\n                }\n            }\n        }\n    }\n\n    private static Collection<Configuration> getMybatisConfigurations(Project project) {\n        return DomUtils.findDomElements(project, Configuration.class);\n    }\n\n    public static void processConfiguredPackage(@NotNull Project project,\n                                                @NotNull Processor<com.wuzhizhan.mybatis.dom.model.Package> processor) {\n        for (Configuration conf : getMybatisConfigurations(project)) {\n            for (TypeAliases tas : conf.getTypeAliases()) {\n                for (com.wuzhizhan.mybatis.dom.model.Package pkg : tas.getPackages()) {\n                    if (!processor.process(pkg)) {\n                        return;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/util/MybatisConstants.java",
    "content": "package com.wuzhizhan.mybatis.util;\n\nimport com.intellij.psi.util.ReferenceSetBase;\n\n/**\n * @author yanglin\n */\npublic final class MybatisConstants {\n\n    private MybatisConstants() {\n        throw new UnsupportedOperationException();\n    }\n\n    public static final String DOT_SEPARATOR = String.valueOf(ReferenceSetBase.DOT_SEPARATOR);\n\n    public static final double PRIORITY = 400.0;\n\n}\n"
  },
  {
    "path": "src/main/java/com/wuzhizhan/mybatis/util/StringUtils.java",
    "content": "package com.wuzhizhan.mybatis.util;\n\n/**\n * Created by Owen on 6/18/16.\n */\npublic class StringUtils {\n\n    /**\n     * convert string from slash style to camel style, such as my_course will convert to MyCourse\n     *\n     * @param str\n     * @return\n     */\n    public static String dbStringToCamelStyle(String str) {\n        if (str != null) {\n            str = str.toLowerCase();\n            StringBuilder sb = new StringBuilder();\n            sb.append(String.valueOf(str.charAt(0)).toUpperCase());\n            for (int i = 1; i < str.length(); i++) {\n                char c = str.charAt(i);\n                if (c != '_') {\n                    sb.append(c);\n                } else {\n                    if (i + 1 < str.length()) {\n                        sb.append(String.valueOf(str.charAt(i + 1)).toUpperCase());\n                        i++;\n                    }\n                }\n            }\n            return sb.toString();\n        }\n        return null;\n    }\n\n    public static boolean isEmpty(Object str) {\n        return str == null || \"\".equals(str);\n    }\n}\n"
  },
  {
    "path": "src/main/resources/META-INF/plugin.xml",
    "content": "<idea-plugin>\n    <id>cn.wuzhizhan.plugin.mybatis</id>\n    <name>FreeMyBatisPlugin</name>\n    <vendor email=\"wuzhizhan@wuzhizhan.cn\" url=\"https://github.com/wuzhizhan\">wuzhizhan</vendor>\n\n    <description><![CDATA[\n    Free Mybatis Plugin <br/>\n    A idea plugin for mybatis <br/>\n    free-mybatis-plugin is an enchange plugin for idea to supoort mybatis,here is the main functions:</br>\n    <ul>\n        <li>generate mapper xml files</li>\n        <li>navigate from the code to mapper and from the mapper back to code</li>\n        <li>auto code and error tips</li>\n    </ul>\n\n    free-mybatis-plugin是一款增强idea对mybatis支持的插件，主要功能如下：<br/>\n    <ul>\n        <li>生成mapper xml文件</li>\n        <li>快速从代码跳转到mapper及从mapper返回代码</li>\n        <li>mybatis自动补全及语法错误提示</li>\n    </ul>\n    ]]></description>\n\n    <idea-version since-build=\"145\"/>\n\n    <extensions defaultExtensionNs=\"com.intellij\">\n        <dom.fileDescription implementation=\"com.wuzhizhan.mybatis.dom.description.MapperDescription\"/>\n        <dom.fileDescription implementation=\"com.wuzhizhan.mybatis.dom.description.ConfigurationDescription\"/>\n        <definitionsSearch implementation=\"com.wuzhizhan.mybatis.definitionsearch.MapperDefinitionSearch\"/>\n        <projectService serviceImplementation=\"com.wuzhizhan.mybatis.service.JavaService\"/>\n        <projectService serviceImplementation=\"com.wuzhizhan.mybatis.service.AnnotationService\"/>\n        <projectService serviceImplementation=\"com.wuzhizhan.mybatis.service.EditorService\"/>\n        <projectService serviceImplementation=\"com.wuzhizhan.mybatis.alias.AliasFacade\"/>\n        <projectService serviceImplementation=\"com.wuzhizhan.mybatis.locator.MapperLocator\"/>\n        <projectService serviceImplementation=\"com.wuzhizhan.mybatis.service.TableInfoService\"/>\n        <codeInsight.lineMarkerProvider language=\"JAVA\" implementationClass=\"com.wuzhizhan.mybatis.provider.MapperLineMarkerProvider\"/>\n        <codeInsight.lineMarkerProvider language=\"XML\" implementationClass=\"com.wuzhizhan.mybatis.provider.StatementLineMarkerProvider\"/>\n        <codeInsight.lineMarkerProvider language=\"JAVA\" implementationClass=\"com.wuzhizhan.mybatis.provider.InjectionLineMarkerProvider\"/>\n        <applicationConfigurable groupId=\"tools\" instance=\"com.wuzhizhan.mybatis.setting.MybatisConfigurable\"/>\n        <completion.contributor language=\"JAVA\" implementationClass=\"com.wuzhizhan.mybatis.contributor.JavaMenthodCompletionContributor\"/>\n        <applicationService serviceImplementation=\"com.wuzhizhan.mybatis.setting.MybatisSetting\"/>\n        <completion.contributor language=\"XML\" implementationClass=\"com.wuzhizhan.mybatis.contributor.TestParamContributor\"/>\n        <completion.contributor language=\"SQL\" implementationClass=\"com.wuzhizhan.mybatis.contributor.SqlParamCompletionContributor\" order=\"first\"/>\n        <fileTemplateGroup implementation=\"com.wuzhizhan.mybatis.template.MybatisFileTemplateDescriptorFactory\"/>\n        <typedHandler implementation=\"com.wuzhizhan.mybatis.action.MybatisTypedHandler\" id=\"mybatis\" order=\"first\"/>\n        <defaultLiveTemplates file=\"liveTemplates/sql.xml\" hidden=\"false\"/>\n        <refactoring.elementListenerProvider implementation=\"com.wuzhizhan.mybatis.refactoring.MapperRefactoringProvider\"/>\n        <localInspection language=\"JAVA\" shortName=\"MybatisMapperMethodInspection\"\n                         displayName=\"Mapper method inspection\"\n                         groupName=\"Mybatis\" enabledByDefault=\"true\" level=\"ERROR\"\n                         implementationClass=\"com.wuzhizhan.mybatis.inspection.MapperMethodInspection\"/>\n        <localInspection language=\"XML\" shortName=\"MybatisMapperXmlInspection\" enabledByDefault=\"true\" level=\"ERROR\"\n                         displayName=\"Mapper xml inspection\"\n                         groupName=\"Mybatis\"\n                         implementationClass=\"com.wuzhizhan.mybatis.inspection.MapperXmlInspection\"/>\n        <intentionAction>\n            <className>com.wuzhizhan.mybatis.intention.GenerateParamAnnotationIntention</className>\n        </intentionAction>\n        <intentionAction>\n            <className>com.wuzhizhan.mybatis.intention.GenerateStatementIntention</className>\n        </intentionAction>\n        <intentionAction order=\"first\">\n            <className>com.wuzhizhan.mybatis.intention.GenerateMapperIntention</className>\n        </intentionAction>\n    </extensions>\n</idea-plugin>"
  },
  {
    "path": "src/main/resources/fileTemplates/j2ee/Mybatis Mapper.xml.ft",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\n<mapper namespace=\"${NAMESPACE}\" >\n</mapper>"
  },
  {
    "path": "src/main/resources/liveTemplates/sql.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<templateSet group=\"Mybatis/SQL\">\n    <template resource-bundle=\"messages.CodeInsightBundle\" key=\"livetemplate.description.surround.cdata.in.xmlorhtmlorjsp\"\n              name=\"CD\" toReformat=\"false\" toShortenFQNames=\"false\" value=\"&lt;![CDATA[&#10;$SELECTION$&#10;]]&gt;\">\n        <variable name=\"SELECTION\" expression=\"\" defaultValue=\"\" alwaysStopAt=\"false\" />\n        <context>\n            <option name=\"SQL\" value=\"true\" />\n        </context>\n    </template>\n</templateSet>"
  }
]