() {
87 | @Override
88 | public LookupElement apply(PsiElement element) {
89 | return LookupElementBuilder.create(element, getLookupString(element)).withIcon(Icons.JAVA_PARAMETER_ICON);
90 | }
91 | });
92 | }
93 |
94 | @NotNull
95 | private String getLookupString(PsiElement element) {
96 | if (element instanceof PsiAnnotationMemberValue) {
97 | return element.getText().substring(1, element.getTextLength() - 1);
98 | }
99 | if (element instanceof PsiIdentifier) {
100 | String getterProperty = ParamPropertyHelper.parseGetterMethod(element.getText());
101 | return getterProperty == null ? element.getText() : getterProperty;
102 | }
103 | return element.getText();
104 | }
105 |
106 | /**
107 | * check 10 chars prefix
108 | * @param psiFile origin file
109 | * @param offset text offset
110 | * @return prefix check
111 | */
112 | private boolean checkPrefix(PsiFile psiFile, int offset) {
113 | String allText = psiFile.getText();
114 | for (int i = offset; i >= offset - 20; i--) {
115 | if (allText.charAt(i) == '{'
116 | && (allText.charAt(i - 1) == '#' || allText.charAt(i - 1) == '$')) {
117 | return true;
118 | }
119 | }
120 | return false;
121 | }
122 |
123 | /**
124 | * find statement parent node
125 | * @param currentItem xml node
126 | * @return parent node of statement type
127 | */
128 | @Nullable
129 | private XmlTag findStatementXmlTag(XmlElement currentItem) {
130 | XmlElement parentItem = (XmlElement) currentItem.getParent();
131 | while (parentItem != null && !(parentItem instanceof XmlDocument)) {
132 | if ((parentItem instanceof XmlTag)
133 | && STATEMENT_TAG_NAMES.contains(((XmlTag) parentItem).getName())) {
134 | return (XmlTag) parentItem;
135 | } else {
136 | parentItem = (XmlElement) parentItem.getParent();
137 | }
138 | }
139 | return null;
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/contributor/StatementParamsReferenceContributor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.contributor;
5 |
6 | import com.google.common.collect.Lists;
7 | import com.intellij.openapi.util.Pair;
8 | import com.intellij.openapi.util.TextRange;
9 | import com.intellij.patterns.XmlPatterns;
10 | import com.intellij.psi.PsiElement;
11 | import com.intellij.psi.PsiReference;
12 | import com.intellij.psi.PsiReferenceContributor;
13 | import com.intellij.psi.PsiReferenceProvider;
14 | import com.intellij.psi.PsiReferenceRegistrar;
15 | import com.intellij.psi.xml.XmlDocument;
16 | import com.intellij.psi.xml.XmlTag;
17 | import com.intellij.util.ProcessingContext;
18 | import org.jetbrains.annotations.NotNull;
19 | import org.jetbrains.annotations.Nullable;
20 | import org.qunar.plugin.mybatis.bean.Annotation;
21 | import org.qunar.plugin.mybatis.reference.StatementParamsReference;
22 |
23 | import java.util.List;
24 | import java.util.Set;
25 | import java.util.regex.Matcher;
26 | import java.util.regex.Pattern;
27 |
28 | /**
29 | * resolve ${} #{} reference
30 | *
31 | * Author: jianyu.lin
32 | * Date: 2016/12/3 Time: 下午12:35
33 | */
34 | public class StatementParamsReferenceContributor extends PsiReferenceContributor {
35 |
36 | private static final Pattern PATTERN = Pattern.compile("(\\$\\{\\s*([a-zA-Z0-9_ ]+)\\s*" +
37 | "(,[a-zA-Z0-9_. ,=]*)?})|(\\s*#\\{([a-zA-Z0-9_]+)\\s*(,[a-zA-Z0-9_. ,=]*)?})");
38 |
39 | @Override
40 | public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
41 | registrar.registerReferenceProvider(XmlPatterns.xmlTag().withName(getAllStatementAndSubTags()),
42 | new PsiReferenceProvider() {
43 | @NotNull
44 | @Override
45 | public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
46 | @NotNull ProcessingContext context) {
47 | XmlTag xmlTag = (XmlTag) element;
48 | Pair parentTagPair = findParentStatementElement(xmlTag);
49 | if (parentTagPair == null) {
50 | return new PsiReference[0];
51 | }
52 |
53 | TextRange[] subTagRanges = getSubTagTextRanges(xmlTag);
54 |
55 | Matcher matcher = PATTERN.matcher(xmlTag.getText());
56 | List references = Lists.newArrayList();
57 | while (matcher.find()) {
58 | int start = matcher.start();
59 | int end = matcher.end();
60 | boolean belong2SubTag = false;
61 | for (TextRange subTagRange : subTagRanges) {
62 | if (xmlTag.getTextRange().getStartOffset() + start > subTagRange.getStartOffset()
63 | && xmlTag.getTextRange().getStartOffset() + end < subTagRange.getEndOffset()) {
64 | belong2SubTag = true;
65 | break;
66 | }
67 | }
68 | if (belong2SubTag) continue;
69 | int groupIndex = matcher.groupCount() - 1;
70 | start = matcher.start(groupIndex);
71 | end = matcher.end(groupIndex);
72 | if (start < 0 || end < 0) continue;
73 | references.add(new StatementParamsReference(xmlTag, parentTagPair.first,
74 | TextRange.create(start, end)).extraParams(parentTagPair.second));
75 | }
76 | return references.toArray(new PsiReference[references.size()]);
77 | }
78 | });
79 | }
80 |
81 | @Nullable
82 | private Pair findParentStatementElement(XmlTag subTag) {
83 | if (Annotation.getStatementNames().contains(subTag.getName())) {
84 | return Pair.create(subTag, new PsiElement[0]);
85 | }
86 | List elements = Lists.newArrayList();
87 | PsiElement psiElement = subTag;
88 | while (!(psiElement instanceof XmlDocument) && psiElement != null) {
89 | if (psiElement instanceof XmlTag) {
90 | XmlTag parentTag = (XmlTag) psiElement;
91 | elements.addAll(buildExtraParams(parentTag));
92 | if (Annotation.getStatementNames().contains(parentTag.getName())) {
93 | return Pair.create(parentTag, elements.toArray(new PsiElement[elements.size()]));
94 | }
95 | }
96 | psiElement = psiElement.getParent();
97 | }
98 | return null;
99 | }
100 |
101 | /**
102 | * get all subTag text range
103 | * @param xmlTag parent tag
104 | * @return text ranges
105 | */
106 | private TextRange[] getSubTagTextRanges(XmlTag xmlTag) {
107 | XmlTag[] subTags = xmlTag.getSubTags();
108 | TextRange[] textRanges = new TextRange[subTags.length];
109 | for (int i = 0; i < subTags.length; i++) {
110 | textRanges[i] = subTags[i].getTextRange();
111 | }
112 | return textRanges;
113 | }
114 |
115 | @NotNull
116 | private List buildExtraParams(@NotNull XmlTag xmlTag) {
117 | List elements = Lists.newArrayList();
118 | if (xmlTag.getName().equals("foreach")) {
119 | //noinspection ConstantConditions
120 | if (xmlTag.getAttribute("item") != null
121 | && xmlTag.getAttribute("item").getValueElement() != null) {
122 | //noinspection ConstantConditions
123 | elements.add(xmlTag.getAttribute("item").getValueElement());
124 | }
125 | }
126 | return elements;
127 | }
128 |
129 | private String[] getAllStatementAndSubTags() {
130 | Set tagNames = Annotation.getStatementNames();
131 | tagNames.add("if");
132 | tagNames.add("where");
133 | tagNames.add("when");
134 | tagNames.add("otherwise");
135 | tagNames.add("foreach");
136 | return tagNames.toArray(new String[tagNames.size()]);
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/converter/MapperMethodConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.converter;
5 |
6 | import com.intellij.psi.PsiClass;
7 | import com.intellij.psi.PsiMethod;
8 | import com.intellij.psi.scope.processor.MethodResolveProcessor;
9 | import com.intellij.psi.xml.XmlTag;
10 | import com.intellij.spring.model.converters.PsiMethodConverter;
11 | import com.intellij.util.xml.ConvertContext;
12 | import org.jetbrains.annotations.Nullable;
13 | import org.qunar.plugin.service.JavaService;
14 |
15 | /**
16 | * take advantages of PsiMethodConverter
17 | * to parse id attribute of mybatis mapper xml's sub tag
18 | *
19 | * Author: jianyu.lin
20 | * Date: 2016/11/25 Time: 上午1:55
21 | * @since v1.2.2
22 | */
23 | public class MapperMethodConverter extends PsiMethodConverter {
24 |
25 | @Override
26 | protected PsiMethod[] getMethodCandidates(String methodIdentificator, PsiClass psiClass) {
27 | return MethodResolveProcessor.findMethod(psiClass, methodIdentificator);
28 | }
29 |
30 | @Nullable
31 | @Override
32 | protected PsiClass getPsiClass(ConvertContext context) {
33 | XmlTag rootTag = context.getFile().getRootTag();
34 | if (rootTag == null || rootTag.getAttribute("namespace") == null) {
35 | return null;
36 | }
37 | String qualifiedMapperClass = rootTag.getAttributeValue("namespace");
38 | return JavaService.getInstance(context.getProject()).findProjectClass(qualifiedMapperClass);
39 | }
40 |
41 | @Override
42 | protected String getMethodIdentificator(PsiMethod method) {
43 | return method.getName();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/converter/PathFileConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.converter;
5 |
6 | import com.google.common.base.Splitter;
7 | import com.intellij.openapi.project.Project;
8 | import com.intellij.psi.PsiDirectory;
9 | import com.intellij.psi.PsiFile;
10 | import com.intellij.psi.search.FilenameIndex;
11 | import com.intellij.psi.search.GlobalSearchScope;
12 | import com.intellij.util.xml.ConvertContext;
13 | import com.intellij.util.xml.Converter;
14 | import org.apache.commons.lang.StringUtils;
15 | import org.jetbrains.annotations.NonNls;
16 | import org.jetbrains.annotations.NotNull;
17 | import org.jetbrains.annotations.Nullable;
18 | import org.qunar.plugin.service.JavaService;
19 |
20 | import java.util.List;
21 |
22 | /**
23 | * string dir converter
24 | *
25 | * Author: jianyu.lin
26 | * Date: 2016/11/23 Time: 下午3:41
27 | */
28 | public class PathFileConverter extends Converter {
29 |
30 | private static final Splitter PATH_SPLITTER = Splitter.on('/');
31 | private static final String CLASS_PATH_DIR = "";
32 |
33 | @Nullable
34 | @Override
35 | public PsiFile fromString(@Nullable @NonNls String s, ConvertContext context) {
36 | return parseClassPathRelatedFile(context.getProject(), s);
37 | }
38 |
39 | @Nullable
40 | @Override
41 | public String toString(@Nullable PsiFile psiFile, ConvertContext context) {
42 | return psiFile == null ? null : psiFile.toString();
43 | }
44 |
45 | /**
46 | * parse class path related file by path
47 | * @param project project object
48 | * @param filePath path
49 | * @return psiFile
50 | */
51 | public static PsiFile parseClassPathRelatedFile(@NotNull Project project,
52 | @Nullable @NonNls String filePath) {
53 | if (StringUtils.isBlank(filePath)) {
54 | return null;
55 | }
56 | List pathLevels = PATH_SPLITTER.splitToList(filePath);
57 | String fileName = pathLevels.get(pathLevels.size() -1);
58 | PsiFile[] files = FilenameIndex.getFilesByName(project, fileName, GlobalSearchScope.projectScope(project));
59 | if (files.length == 0) {
60 | return null;
61 | }
62 | PsiDirectory[] directories = JavaService.getInstance(project).getRelatedDirectories(CLASS_PATH_DIR);
63 | for (PsiFile psiFile : files) {
64 | for (PsiDirectory dir : directories) {
65 | String absolutePath = dir.getVirtualFile().getCanonicalPath() + "/" + filePath;
66 | if (StringUtils.equals(psiFile.getVirtualFile().getCanonicalPath(), absolutePath)) {
67 | return psiFile;
68 | }
69 | }
70 | }
71 | return null;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/converter/TypeAliasConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.converter;
5 |
6 | import com.intellij.psi.PsiClass;
7 | import com.intellij.psi.PsiElement;
8 | import com.intellij.psi.PsiReference;
9 | import com.intellij.psi.xml.XmlAttributeValue;
10 | import com.intellij.util.xml.ConvertContext;
11 | import com.intellij.util.xml.CustomReferenceConverter;
12 | import com.intellij.util.xml.GenericDomValue;
13 | import com.intellij.util.xml.PsiClassConverter;
14 | import org.jetbrains.annotations.NotNull;
15 | import org.qunar.plugin.mybatis.reference.TypeAliasNameReference;
16 | import org.qunar.plugin.service.JavaService;
17 | import org.qunar.plugin.service.TypeAliasService;
18 |
19 | /**
20 | * sql node parameter type attribute converter
21 | *
22 | * Author: jianyu.lin
23 | * Date: 2016/11/25 Time: 下午2:30
24 | */
25 | public class TypeAliasConverter extends PsiClassConverter implements CustomReferenceConverter {
26 |
27 | @Override
28 | public PsiClass fromString(String parameterType, ConvertContext context) {
29 | if (parameterType.contains(".")) {
30 | return super.fromString(parameterType, context);
31 | }
32 | PsiClass qualifiedClass = JavaService.getInstance(context.getProject()).findClass(parameterType);
33 | return qualifiedClass != null ? qualifiedClass :
34 | TypeAliasService.INSTANCE(context.getProject()).getAliasClassByName(parameterType);
35 | }
36 |
37 | @NotNull
38 | @Override
39 | public PsiReference[] createReferences(GenericDomValue genericDomValue,
40 | PsiElement element, ConvertContext context) {
41 | XmlAttributeValue attributeValue = (XmlAttributeValue) element;
42 | if (attributeValue.getValue() == null || attributeValue.getValue().contains(".")) {
43 | return super.createReferences(genericDomValue, element, context);
44 | }
45 | return new PsiReference[]{new TypeAliasNameReference(attributeValue)};
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/description/ConfigurationDescription.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.description;
5 |
6 | import com.intellij.util.xml.DomFileDescription;
7 | import org.qunar.plugin.mybatis.bean.config.Configuration;
8 | import org.qunar.plugin.mybatis.util.ConfigConfHolder;
9 |
10 | /**
11 | * mybatis configuration xml description
12 | *
13 | * Author: jianyu.lin
14 | * Date: 2016/11/22 Time: 上午12:17
15 | */
16 | public class ConfigurationDescription extends DomFileDescription {
17 |
18 | public ConfigurationDescription() {
19 | super(Configuration.class, ConfigConfHolder.INSTANCE.rootTagName);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/description/MapperDescription.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.description;
5 |
6 | import com.intellij.util.xml.DomFileDescription;
7 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
8 | import org.qunar.plugin.mybatis.util.MapperConfHolder;
9 |
10 | /**
11 | * mybatis mapper xml description
12 | *
13 | * Author: jianyu.lin
14 | * Date: 2016/11/22 Time: 上午12:17
15 | */
16 | public class MapperDescription extends DomFileDescription {
17 |
18 | public MapperDescription() {
19 | super(Mapper.class, MapperConfHolder.INSTANCE.rootTagName);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/generator/AbstractGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.generator;
5 |
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.psi.PsiElement;
8 | import com.intellij.sql.psi.SqlElement;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 | import org.qunar.plugin.bean.ModuleSetting;
12 | import org.qunar.plugin.util.Modules;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 |
16 | /**
17 | * mybatis mapper generator
18 | *
19 | * Author: jianyu.lin
20 | * Date: 2016/12/22 Time: 下午2:58
21 | */
22 | public abstract class AbstractGenerator {
23 |
24 | protected static final Logger logger = LoggerFactory.getLogger(AbstractGenerator.class);
25 |
26 | @NotNull
27 | protected final Project project;
28 | @NotNull
29 | protected final SqlElement myCreateTableDdl;
30 | protected final ModuleSetting moduleSetting;
31 |
32 | public AbstractGenerator(@NotNull Project project, @NotNull SqlElement myCreateTableDdl) {
33 | this.project = project;
34 | this.myCreateTableDdl = myCreateTableDdl;
35 | moduleSetting = Modules.getModuleSettingByElement(myCreateTableDdl);
36 | }
37 |
38 | /**
39 | * generate psi element
40 | * @return psi element generated by this plugin
41 | */
42 | @Nullable
43 | public abstract T generate();
44 | }
45 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/generator/JavaGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.generator;
5 |
6 | import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassKind;
7 | import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils;
8 | import com.intellij.openapi.application.ApplicationManager;
9 | import com.intellij.openapi.command.WriteCommandAction;
10 | import com.intellij.openapi.project.Project;
11 | import com.intellij.openapi.util.Computable;
12 | import com.intellij.openapi.util.Pair;
13 | import com.intellij.openapi.vfs.VirtualFile;
14 | import com.intellij.psi.PsiClass;
15 | import com.intellij.psi.PsiDirectory;
16 | import com.intellij.psi.PsiElementFactory;
17 | import com.intellij.psi.PsiImportStatement;
18 | import com.intellij.psi.PsiJavaFile;
19 | import com.intellij.psi.PsiManager;
20 | import com.intellij.psi.PsiMethod;
21 | import com.intellij.psi.codeStyle.CodeStyleManager;
22 | import com.intellij.psi.search.GlobalSearchScope;
23 | import com.intellij.psi.util.CreateClassUtil;
24 | import com.intellij.sql.psi.SqlElement;
25 | import org.jetbrains.annotations.NotNull;
26 | import org.jetbrains.annotations.Nullable;
27 | import org.qunar.plugin.service.EditorService;
28 | import org.qunar.plugin.service.JavaService;
29 |
30 | import static com.intellij.psi.util.CreateClassUtil.DEFAULT_CLASS_TEMPLATE;
31 |
32 | /**
33 | * generate mapper java interface
34 | *
35 | * Author: jianyu.lin
36 | * Date: 2016/12/22 Time: 下午2:59
37 | */
38 | public class JavaGenerator extends AbstractGenerator {
39 |
40 | /* qualified class name */
41 | @NotNull
42 | private final String packageName;
43 | private final String beanName;
44 | private final String daoName;
45 |
46 | public JavaGenerator(@NotNull Project project,
47 | @NotNull SqlElement sqlElement, @NotNull String qualifiedName) {
48 | super(project, sqlElement);
49 | int lastIndex = qualifiedName.lastIndexOf(".");
50 | this.packageName = lastIndex < 0 ? "" : qualifiedName.substring(0, lastIndex);
51 | this.daoName = qualifiedName.substring(lastIndex + 1, qualifiedName.length());
52 | this.beanName = daoName.substring(0, daoName.length() - 3);
53 | }
54 |
55 | /**
56 | * {@inheritDoc}
57 | * @return psi class
58 | */
59 | @Nullable
60 | @Override
61 | public Pair generate() {
62 | VirtualFile dirVirtualFile = moduleSetting.getJavaSources().get(0);
63 | PsiDirectory baseDir = PsiManager.getInstance(project).findDirectory(dirVirtualFile);
64 | final PsiDirectory generateDir = createOrFindDirectory(baseDir);
65 |
66 | return ApplicationManager.getApplication().runWriteAction(new Computable>() {
67 | @Override
68 | public Pair compute() {
69 | final PsiClass daoClass = CreateFromUsageUtils.createClass(CreateClassKind.INTERFACE,
70 | generateDir, daoName, generateDir.getManager(), generateDir, null, null);
71 |
72 | if (daoClass == null) {
73 | return null;
74 | }
75 | PsiClass beanClass = CreateClassUtil.createClassFromCustomTemplate(
76 | generateDir, moduleSetting.getModule(), beanName, DEFAULT_CLASS_TEMPLATE);
77 | if (beanClass == null) {
78 | return null;
79 | }
80 | generateMethods(daoClass, beanClass);
81 | EditorService.getInstance(project).scrollTo(daoClass);
82 | return Pair.create(daoClass, beanClass);
83 | }
84 | });
85 | }
86 |
87 | /**
88 | * generate common mapper method
89 | * @param daoClass dao class
90 | * @param beanClass bean class
91 | */
92 | private void generateMethods(@NotNull final PsiClass daoClass, @NotNull final PsiClass beanClass) {
93 | WriteCommandAction.runWriteCommandAction(project, new Runnable() {
94 | @Override
95 | public void run() {
96 |
97 | PsiElementFactory elementFactory = JavaService.getInstance(project).elementFactory;
98 |
99 | PsiClass javaList = JavaService.getInstance(project).findClass("java.util.List", GlobalSearchScope.allScope(project));
100 | if (javaList != null) {
101 | PsiImportStatement importStatement = elementFactory.createImportStatement(javaList);
102 | //noinspection ConstantConditions
103 | ((PsiJavaFile) daoClass.getParent()).getImportList().add(importStatement);
104 | }
105 |
106 | String methodStr = String.format("int insert(%s bean);", beanClass.getName());
107 | PsiMethod insertMethod = elementFactory.createMethodFromText(methodStr, null);
108 | daoClass.add(insertMethod);
109 |
110 | methodStr = String.format("int delete(%s bean);", beanClass.getName());
111 | PsiMethod deleteMethod = elementFactory.createMethodFromText(methodStr, null);
112 | daoClass.add(deleteMethod);
113 |
114 | methodStr = String.format("%s selectOne(%s bean);", beanClass.getName(), beanClass.getName());
115 | PsiMethod selectOneMethod = elementFactory.createMethodFromText(methodStr, null);
116 | daoClass.add(selectOneMethod);
117 |
118 | methodStr = String.format("List<%s> selectList(%s bean);", beanClass.getName(), beanClass.getName());
119 | PsiMethod selectListMethod = elementFactory.createMethodFromText(methodStr, null);
120 | daoClass.add(selectListMethod);
121 |
122 | CodeStyleManager.getInstance(project).reformat(daoClass);
123 | }
124 | });
125 | }
126 |
127 | /**
128 | * create or find directory with given base dir
129 | * @param baseDir class path based dir
130 | * @return psi directory
131 | */
132 | private PsiDirectory createOrFindDirectory(final PsiDirectory baseDir) {
133 | return ApplicationManager.getApplication().runWriteAction(new Computable() {
134 | @Override
135 | public PsiDirectory compute() {
136 | PsiDirectory directory = baseDir;
137 | for (String path : packageName.split("\\.")) {
138 | PsiDirectory subDirectory = directory.findSubdirectory(path);
139 | if (subDirectory == null) {
140 | subDirectory = directory.createSubdirectory(path);
141 | }
142 | directory = subDirectory;
143 | }
144 | return directory;
145 | }
146 | });
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/generator/XmlGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.generator;
5 |
6 | import com.intellij.openapi.application.ApplicationManager;
7 | import com.intellij.openapi.command.WriteCommandAction;
8 | import com.intellij.openapi.project.Project;
9 | import com.intellij.openapi.util.Computable;
10 | import com.intellij.openapi.vfs.VirtualFile;
11 | import com.intellij.psi.PsiClass;
12 | import com.intellij.psi.PsiDirectory;
13 | import com.intellij.psi.PsiManager;
14 | import com.intellij.psi.XmlElementFactory;
15 | import com.intellij.psi.codeStyle.CodeStyleManager;
16 | import com.intellij.psi.xml.XmlFile;
17 | import com.intellij.psi.xml.XmlTag;
18 | import com.intellij.sql.psi.SqlElement;
19 | import org.jetbrains.annotations.NotNull;
20 | import org.jetbrains.annotations.Nullable;
21 | import org.qunar.plugin.mybatis.ui.CreateMapperXmlDialog;
22 |
23 | /**
24 | * generate mapper sql xml
25 | * deprecated, replaced by XmlVelocityGenerator
26 | *
27 | *
28 | * @see XmlVelocityGenerator
29 | *
30 | * Author: jianyu.lin
31 | * Date: 2016/12/22 Time: 下午2:59
32 | */
33 | @Deprecated @SuppressWarnings("unused")
34 | public class XmlGenerator extends AbstractGenerator {
35 |
36 | @NotNull
37 | private final PsiClass mapperClass;
38 | @NotNull
39 | private final String fileName;
40 | @NotNull
41 | private final String dirPath;
42 |
43 | public XmlGenerator(@NotNull Project project, @NotNull PsiClass mapperClass,
44 | @NotNull SqlElement sqlElement, @NotNull String relatedPath) {
45 | super(project, sqlElement);
46 | this.mapperClass = mapperClass;
47 | relatedPath = relatedPath.startsWith("/") ? relatedPath.substring(1, relatedPath.length()) :relatedPath;
48 | int lastIndex = relatedPath.lastIndexOf("/");
49 | this.dirPath = lastIndex < 0 ? "" : relatedPath.substring(0, lastIndex);
50 | this.fileName = relatedPath.substring(lastIndex + 1, relatedPath.length());
51 | }
52 |
53 | /**
54 | * {@inheritDoc}
55 | * @return psi xml
56 | */
57 | @Nullable
58 | @Override
59 | public XmlFile generate() {
60 | VirtualFile dirVirtualFile = moduleSetting.getResourceSources().get(0);
61 | PsiDirectory baseDir = PsiManager.getInstance(project).findDirectory(dirVirtualFile);
62 | final PsiDirectory generateDir = createOrFindDirectory(baseDir);
63 |
64 | return ApplicationManager.getApplication().runWriteAction(new Computable() {
65 | @Override
66 | public XmlFile compute() {
67 | CreateMapperXmlDialog dialog = new CreateMapperXmlDialog(project, mapperClass);
68 | XmlFile xmlFile = (XmlFile) dialog.generateMapperFile(fileName + ".xml");
69 | xmlFile = (XmlFile) generateDir.add(xmlFile);
70 | generateStatement(xmlFile);
71 | return xmlFile;
72 | }
73 | });
74 | }
75 |
76 | /**
77 | * generate mapper statement
78 | * @param xmlFile mapper xml file
79 | */
80 | private void generateStatement(final XmlFile xmlFile) {
81 | WriteCommandAction.runWriteCommandAction(project, new Runnable() {
82 | @Override
83 | public void run() {
84 | XmlTag rootTag = xmlFile.getRootTag();
85 | if (rootTag == null) return;
86 |
87 | @SuppressWarnings("ConstantConditions")
88 | String qualifiedBeanName = mapperClass.getQualifiedName().substring(0, mapperClass.getName().length() - 3);
89 |
90 | String sql = String.format(
91 | "", qualifiedBeanName, myCreateTableDdl.getName());
94 | XmlTag selectListTag = XmlElementFactory.getInstance(project).createTagFromText(sql);
95 | rootTag.add(selectListTag);
96 |
97 | sql = String.format(
98 | "\n" +
99 | " DELETE FROM %s WHERE id = #{id}\n" +
100 | " ", qualifiedBeanName, myCreateTableDdl.getName());
101 | XmlTag deleteTag = XmlElementFactory.getInstance(project).createTagFromText(sql);
102 | rootTag.add(deleteTag);
103 |
104 | sql = String.format(
105 | "\n" +
106 | " INSERT INTO %s(" +
107 | ")\n" +
108 | " ", qualifiedBeanName, myCreateTableDdl.getName());
109 | XmlTag insertOne = XmlElementFactory.getInstance(project).createTagFromText(sql);
110 | rootTag.add(insertOne);
111 |
112 | CodeStyleManager.getInstance(project).reformat(xmlFile.getRootTag());
113 | }
114 | });
115 | }
116 |
117 | /**
118 | * create or find directory with given base dir
119 | * @param baseDir class path based dir
120 | * @return psi directory
121 | */
122 | private PsiDirectory createOrFindDirectory(final PsiDirectory baseDir) {
123 | return ApplicationManager.getApplication().runWriteAction(new Computable() {
124 | @Override
125 | public PsiDirectory compute() {
126 | PsiDirectory directory = baseDir;
127 | for (String path : dirPath.split("/")) {
128 | PsiDirectory subDirectory = directory.findSubdirectory(path);
129 | if (subDirectory == null) {
130 | subDirectory = directory.createSubdirectory(path);
131 | }
132 | directory = subDirectory;
133 | }
134 | return directory;
135 | }
136 | });
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/inspection/MybatisMapperInspection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.inspection;
5 |
6 | import com.google.common.collect.Lists;
7 | import com.intellij.codeInspection.InspectionManager;
8 | import com.intellij.codeInspection.LocalInspectionTool;
9 | import com.intellij.codeInspection.ProblemDescriptor;
10 | import com.intellij.psi.PsiFile;
11 | import org.jetbrains.annotations.NotNull;
12 | import org.jetbrains.annotations.Nullable;
13 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
14 | import org.qunar.plugin.mybatis.util.DomElements;
15 | import org.qunar.plugin.mybatis.util.MapperConfHolder;
16 | import org.qunar.plugin.util.Inspections;
17 |
18 | import java.util.List;
19 |
20 | /**
21 | * mybatis mapper xml inspection
22 | *
23 | * Author: jianyu.lin
24 | * Date: 2016/11/22 Time: 下午8:13
25 | */
26 | public class MybatisMapperInspection extends LocalInspectionTool {
27 |
28 | /**
29 | * valid config file
30 | * @param file config file
31 | * @param manager inspection manager
32 | * @param isOnTheFly the error show at the end of line
33 | * @return potential problems
34 | */
35 | @Nullable
36 | @Override
37 | public ProblemDescriptor[] checkFile(@NotNull PsiFile file,
38 | @NotNull InspectionManager manager, boolean isOnTheFly) {
39 | if (!(DomElements.isMapperXmlFile(file))) {
40 | return null;
41 | }
42 | Mapper mapper = MapperConfHolder.INSTANCE.getDomElement(file);
43 | if (mapper == null || mapper.getNamespace() == null) {
44 | return null;
45 | }
46 |
47 | List allProblems = Lists.newArrayList();
48 | // validate namespace attribute
49 | allProblems.addAll(Inspections.buildPsiClassProblems(manager, mapper.getNamespace()));
50 | // validate mapper statement nodes
51 | allProblems.addAll(DomElements.checkMapperDomElement(manager, mapper));
52 | return allProblems.toArray(new ProblemDescriptor[allProblems.size()]);
53 | }
54 | }
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/inspection/config/AbstractConfigInspection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.inspection.config;
5 |
6 | import com.intellij.codeInspection.InspectionManager;
7 | import com.intellij.codeInspection.LocalInspectionTool;
8 | import com.intellij.codeInspection.ProblemDescriptor;
9 | import com.intellij.psi.PsiFile;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.jetbrains.annotations.Nullable;
12 | import org.qunar.plugin.mybatis.bean.config.Configuration;
13 | import org.qunar.plugin.mybatis.util.ConfigConfHolder;
14 | import org.qunar.plugin.mybatis.util.DomElements;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * super class of configuration node inspection
20 | *
21 | * Author: jianyu.lin
22 | * Date: 2016/12/19 Time: 下午6:52
23 | */
24 | abstract class AbstractConfigInspection extends LocalInspectionTool {
25 |
26 | /**
27 | * valid config file
28 | * @param file config file
29 | * @param manager inspection manager
30 | * @param isOnTheFly the error show at the end of line
31 | * @return potential problems
32 | */
33 | @Nullable
34 | @Override
35 | public ProblemDescriptor[] checkFile(@NotNull PsiFile file,
36 | @NotNull InspectionManager manager, boolean isOnTheFly) {
37 | if (!DomElements.isConfigurationXmlFile(file)) {
38 | return null;
39 | }
40 | Configuration configuration = ConfigConfHolder.INSTANCE.getDomElement(file);
41 | if (configuration == null) {
42 | return null;
43 | }
44 | List allProblems = buildProblems(manager, configuration);
45 | return allProblems.toArray(new ProblemDescriptor[allProblems.size()]);
46 | }
47 |
48 | /**
49 | * build problems
50 | * @param manager manager
51 | * @param configuration config dom
52 | * @return problems
53 | */
54 | @NotNull
55 | protected abstract List buildProblems(@NotNull InspectionManager manager,
56 | @NotNull Configuration configuration);
57 | }
58 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/inspection/config/MappersInspection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.inspection.config;
5 |
6 | import com.google.common.collect.Lists;
7 | import com.intellij.codeInspection.InspectionManager;
8 | import com.intellij.codeInspection.ProblemDescriptor;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.qunar.plugin.mybatis.bean.config.Configuration;
11 | import org.qunar.plugin.mybatis.util.domchecker.MappersChecker;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * mybatis configuration xml inspection
17 | *
18 | * Author: jianyu.lin
19 | * Date: 2016/11/22 Time: 下午8:13
20 | */
21 | public class MappersInspection extends AbstractConfigInspection {
22 |
23 | /**
24 | * {@inheritDoc}
25 | * @param manager manager
26 | * @param configuration config dom
27 | * @return problems
28 | */
29 | @NotNull
30 | @Override
31 | protected List buildProblems(@NotNull InspectionManager manager,
32 | @NotNull Configuration configuration) {
33 | return new MappersChecker().check(manager, Lists.newArrayList(configuration.getMappers()));
34 | }
35 | }
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/inspection/config/TypeAliasesInspection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.inspection.config;
5 |
6 | import com.google.common.collect.Lists;
7 | import com.intellij.codeInspection.InspectionManager;
8 | import com.intellij.codeInspection.ProblemDescriptor;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.qunar.plugin.mybatis.bean.config.Configuration;
11 | import org.qunar.plugin.mybatis.util.domchecker.TypeAliasesChecker;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * mybatis configuration xml inspection
17 | *
18 | * Author: jianyu.lin
19 | * Date: 2016/11/22 Time: 下午8:13
20 | */
21 | public class TypeAliasesInspection extends AbstractConfigInspection {
22 |
23 | /**
24 | * {@inheritDoc}
25 | * @param manager manager
26 | * @param configuration config dom
27 | * @return problems
28 | */
29 | @NotNull
30 | @Override
31 | protected List buildProblems(@NotNull InspectionManager manager,
32 | @NotNull Configuration configuration) {
33 | return new TypeAliasesChecker().check(manager, Lists.newArrayList(configuration.getTypeAliases()));
34 | }
35 | }
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/intention/MapperGenerateIntention.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.intention;
5 |
6 | import com.intellij.codeInsight.intention.IntentionAction;
7 | import com.intellij.openapi.application.ApplicationManager;
8 | import com.intellij.openapi.application.Result;
9 | import com.intellij.openapi.command.WriteCommandAction;
10 | import com.intellij.openapi.editor.Editor;
11 | import com.intellij.openapi.module.Module;
12 | import com.intellij.openapi.module.ModuleUtil;
13 | import com.intellij.openapi.project.Project;
14 | import com.intellij.psi.PsiClass;
15 | import com.intellij.psi.PsiElement;
16 | import com.intellij.psi.PsiFile;
17 | import com.intellij.psi.PsiIdentifier;
18 | import com.intellij.psi.PsiJavaFile;
19 | import com.intellij.util.IncorrectOperationException;
20 | import org.jetbrains.annotations.Nls;
21 | import org.jetbrains.annotations.NotNull;
22 | import org.jetbrains.annotations.Nullable;
23 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
24 | import org.qunar.plugin.mybatis.ui.CreateMapperXmlDialog;
25 | import org.qunar.plugin.mybatis.util.MapperConfHolder;
26 | import org.qunar.plugin.service.EditorService;
27 |
28 | /**
29 | * generate new mapper xml
30 | *
31 | * Author: jianyu.lin
32 | * Date: 2016/12/1 Time: 下午7:26
33 | */
34 | public class MapperGenerateIntention implements IntentionAction {
35 |
36 | @Nls
37 | @NotNull
38 | @Override
39 | public String getText() {
40 | return getFamilyName();
41 | }
42 |
43 | @Nls
44 | @NotNull
45 | @Override
46 | public String getFamilyName() {
47 | return "Generate Mybatis Mapper Xml";
48 | }
49 |
50 | @Override
51 | public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
52 | return getCurrentClass(editor, file) != null;
53 | }
54 |
55 | @Override
56 | public void invoke(@NotNull final Project project, Editor editor, final PsiFile file) throws IncorrectOperationException {
57 | final PsiClass psiClass = getCurrentClass(editor, file);
58 | if (psiClass == null) {
59 | return;
60 | }
61 | new WriteCommandAction(project) {
62 | @Override
63 | protected void run(@NotNull Result result) throws Throwable {
64 | Module module = ModuleUtil.findModuleForPsiElement(file);
65 | if (module == null) return;
66 | ApplicationManager.getApplication().runWriteAction(new Runnable() {
67 | @Override
68 | public void run() {
69 | CreateMapperXmlDialog dialog = new CreateMapperXmlDialog(project, psiClass);
70 | if (dialog.showAndGet()) {
71 | PsiFile mapperFile = dialog.getNewMapperFile();
72 | if (mapperFile == null) return;
73 | Mapper mapperDom = MapperConfHolder.INSTANCE.getDomElement(mapperFile);
74 | if (mapperDom == null) return;
75 | EditorService.getInstance(project).scrollTo(mapperDom.getXmlTag());
76 | }
77 | }
78 | });
79 | }
80 | }.execute();
81 | }
82 |
83 | @Override
84 | public boolean startInWriteAction() {
85 | return false;
86 | }
87 |
88 | /**
89 | * get the caret point method
90 | * @param editor current editor
91 | * @param file current file
92 | * @return psi method
93 | */
94 | @Nullable
95 | private PsiClass getCurrentClass(@Nullable Editor editor, @Nullable PsiFile file) {
96 | if (editor == null || file == null
97 | || !(file instanceof PsiJavaFile)) {
98 | return null;
99 | }
100 | PsiJavaFile javaFile = (PsiJavaFile) file;
101 | int offset = editor.getCaretModel().getOffset();
102 | PsiElement psiElement = javaFile.findElementAt(offset);
103 | if (!(psiElement instanceof PsiIdentifier)
104 | || !(psiElement.getParent() instanceof PsiClass)) {
105 | return null;
106 | }
107 | if (javaFile.getClasses().length == 0) {
108 | return null;
109 | }
110 | PsiClass psiClass = javaFile.getClasses()[0];
111 | if (!psiClass.isInterface()
112 | && !MapperConfHolder.INSTANCE.getMapperDomElements(psiClass).isEmpty()) {
113 | return null;
114 | }
115 | return psiClass;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/intention/statement/DeleteGenerateIntention.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.intention.statement;
5 |
6 | import com.google.common.collect.Sets;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
10 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
11 |
12 | import java.util.Set;
13 |
14 | /**
15 | * generate insert node in xml
16 | *
17 | * Author: jianyu.lin
18 | * Date: 2016/12/1 Time: 下午8:14
19 | */
20 | public class DeleteGenerateIntention extends StatementGenerateIntention {
21 |
22 | private static final Set KEYWORDS = Sets.newHashSet(
23 | "delete", "remove", "del"
24 | );
25 | @NotNull
26 | @Override
27 | protected Statement generateStatement(@NotNull Mapper mapperDom) {
28 | return mapperDom.addDelete(mapperDom.getDeletes().size());
29 | }
30 |
31 | @NotNull
32 | @Override
33 | protected Set getSubGeneratorKeywords() {
34 | return KEYWORDS;
35 | }
36 |
37 | @Nls
38 | @NotNull
39 | @Override
40 | public String getFamilyName() {
41 | return "Generate Mapper Delete Statement";
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/intention/statement/InsertGenerateIntention.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.intention.statement;
5 |
6 | import com.google.common.collect.Sets;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
10 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
11 |
12 | import java.util.Set;
13 |
14 | /**
15 | * generate insert node in xml
16 | *
17 | * Author: jianyu.lin
18 | * Date: 2016/12/1 Time: 下午8:14
19 | */
20 | public class InsertGenerateIntention extends StatementGenerateIntention {
21 |
22 | private static final Set KEYWORDS = Sets.newHashSet(
23 | "insert", "add", "append", "addictive"
24 | );
25 |
26 | @NotNull
27 | @Override
28 | protected Statement generateStatement(@NotNull Mapper mapperDom) {
29 | return mapperDom.addInsert(mapperDom.getInserts().size());
30 | }
31 |
32 | @NotNull
33 | @Override
34 | protected Set getSubGeneratorKeywords() {
35 | return KEYWORDS;
36 | }
37 |
38 | @Nls
39 | @NotNull
40 | @Override
41 | public String getFamilyName() {
42 | return "Generate Mapper Insert Statement";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/intention/statement/SelectGenerateIntention.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.intention.statement;
5 |
6 | import com.google.common.collect.Sets;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
10 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
11 |
12 | import java.util.Set;
13 |
14 | /**
15 | * generate select node in xml
16 | *
17 | * Author: jianyu.lin
18 | * Date: 2016/12/1 Time: 下午8:14
19 | */
20 | public class SelectGenerateIntention extends StatementGenerateIntention {
21 |
22 | private static final Set KEYWORDS = Sets.newHashSet(
23 | "select", "get", "find", "query", "count", "sort"
24 | );
25 |
26 | @NotNull
27 | @Override
28 | protected Statement generateStatement(@NotNull Mapper mapperDom) {
29 | return mapperDom.addSelect(mapperDom.getSelects().size());
30 | }
31 |
32 | @NotNull
33 | @Override
34 | protected Set getSubGeneratorKeywords() {
35 | return KEYWORDS;
36 | }
37 |
38 | @Nls
39 | @NotNull
40 | @Override
41 | public String getFamilyName() {
42 | return "Generate Mapper Select Statement";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/intention/statement/StatementGenerateIntention.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.intention.statement;
5 |
6 | import com.intellij.codeInsight.intention.IntentionAction;
7 | import com.intellij.openapi.application.ApplicationManager;
8 | import com.intellij.openapi.editor.Editor;
9 | import com.intellij.openapi.project.Project;
10 | import com.intellij.psi.PsiElement;
11 | import com.intellij.psi.PsiFile;
12 | import com.intellij.psi.PsiIdentifier;
13 | import com.intellij.psi.PsiJavaFile;
14 | import com.intellij.psi.PsiMethod;
15 | import com.intellij.psi.xml.XmlTag;
16 | import com.intellij.util.IncorrectOperationException;
17 | import org.jetbrains.annotations.Nls;
18 | import org.jetbrains.annotations.NotNull;
19 | import org.jetbrains.annotations.Nullable;
20 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
21 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
22 | import org.qunar.plugin.mybatis.util.DomElements;
23 | import org.qunar.plugin.mybatis.util.MapperConfHolder;
24 | import org.qunar.plugin.service.EditorService;
25 | import org.qunar.plugin.util.CodeFormatter;
26 |
27 | import java.util.Collection;
28 | import java.util.Set;
29 |
30 | /**
31 | * generate statement int mapping mapper xml
32 | *
33 | * Author: jianyu.lin
34 | * Date: 2016/12/1 Time: 下午7:26
35 | */
36 | abstract class StatementGenerateIntention implements IntentionAction {
37 |
38 | /**
39 | * return same as family name
40 | * @return family name
41 | */
42 | @Nls
43 | @NotNull
44 | @Override
45 | public String getText() {
46 | return getFamilyName();
47 | }
48 |
49 | /**
50 | * check method reference to mapper xml
51 | * @param project current project
52 | * @param editor current editor
53 | * @param file current file
54 | * @return boolean
55 | */
56 | @Override
57 | public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
58 |
59 | PsiMethod method = getCurrentMethod(editor, file);
60 | if (method == null || method.getContainingClass() == null) {
61 | return false;
62 | }
63 | @SuppressWarnings("ConstantConditions")
64 | Collection mapperDomList = MapperConfHolder.INSTANCE.getMapperDomElements(method.getContainingClass());
65 | if (mapperDomList.size() != 1) {
66 | return false;
67 | }
68 | Mapper mapperDom = mapperDomList.iterator().next();
69 | for (Statement statement : DomElements.collectStatements(mapperDom)) {
70 | if (statement.getId().getValue() == method) {
71 | return false;
72 | }
73 | }
74 | return checkKeywords(method.getName());
75 | }
76 |
77 | /**
78 | * do generate action
79 | * @param project current project
80 | * @param editor current editor
81 | * @param file current file
82 | * @throws IncorrectOperationException any
83 | */
84 | @Override
85 | public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
86 | PsiMethod method = getCurrentMethod(editor, file);
87 | if (method == null || method.getContainingClass() == null) {
88 | return;
89 | }
90 | @SuppressWarnings("ConstantConditions")
91 | Collection mapperDomList = MapperConfHolder.INSTANCE.getMapperDomElements(method.getContainingClass());
92 | if (mapperDomList.size() != 1) {
93 | return;
94 | }
95 | generateStatement(project, method, mapperDomList.iterator().next());
96 | }
97 |
98 | @Override
99 | public boolean startInWriteAction() {
100 | return false;
101 | }
102 |
103 | /**
104 | * check intention key words
105 | * @param methodName current method name
106 | * @return boolean
107 | */
108 | private boolean checkKeywords(String methodName) {
109 | Set keywords = getSubGeneratorKeywords();
110 | for (String keyword : keywords) {
111 | if (methodName.toLowerCase().contains(keyword.toLowerCase())) {
112 | return true;
113 | }
114 | }
115 | return false;
116 | }
117 |
118 | /**
119 | * get the caret point method
120 | * @param editor current editor
121 | * @param file current file
122 | * @return psi method
123 | */
124 | @Nullable
125 | private PsiMethod getCurrentMethod(@Nullable Editor editor, @Nullable PsiFile file) {
126 | if (editor == null || file == null
127 | || !(file instanceof PsiJavaFile)) {
128 | return null;
129 | }
130 | PsiJavaFile javaFile = (PsiJavaFile) file;
131 | int offset = editor.getCaretModel().getOffset();
132 | PsiElement psiElement = javaFile.findElementAt(offset);
133 | if (!(psiElement instanceof PsiIdentifier)
134 | || !(psiElement.getParent() instanceof PsiMethod)) {
135 | return null;
136 | }
137 | return (PsiMethod) psiElement.getParent();
138 | }
139 |
140 | /**
141 | * generate statement in mapper xml
142 | * @param project current project
143 | * @param mapperDom mapper dom
144 | */
145 | private void generateStatement(@NotNull final Project project,
146 | @NotNull final PsiMethod method, @NotNull final Mapper mapperDom) {
147 | final XmlTag rootTag = mapperDom.getXmlTag();
148 | if (rootTag == null || mapperDom.getNamespace().getValue() == null) {
149 | return;
150 | }
151 | ApplicationManager.getApplication().runWriteAction(new Runnable() {
152 | @Override
153 | public void run() {
154 | // generate new statement
155 | Statement statement = generateStatement(mapperDom);
156 | statement.getId().setStringValue(method.getName());
157 | statement.setStringValue("\n");
158 | CodeFormatter.format(statement.getXmlTag());
159 | // navigate to new statement
160 | //noinspection ConstantConditions
161 | EditorService.getInstance(project).scrollTo(statement.getId().getXmlAttributeValue());
162 | }
163 | });
164 | }
165 |
166 | /**
167 | * generated dom element
168 | * @return new dom element
169 | */
170 | @NotNull
171 | protected abstract Statement generateStatement(@NotNull Mapper mapperDom);
172 |
173 | /**
174 | * get sub generator
175 | * @return key words
176 | */
177 | @NotNull
178 | protected abstract Set getSubGeneratorKeywords();
179 | }
180 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/intention/statement/UpdateGenerateIntention.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.intention.statement;
5 |
6 | import com.google.common.collect.Sets;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
10 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
11 |
12 | import java.util.Set;
13 |
14 | /**
15 | * generate insert node in xml
16 | *
17 | * Author: jianyu.lin
18 | * Date: 2016/12/1 Time: 下午8:14
19 | */
20 | public class UpdateGenerateIntention extends StatementGenerateIntention {
21 |
22 | private static final Set KEYWORDS = Sets.newHashSet(
23 | "update", "change"
24 | );
25 |
26 | @NotNull
27 | @Override
28 | protected Statement generateStatement(@NotNull Mapper mapperDom) {
29 | return mapperDom.addUpdate(mapperDom.getUpdates().size());
30 | }
31 |
32 | @NotNull
33 | @Override
34 | protected Set getSubGeneratorKeywords() {
35 | return KEYWORDS;
36 | }
37 |
38 | @Nls
39 | @NotNull
40 | @Override
41 | public String getFamilyName() {
42 | return "Generate Mapper Update Statement";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/linemarker/AbstractMapperMakerProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.linemarker;
5 |
6 | import com.google.common.collect.Lists;
7 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;
8 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;
9 | import com.intellij.psi.PsiElement;
10 | import com.intellij.psi.PsiMethod;
11 | import org.jetbrains.annotations.NotNull;
12 | import org.jetbrains.annotations.Nullable;
13 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
14 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
15 | import org.qunar.plugin.mybatis.util.DomElements;
16 | import org.qunar.plugin.util.XmlUtils;
17 |
18 | import java.util.Collection;
19 | import java.util.List;
20 |
21 | /**
22 | * mapper maker abstract super class
23 | *
24 | * Author: jianyu.lin
25 | * Date: 2016/11/25 Time: 下午10:19
26 | */
27 | abstract class AbstractMapperMakerProvider extends RelatedItemLineMarkerProvider {
28 |
29 | /**
30 | * one mapper xml deal only once
31 | * @param elements changed elements
32 | * @param result marker result
33 | * @param forNavigation navigation
34 | */
35 | @Override
36 | public void collectNavigationMarkers(@NotNull List elements,
37 | Collection super RelatedItemLineMarkerInfo> result, boolean forNavigation) {
38 | List myElements = elements.size() > 0 ? chooseElement(elements) : Lists.newArrayList();
39 | super.collectNavigationMarkers(myElements, result, forNavigation);
40 | }
41 |
42 | /**
43 | * filter duplicate elements request
44 | * @param elements changed elements
45 | * @return choose correct element to build markers
46 | */
47 | @NotNull
48 | protected abstract List chooseElement(@NotNull List elements);
49 |
50 | /**
51 | * build mapping method marks
52 | * @param mapperDom mapper dom
53 | * @return mark info list
54 | */
55 | List buildMethodLineMarkers(Mapper mapperDom) {
56 | List lineMarkerInfoList = Lists.newArrayList();
57 | for (Statement statement : DomElements.collectStatements(mapperDom)) {
58 | PsiMethod method = XmlUtils.getAttrValue(statement.getId());
59 | if (method == null || method.getNameIdentifier() == null) {
60 | continue;
61 | }
62 | RelatedItemLineMarkerInfo lineMarker = buildMethodLineMarker(statement, method);
63 | if (lineMarker != null) {
64 | lineMarkerInfoList.add(lineMarker);
65 | }
66 | }
67 | return lineMarkerInfoList;
68 | }
69 |
70 | /**
71 | * build single mapping method marks
72 | * @param statement sql statement
73 | * @return single line marker
74 | */
75 | @Nullable
76 | protected abstract RelatedItemLineMarkerInfo buildMethodLineMarker(@NotNull Statement statement,
77 | @NotNull PsiMethod method);
78 | }
79 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/linemarker/Java2XmlLineMarkerProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.linemarker;
5 |
6 | import com.google.common.collect.Lists;
7 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;
8 | import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
9 | import com.intellij.openapi.editor.markup.GutterIconRenderer;
10 | import com.intellij.psi.PsiClass;
11 | import com.intellij.psi.PsiDirectory;
12 | import com.intellij.psi.PsiElement;
13 | import com.intellij.psi.PsiFile;
14 | import com.intellij.psi.PsiJavaFile;
15 | import com.intellij.psi.PsiMethod;
16 | import com.intellij.psi.xml.XmlAttribute;
17 | import com.intellij.psi.xml.XmlAttributeValue;
18 | import org.jetbrains.annotations.NotNull;
19 | import org.jetbrains.annotations.Nullable;
20 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
21 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
22 | import org.qunar.plugin.mybatis.util.MapperConfHolder;
23 | import org.qunar.plugin.util.Icons;
24 |
25 | import java.util.Collection;
26 | import java.util.List;
27 |
28 | /**
29 | * navigate from java interface 2 mapper xml
30 | *
31 | * Author: jianyu.lin
32 | * Date: 2016/11/25 Time: 下午7:08
33 | */
34 | public class Java2XmlLineMarkerProvider extends AbstractMapperMakerProvider {
35 |
36 | /**
37 | * {@inheritDoc}
38 | * @param elements changed elements
39 | * @return psiClass
40 | */
41 | @NotNull
42 | @Override
43 | protected List chooseElement(@NotNull List elements) {
44 | for (PsiElement element : elements) {
45 | if (element instanceof PsiClass) {
46 | return Lists.newArrayList(element);
47 | }
48 | }
49 | return Lists.newArrayList();
50 | }
51 |
52 | @Override
53 | protected void collectNavigationMarkers(@NotNull PsiElement element,
54 | Collection super RelatedItemLineMarkerInfo> result) {
55 | PsiClass mapperClass = getCurrentPsiClass(element);
56 | if (mapperClass == null) {
57 | return;
58 | }
59 | Collection mapperDomElements = MapperConfHolder.INSTANCE.getMapperDomElements(mapperClass);
60 |
61 | for (Mapper mapperDom : mapperDomElements) {
62 | // add interface 2 mapper
63 | if (mapperDom.getNamespace().getXmlAttribute() != null) {
64 | result.add(buildInterfaceLineMarker(mapperClass, mapperDom));
65 | }
66 | // add method 2 statement
67 | result.addAll(buildMethodLineMarkers(mapperDom));
68 | }
69 | }
70 |
71 | /**
72 | * get psi class by current element
73 | * @param element element
74 | * @return psi class
75 | */
76 | @Nullable
77 | private PsiClass getCurrentPsiClass(PsiElement element) {
78 | PsiElement tempElement = element;
79 | while (tempElement != null && !(tempElement instanceof PsiDirectory)) {
80 | if (tempElement instanceof PsiClass) {
81 | return (PsiClass) tempElement;
82 | }
83 | if (tempElement instanceof PsiJavaFile) {
84 | PsiClass[] psiClasses = ((PsiJavaFile) tempElement).getClasses();
85 | if (psiClasses.length > 0) {
86 | return psiClasses[0];
87 | }
88 | }
89 | tempElement = tempElement.getParent();
90 | }
91 | return null;
92 | }
93 |
94 | /**
95 | * build interface line marker
96 | * @param mapperClass mapper class
97 | * @param mapperDom mapper dom element
98 | * @return line marker
99 | */
100 | @SuppressWarnings("ConstantConditions")
101 | private RelatedItemLineMarkerInfo buildInterfaceLineMarker(@NotNull PsiClass mapperClass,
102 | @NotNull Mapper mapperDom) {
103 | // marker element
104 | PsiElement markElement = mapperClass.getNameIdentifier() == null ? mapperClass : mapperClass.getNameIdentifier();
105 | // target element
106 | XmlAttribute attribute = mapperDom.getNamespace().getXmlAttribute();
107 | PsiElement targetElement = attribute.getValueElement() == null ? attribute : attribute.getValueElement();
108 | // tooltip text
109 | PsiFile mapperFile = mapperDom.getXmlElement().getContainingFile();
110 | String tooltipText = "Navigate to mapper xml" + (mapperFile == null ? "" : ": " + mapperFile.getName());
111 | // build line marker
112 | return NavigationGutterIconBuilder.create(Icons.MYBATIS_2_XML_ICON)
113 | .setTarget(targetElement)
114 | .setTooltipText(tooltipText)
115 | .createLineMarkerInfo(markElement);
116 | }
117 |
118 | /**
119 | * {@inheritDoc}
120 | * @param statement sql statement
121 | * @return marker
122 | */
123 | @Override
124 | @Nullable
125 | protected RelatedItemLineMarkerInfo buildMethodLineMarker(@NotNull Statement statement,
126 | @NotNull PsiMethod method) {
127 | @SuppressWarnings("ConstantConditions")
128 | XmlAttributeValue idAttrValue = statement.getXmlTag().getAttribute("id").getValueElement();
129 | String statementDesc = String.format("<%s id="%s" .../>", statement.getXmlTag().getName(), method.getName());
130 | NavigationGutterIconBuilder builder =
131 | NavigationGutterIconBuilder.create(Icons.MYBATIS_2_XML_ICON).setTarget(idAttrValue)
132 | .setAlignment(GutterIconRenderer.Alignment.CENTER)
133 | .setTooltipText("Navigate to mapper xml statement: " + statementDesc);
134 | PsiElement markElement = method.getNameIdentifier() == null ? method : method.getNameIdentifier();
135 | return builder.createLineMarkerInfo(markElement);
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/linemarker/Xml2JavaLineMarkerProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.linemarker;
5 |
6 | import com.google.common.collect.Lists;
7 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;
8 | import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
9 | import com.intellij.psi.PsiClass;
10 | import com.intellij.psi.PsiElement;
11 | import com.intellij.psi.PsiMethod;
12 | import com.intellij.psi.xml.XmlTag;
13 | import org.jetbrains.annotations.NotNull;
14 | import org.jetbrains.annotations.Nullable;
15 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
16 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
17 | import org.qunar.plugin.mybatis.util.DomElements;
18 | import org.qunar.plugin.mybatis.util.MapperConfHolder;
19 | import org.qunar.plugin.util.Icons;
20 |
21 | import java.util.Collection;
22 | import java.util.List;
23 |
24 | /**
25 | * navigate from mapper xml 2 java interface
26 | *
27 | * Author: jianyu.lin
28 | * Date: 2016/11/25 Time: 下午7:08
29 | */
30 | public class Xml2JavaLineMarkerProvider extends AbstractMapperMakerProvider {
31 |
32 | /**
33 | * {@inheritDoc}
34 | * @param elements changed elements
35 | * @return root tag
36 | */
37 | @NotNull
38 | @Override
39 | protected List chooseElement(@NotNull List elements) {
40 | for (PsiElement element : elements) {
41 | if (element instanceof XmlTag) {
42 | XmlTag xmlTag = (XmlTag) element;
43 | if (MapperConfHolder.INSTANCE.rootTagName.contains(xmlTag.getName())) {
44 | return Lists.newArrayList(element);
45 | }
46 | }
47 | }
48 | return Lists.newArrayList();
49 | }
50 |
51 | @Override
52 | protected void collectNavigationMarkers(@NotNull PsiElement element,
53 | Collection super RelatedItemLineMarkerInfo> result) {
54 | if (!DomElements.isMapperXmlFile(element.getContainingFile())) {
55 | return;
56 | }
57 |
58 | Mapper mapperDom = MapperConfHolder.INSTANCE.getDomElement(element.getContainingFile());
59 | if (mapperDom == null || mapperDom.getNamespace() == null
60 | || mapperDom.getNamespace().getValue() == null) {
61 | return;
62 | }
63 |
64 | // mark mapping mapper tag
65 | PsiClass mapperClass = mapperDom.getNamespace().getValue();
66 | NavigationGutterIconBuilder builder =
67 | NavigationGutterIconBuilder.create(Icons.MYBATIS_2_JAVA_ICON)
68 | .setTarget(mapperClass).setTooltipText("Navigate to mapper java interface: " + mapperClass.getName());
69 | result.add(builder.createLineMarkerInfo(mapperDom.getXmlTag()));
70 |
71 | // mark mapping statement tag
72 | result.addAll(buildMethodLineMarkers(mapperDom));
73 | }
74 |
75 | /**
76 | * {@inheritDoc}
77 | * @param statement sql statement
78 | * @return marker
79 | */
80 | @Nullable
81 | @Override
82 | protected RelatedItemLineMarkerInfo buildMethodLineMarker(@NotNull Statement statement,
83 | @NotNull PsiMethod method) {
84 | NavigationGutterIconBuilder builder =
85 | NavigationGutterIconBuilder.create(Icons.MYBATIS_2_JAVA_ICON).setTarget(method.getNameIdentifier())
86 | .setTooltipText("Navigate to mapper java method: " + method.getName());
87 | return builder.createLineMarkerInfo(statement.getXmlTag());
88 | }
89 |
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/query/MapperXmlInheritorsSearch.java:
--------------------------------------------------------------------------------
1 | package org.qunar.plugin.mybatis.query;
2 |
3 | import com.intellij.openapi.application.ApplicationManager;
4 | import com.intellij.openapi.util.Computable;
5 | import com.intellij.psi.PsiClass;
6 | import com.intellij.psi.PsiElement;
7 | import com.intellij.psi.PsiMethod;
8 | import com.intellij.psi.search.searches.DefinitionsScopedSearch;
9 | import com.intellij.psi.xml.XmlAttribute;
10 | import com.intellij.psi.xml.XmlElement;
11 | import com.intellij.util.Processor;
12 | import com.intellij.util.QueryExecutor;
13 | import org.jetbrains.annotations.NotNull;
14 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
15 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
16 | import org.qunar.plugin.mybatis.util.DomElements;
17 | import org.qunar.plugin.mybatis.util.MapperConfHolder;
18 | import org.qunar.plugin.util.XmlUtils;
19 |
20 | import java.util.Collection;
21 | import java.util.List;
22 |
23 | /**
24 | * mark mapper xml to be the implementation of mapper class
25 | * can use 'implementation' key to navigate to xml
26 | *
27 | * author: jianyu.lin Date: 16-11-26.
28 | */
29 | public class MapperXmlInheritorsSearch implements QueryExecutor {
30 |
31 | /**
32 | * process inheritor between xml and interface
33 | *
34 | * @param queryParameters query parameters
35 | * @param consumer processor
36 | * @return result
37 | */
38 | @Override
39 | public boolean execute(@NotNull DefinitionsScopedSearch.SearchParameters queryParameters,
40 | @NotNull Processor consumer) {
41 | PsiElement element = queryParameters.getElement();
42 | //noinspection SimplifiableIfStatement
43 | if (!(element instanceof PsiClass) && !(element instanceof PsiMethod)) {
44 | return true;
45 | }
46 | return element instanceof PsiClass ?
47 | processClass((PsiClass) element, consumer) :
48 | processMethod((PsiMethod) element, consumer);
49 | }
50 |
51 | /**
52 | * process class inheritors
53 | *
54 | * @param mapperClass mapper class
55 | * @param consumer processor
56 | * @return result
57 | */
58 | @SuppressWarnings("SameReturnValue")
59 | private boolean processClass(@NotNull PsiClass mapperClass,
60 | @NotNull final Processor consumer) {
61 | Collection mapperDomElements = MapperConfHolder.INSTANCE.getMapperDomElements(mapperClass);
62 | for (final Mapper mapperDom : mapperDomElements) {
63 | if (mapperDom.getXmlElement() != null) {
64 | consumer.process(mapperDom.getXmlElement());
65 | }
66 | }
67 | return Boolean.TRUE;
68 | }
69 |
70 | /**
71 | * process method inheritors
72 | *
73 | * @param mapperMethod mapper method
74 | * @param consumer processor
75 | * @return result
76 | */
77 | @SuppressWarnings("SameReturnValue")
78 | private boolean processMethod(@NotNull final PsiMethod mapperMethod,
79 | @NotNull final Processor consumer) {
80 | return ApplicationManager.getApplication().runReadAction(new Computable() {
81 | @Override
82 | public Boolean compute() {
83 | if (mapperMethod.getContainingClass() == null) {
84 | return Boolean.TRUE;
85 | }
86 | Collection mapperDomElements = MapperConfHolder.INSTANCE
87 | .getMapperDomElements(mapperMethod.getContainingClass());
88 | for (final Mapper mapperDom : mapperDomElements) {
89 | if (mapperDom.getXmlElement() != null) {
90 | List statements = DomElements.collectStatements(mapperDom);
91 | for (final Statement statement : statements) {
92 | PsiMethod psiMethod = XmlUtils.getAttrValue(statement.getId());
93 | final XmlAttribute idAttr = statement.getXmlTag().getAttribute("id");
94 | if (psiMethod == mapperMethod && idAttr != null) {
95 | if (idAttr.getValueElement() != null) {
96 | consumer.process(idAttr.getValueElement());
97 | }
98 | }
99 | }
100 | }
101 | }
102 | return Boolean.TRUE;
103 | }
104 | });
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/reference/ClassPathRelatedFileReference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.reference;
5 |
6 | import com.intellij.psi.PsiElement;
7 | import com.intellij.psi.PsiElementResolveResult;
8 | import com.intellij.psi.PsiFile;
9 | import com.intellij.psi.PsiPolyVariantReference;
10 | import com.intellij.psi.PsiReferenceBase;
11 | import com.intellij.psi.ResolveResult;
12 | import com.intellij.psi.xml.XmlAttributeValue;
13 | import org.jetbrains.annotations.NotNull;
14 | import org.jetbrains.annotations.Nullable;
15 | import org.qunar.plugin.mybatis.converter.PathFileConverter;
16 |
17 | /**
18 | * classPath related file reference
19 | *
20 | * Author: jianyu.lin
21 | * Date: 2016/11/23 Time: 下午2:19
22 | */
23 | public class ClassPathRelatedFileReference extends PsiReferenceBase implements PsiPolyVariantReference {
24 |
25 | public ClassPathRelatedFileReference(@NotNull XmlAttributeValue element) {
26 | super(element);
27 | }
28 |
29 | @Nullable
30 | @Override
31 | public PsiElement resolve() {
32 | ResolveResult[] results = multiResolve(true);
33 | return results.length > 0 ? results[0].getElement() : null;
34 | }
35 |
36 | @NotNull
37 | @Override
38 | public Object[] getVariants() {
39 | return new Object[0];
40 | }
41 |
42 | @NotNull
43 | @Override
44 | public ResolveResult[] multiResolve(boolean incompleteCode) {
45 | PsiFile relatedFile = PathFileConverter.parseClassPathRelatedFile(myElement.getProject(), myElement.getValue());
46 | return relatedFile == null ? new ResolveResult[]{} :
47 | new ResolveResult[]{new PsiElementResolveResult(relatedFile.getOriginalElement())};
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/reference/MapperAttr2ResultMapReference.java:
--------------------------------------------------------------------------------
1 | package org.qunar.plugin.mybatis.reference;
2 |
3 | import com.intellij.psi.xml.XmlAttributeValue;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.qunar.plugin.mybatis.bean.IdDomElement;
6 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * mapper sql tag reference
12 | *
13 | * Author: jianyu.lin
14 | * Date: 16-11-27 Time: 下午1:57
15 | */
16 | public class MapperAttr2ResultMapReference extends MapperIdAttrRefXmlTagReference {
17 |
18 | public MapperAttr2ResultMapReference(@NotNull XmlAttributeValue resultMapAttrValue) {
19 | super(resultMapAttrValue);
20 | }
21 |
22 | @Override
23 | protected List extends IdDomElement> getIdDomElements(@NotNull Mapper mapperDom) {
24 | return mapperDom.getResultMaps();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/reference/MapperIdAttrRefXmlTagReference.java:
--------------------------------------------------------------------------------
1 | package org.qunar.plugin.mybatis.reference;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.intellij.codeInsight.lookup.LookupElement;
5 | import com.intellij.codeInsight.lookup.LookupElementBuilder;
6 | import com.intellij.psi.PsiElement;
7 | import com.intellij.psi.PsiReferenceBase;
8 | import com.intellij.psi.xml.XmlAttribute;
9 | import com.intellij.psi.xml.XmlAttributeValue;
10 | import org.apache.commons.lang.ObjectUtils;
11 | import org.apache.commons.lang.StringUtils;
12 | import org.jetbrains.annotations.NotNull;
13 | import org.jetbrains.annotations.Nullable;
14 | import org.qunar.plugin.mybatis.bean.IdDomElement;
15 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
16 | import org.qunar.plugin.service.DomParseService;
17 | import org.qunar.plugin.util.XmlUtils;
18 |
19 | import java.util.List;
20 |
21 | /**
22 | * mapper id attribute to id required tag reference
23 | *
24 | * Author: jianyu.lin
25 | * Date: 16-11-27 Time: 下午1:57
26 | */
27 | abstract class MapperIdAttrRefXmlTagReference extends PsiReferenceBase {
28 |
29 | MapperIdAttrRefXmlTagReference(@NotNull XmlAttributeValue resultMapAttrValue) {
30 | super(resultMapAttrValue);
31 | }
32 |
33 | @Nullable
34 | @Override
35 | public PsiElement resolve() {
36 | for (IdDomElement result : getIdDomElements()) {
37 | XmlAttribute resultMapIdAttr = result.getXmlTag().getAttribute("id");
38 | if (ObjectUtils.equals(XmlUtils.getAttrValue(result.getId()), myElement.getValue())
39 | && resultMapIdAttr != null) {
40 | return resultMapIdAttr.getValueElement();
41 | }
42 | }
43 | return null;
44 | }
45 |
46 | @NotNull
47 | @Override
48 | public Object[] getVariants() {
49 | List lookupElements = Lists.newArrayList();
50 | for (IdDomElement idDomElement : getIdDomElements()) {
51 | if (XmlUtils.getAttrValue(idDomElement.getId()) != null) {
52 | //noinspection ConstantConditions
53 | lookupElements.add(LookupElementBuilder.create(XmlUtils.getAttrValue(idDomElement.getId())));
54 | }
55 | }
56 | return lookupElements.toArray();
57 | }
58 |
59 | @NotNull
60 | private List extends IdDomElement> getIdDomElements() {
61 | if (myElement == null || StringUtils.isBlank(myElement.getValue())) {
62 | return Lists.newArrayList();
63 | }
64 | Mapper mapperDom = DomParseService.INSTANCE(myElement.getProject())
65 | .parseDomElementsByFile(myElement.getContainingFile(), Mapper.class);
66 | if (mapperDom == null) {
67 | return Lists.newArrayList();
68 | }
69 | return getIdDomElements(mapperDom);
70 | }
71 |
72 | protected abstract List extends IdDomElement> getIdDomElements(@NotNull Mapper mapperDom);
73 | }
74 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/reference/MapperInclude2SqlReference.java:
--------------------------------------------------------------------------------
1 | package org.qunar.plugin.mybatis.reference;
2 |
3 | import com.intellij.psi.xml.XmlAttributeValue;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.qunar.plugin.mybatis.bean.IdDomElement;
6 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * mapper sql tag reference
12 | *
13 | * Author: jianyu.lin
14 | * Date: 16-11-27 Time: 下午1:57
15 | */
16 | public class MapperInclude2SqlReference extends MapperIdAttrRefXmlTagReference {
17 |
18 | public MapperInclude2SqlReference(@NotNull XmlAttributeValue sqlRefAttrValue) {
19 | super(sqlRefAttrValue);
20 | }
21 |
22 | @Override
23 | protected List extends IdDomElement> getIdDomElements(@NotNull Mapper mapperDom) {
24 | return mapperDom.getSqls();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/reference/StatementParamsReference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.reference;
5 |
6 | import com.google.common.collect.Sets;
7 | import com.intellij.openapi.util.TextRange;
8 | import com.intellij.psi.PsiAnnotationMemberValue;
9 | import com.intellij.psi.PsiElement;
10 | import com.intellij.psi.PsiIdentifier;
11 | import com.intellij.psi.PsiMethod;
12 | import com.intellij.psi.PsiReferenceBase;
13 | import com.intellij.psi.xml.XmlAttributeValue;
14 | import com.intellij.psi.xml.XmlTag;
15 | import com.intellij.util.xml.DomManager;
16 | import org.apache.commons.lang.StringUtils;
17 | import org.jetbrains.annotations.NotNull;
18 | import org.jetbrains.annotations.Nullable;
19 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
20 | import org.qunar.plugin.mybatis.util.ParamPropertyHelper;
21 |
22 | import java.util.Arrays;
23 | import java.util.Set;
24 |
25 | /**
26 | * add inline sql parameter (${} #{}) reference
27 | *
28 | * Author: jianyu.lin
29 | * Date: 2016/12/3 Time: 下午12:40
30 | */
31 | public class StatementParamsReference extends PsiReferenceBase {
32 |
33 | private final XmlTag parent;
34 | private final String text;
35 | /* add for support tags who adds temp parameters,
36 | * eg:
37 | **/
38 | private final Set extraParams = Sets.newHashSet();
39 |
40 | public StatementParamsReference(@NotNull XmlTag xmlTag,
41 | @NotNull XmlTag parentTag, @NotNull TextRange range) {
42 | super(xmlTag, range, true);
43 | this.parent = parentTag;
44 | text = xmlTag.getText().substring(range.getStartOffset(), range.getEndOffset());
45 | }
46 |
47 | /**
48 | * add extra params
49 | * @param extraParams extra params
50 | * @return this
51 | */
52 | public StatementParamsReference extraParams(PsiElement... extraParams) {
53 | if (extraParams != null) {
54 | this.extraParams.addAll(Arrays.asList(extraParams));
55 | }
56 | return this;
57 | }
58 |
59 | @Nullable
60 | @Override
61 | public PsiElement resolve() {
62 | Statement statement = (Statement) DomManager.getDomManager(myElement.getProject()).getDomElement(parent);
63 | if (statement == null || statement.getId().getValue() == null) {
64 | return null;
65 | }
66 | PsiMethod psiMethod = statement.getId().getValue();
67 | Set elements = ParamPropertyHelper.buildParamLookupElements(psiMethod);
68 | elements.addAll(extraParams);
69 | for (PsiElement element : elements) {
70 | if (checkPsiElementWithTargetText(element)) {
71 | return element;
72 | }
73 | }
74 | return null;
75 | }
76 |
77 | @NotNull
78 | @Override
79 | public Object[] getVariants() {
80 | return new Object[0];
81 | }
82 |
83 | /**
84 | * check the reference psi element
85 | * @param element parameter element
86 | * @return boolean
87 | */
88 | private boolean checkPsiElementWithTargetText(PsiElement element) {
89 | String psiName;
90 | if (element instanceof PsiAnnotationMemberValue) { // @Param
91 | // delete first letter " and last one "
92 | psiName = element.getText().substring(1, element.getTextLength() - 1);
93 | } else if (element instanceof PsiIdentifier) { // method name
94 | String getterProperty = ParamPropertyHelper.parseGetterMethod(element.getText());
95 | psiName = getterProperty == null ? element.getText() : getterProperty;
96 | } else if (element instanceof XmlAttributeValue) { // xml attribute
97 | psiName = ((XmlAttributeValue) element).getValue();
98 | } else {
99 | psiName = element.getText();
100 | }
101 | return StringUtils.equals(text, psiName);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/reference/TypeAliasNameReference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.reference;
5 |
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.psi.PsiClass;
8 | import com.intellij.psi.PsiReferenceBase;
9 | import com.intellij.psi.xml.XmlAttributeValue;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.jetbrains.annotations.Nullable;
12 | import org.qunar.plugin.mybatis.util.TypeAliasResolver;
13 | import org.qunar.plugin.service.JavaService;
14 | import org.qunar.plugin.service.TypeAliasService;
15 |
16 | import java.util.Set;
17 |
18 | /**
19 | * type alias reference
20 | *
21 | * Author: jianyu.lin
22 | * Date: 2016/11/25 Time: 下午6:09
23 | */
24 | public class TypeAliasNameReference extends PsiReferenceBase {
25 |
26 | public TypeAliasNameReference(@NotNull XmlAttributeValue element) {
27 | super(element);
28 | }
29 |
30 | @Nullable
31 | @Override
32 | public PsiClass resolve() {
33 | XmlAttributeValue xmlAttributeValue = getElement();
34 | PsiClass qualifiedClass = JavaService.getInstance(getElement().getProject()).findClass(xmlAttributeValue.getValue());
35 | return qualifiedClass != null ? qualifiedClass : TypeAliasService
36 | .INSTANCE(xmlAttributeValue.getProject()).getAliasClassByName(xmlAttributeValue.getValue());
37 | }
38 |
39 | @NotNull
40 | @Override
41 | public Object[] getVariants() {
42 | Project project = getElement().getProject();
43 | Set registerAliases = TypeAliasResolver.getAllTypeAlias(project).keySet();
44 | return registerAliases.toArray(new String[registerAliases.size()]);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/typehandler/MapperSqlParamTypedHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.typehandler;
5 |
6 | import com.intellij.codeInsight.AutoPopupController;
7 | import com.intellij.codeInsight.editorActions.TypedHandlerDelegate;
8 | import com.intellij.openapi.editor.Editor;
9 | import com.intellij.openapi.project.Project;
10 | import com.intellij.openapi.util.Condition;
11 | import com.intellij.psi.PsiDocumentManager;
12 | import com.intellij.psi.PsiFile;
13 | import org.jetbrains.annotations.NotNull;
14 | import org.qunar.plugin.mybatis.contributor.StatementParamsCompletionContributor;
15 | import org.qunar.plugin.mybatis.util.DomElements;
16 |
17 | /**
18 | * allow #{ or ${ active auto completion
19 | * add statement sql text auto pop with method params
20 | * to see: {@link StatementParamsCompletionContributor}
21 | *
22 | * Author: jianyu.lin
23 | * Date: 2016/11/28 Time: 下午6:35
24 | */
25 | public class MapperSqlParamTypedHandler extends TypedHandlerDelegate {
26 |
27 | @Override
28 | public Result charTyped(char charTyped, Project project, @NotNull Editor editor, @NotNull PsiFile file) {
29 | if (charTyped == '{' && DomElements.isMapperXmlFile(file)) {
30 | int offset = editor.getCaretModel().getOffset();
31 | char preChar = editor.getDocument().getCharsSequence().charAt(offset - 2);
32 | if (offset >= 2 && (preChar == '#' || preChar == '$')) {
33 | //noinspection unchecked
34 | AutoPopupController.getInstance(project).autoPopupMemberLookup(editor, Condition.TRUE);
35 | PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
36 | }
37 | return Result.STOP;
38 | }
39 | return super.charTyped(charTyped, project, editor, file);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/ui/CreateMapperXmlDialog.form:
--------------------------------------------------------------------------------
1 |
2 |
85 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/util/ConfigConfHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.util;
5 |
6 | import org.jetbrains.annotations.NotNull;
7 | import org.qunar.plugin.mybatis.bean.config.Configuration;
8 | import org.qunar.plugin.util.ConfHolder;
9 |
10 | /**
11 | * Author: jianyu.lin
12 | * Date: 2016/12/19 Time: 下午6:07
13 | */
14 | public class ConfigConfHolder extends ConfHolder {
15 |
16 | public static final ConfigConfHolder INSTANCE = new ConfigConfHolder(Configuration.class);
17 |
18 | private ConfigConfHolder(@NotNull Class clazz) {
19 | super(clazz);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/util/DbDdlParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.util;
5 |
6 | import com.intellij.database.model.DasTypedObject;
7 | import com.intellij.database.model.MultiRef;
8 | import com.intellij.sql.psi.SqlColumnDefinition;
9 | import com.intellij.sql.psi.SqlCreateTableStatement;
10 | import com.intellij.sql.psi.SqlTableKeyDefinition;
11 | import org.jetbrains.annotations.NotNull;
12 | import org.qunar.plugin.mybatis.bean.model.DbColumn;
13 | import org.qunar.plugin.mybatis.bean.model.CreateTableDdl;
14 | import org.qunar.plugin.mybatis.bean.model.DbKey;
15 | import org.qunar.plugin.service.JavaService;
16 | import org.qunar.plugin.util.Javas;
17 |
18 | /**
19 | * psi ddl util
20 | *
21 | * Author: jianyu.lin
22 | * Date: 2016/12/24 Time: 上午12:23
23 | */
24 | public class DbDdlParser {
25 |
26 | /**
27 | * parse create table ddl
28 | * @param createTableStatement psi create ddl
29 | * @return plain model
30 | */
31 | public static CreateTableDdl parseCreateTableDdl(@NotNull SqlCreateTableStatement createTableStatement) {
32 | CreateTableDdl createTableDdl = new CreateTableDdl(createTableStatement.getName());
33 | for (SqlColumnDefinition columnDefinition : createTableStatement.getDeclaredColumns()) {
34 | DbColumn dbColumn = new DbColumn();
35 | dbColumn.setName(columnDefinition.getName());
36 | dbColumn.setPropertyName(Javas.transUnderline2UpperLetter(columnDefinition.getName()));
37 | dbColumn.setTypeName(columnDefinition.getDataType().typeName);
38 | createTableDdl.getColumns().add(dbColumn);
39 | }
40 | for (SqlTableKeyDefinition keyDefinition : createTableStatement.getDeclaredKeys()) {
41 | DbKey dbKey = new DbKey();
42 | dbKey.setKeyType(DbKey.KeyType.valueOf(keyDefinition.getClass()));
43 | MultiRef.It extends DasTypedObject> it = keyDefinition.getColumnsRef().iterate();
44 | while (it.hasNext()) {
45 | dbKey.getRefColumns().add(it.next());
46 | }
47 | createTableDdl.getDbKeys().add(dbKey);
48 | }
49 | return createTableDdl;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/util/DomElements.java:
--------------------------------------------------------------------------------
1 | package org.qunar.plugin.mybatis.util;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.intellij.codeInspection.InspectionManager;
5 | import com.intellij.codeInspection.ProblemDescriptor;
6 | import com.intellij.openapi.application.ApplicationManager;
7 | import com.intellij.openapi.util.Computable;
8 | import com.intellij.psi.PsiClass;
9 | import com.intellij.psi.PsiFile;
10 | import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
11 | import com.intellij.psi.xml.XmlFile;
12 | import com.intellij.sql.psi.SqlFile;
13 | import org.apache.commons.lang.StringUtils;
14 | import org.jetbrains.annotations.NotNull;
15 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
16 | import org.qunar.plugin.mybatis.bean.mapper.Statement;
17 | import org.qunar.plugin.mybatis.util.domchecker.DeleteChecker;
18 | import org.qunar.plugin.mybatis.util.domchecker.InsertChecker;
19 | import org.qunar.plugin.mybatis.util.domchecker.SelectChecker;
20 | import org.qunar.plugin.mybatis.util.domchecker.UpdateChecker;
21 | import org.qunar.plugin.util.XmlUtils;
22 |
23 | import java.util.List;
24 |
25 | /**
26 | * author: jianyu.lin Date: 16-11-26.
27 | */
28 | public class DomElements {
29 |
30 | /**
31 | * checkMapper dom elements
32 | * @param manager inspection manager
33 | * @param mapperDom mapper dom element
34 | * @return problems
35 | */
36 | @NotNull
37 | public static List checkMapperDomElement(@NotNull InspectionManager manager,
38 | @NotNull Mapper mapperDom) {
39 | PsiClass mapperClass = XmlUtils.getAttrValue(mapperDom.getNamespace());
40 | if (mapperClass == null) {
41 | return Lists.newArrayList();
42 | }
43 |
44 | List allProblems = Lists.newArrayList();
45 | allProblems.addAll(new InsertChecker(mapperClass).check(manager, mapperDom.getInserts()));
46 | allProblems.addAll(new DeleteChecker(mapperClass).check(manager, mapperDom.getDeletes()));
47 | allProblems.addAll(new SelectChecker(mapperClass).check(manager, mapperDom.getSelects()));
48 | allProblems.addAll(new UpdateChecker(mapperClass).check(manager, mapperDom.getUpdates()));
49 | return allProblems;
50 | }
51 |
52 | /**
53 | * collection all statements
54 | * @param mapperDom mapper root dom
55 | * @return statements
56 | */
57 | @NotNull
58 | public static List collectStatements(final Mapper mapperDom) {
59 | if (mapperDom == null) {
60 | return Lists.newArrayList();
61 | }
62 | return ApplicationManager.getApplication().runReadAction(new Computable>() {
63 | @Override
64 | public List compute() {
65 | List statements = Lists.newArrayList();
66 | statements.addAll(mapperDom.getSelects());
67 | statements.addAll(mapperDom.getInserts());
68 | statements.addAll(mapperDom.getUpdates());
69 | statements.addAll(mapperDom.getDeletes());
70 | return statements;
71 | }
72 | });
73 | }
74 |
75 | /**
76 | * is mapper xml file
77 | * @param psiFile file
78 | * @return boolean
79 | */
80 | public static boolean isMapperXmlFile(PsiFile psiFile) {
81 | return isMybatisFile(psiFile, MapperConfHolder.INSTANCE.rootTagName);
82 | }
83 |
84 | /**
85 | * is mapper configuration file
86 | * @param psiFile file
87 | * @return boolean
88 | */
89 | public static boolean isConfigurationXmlFile(PsiFile psiFile) {
90 | return isMybatisFile(psiFile, ConfigConfHolder.INSTANCE.rootTagName);
91 | }
92 |
93 | /**
94 | * is mybatis config file
95 | * @param psiFile file
96 | * @param rootTagName root tag name
97 | * @return boolean
98 | */
99 | private static boolean isMybatisFile(PsiFile psiFile, String rootTagName) {
100 | if (psiFile == null) {
101 | return false;
102 | }
103 | if (psiFile instanceof XmlFile) {
104 | return isMybatisXmlFile((XmlFile) psiFile, rootTagName);
105 | }
106 | return psiFile instanceof SqlFile && isMybatisSqlFile((SqlFile) psiFile, rootTagName);
107 | }
108 |
109 | /**
110 | * judge sql file
111 | * @param sqlFile sql file
112 | * @param rootTagName root tag name
113 | * @return boolean
114 | */
115 | private static boolean isMybatisSqlFile(SqlFile sqlFile, String rootTagName) {
116 | PsiFile psiFile = InjectedLanguageUtil.getTopLevelFile(sqlFile);
117 | return psiFile instanceof XmlFile && isMybatisFile(psiFile, rootTagName);
118 | }
119 |
120 | /**
121 | * judge sql file
122 | * @param xmlFile xml file
123 | * @param rootTagName root tag name
124 | * @return boolean
125 | */
126 | private static boolean isMybatisXmlFile(XmlFile xmlFile, String rootTagName) {
127 | return xmlFile.getRootTag() != null &&
128 | StringUtils.equals(xmlFile.getRootTag().getName(), rootTagName);
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/util/MapperConfHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.util;
5 |
6 | import com.google.common.base.Predicate;
7 | import com.google.common.collect.Collections2;
8 | import com.intellij.openapi.application.ApplicationManager;
9 | import com.intellij.openapi.project.Project;
10 | import com.intellij.openapi.util.Computable;
11 | import com.intellij.psi.PsiClass;
12 | import com.intellij.psi.search.GlobalSearchScope;
13 | import com.intellij.util.xml.DomFileElement;
14 | import com.intellij.util.xml.DomService;
15 | import org.jetbrains.annotations.NotNull;
16 | import org.qunar.plugin.mybatis.bean.mapper.Mapper;
17 | import org.qunar.plugin.util.ConfHolder;
18 | import org.qunar.plugin.util.XmlUtils;
19 |
20 | import java.util.Collection;
21 | import java.util.List;
22 |
23 | /**
24 | * mapper dom cache util
25 | *
26 | * Author: jianyu.lin
27 | * Date: 2016/12/19 Time: 下午6:07
28 | */
29 | public class MapperConfHolder extends ConfHolder {
30 |
31 | public static final MapperConfHolder INSTANCE = new MapperConfHolder(Mapper.class);
32 |
33 | private MapperConfHolder(@NotNull Class clazz) {
34 | super(clazz);
35 | }
36 |
37 | /**
38 | * get all mapping mapper xml
39 | * @param mapperClass class
40 | * @return mapper dom elements
41 | */
42 | @NotNull
43 | public Collection getMapperDomElements(@NotNull final PsiClass mapperClass) {
44 | return ApplicationManager.getApplication().runReadAction(new Computable>() {
45 | @Override
46 | public Collection compute() {
47 | if (getAllDomElements().isEmpty()) {
48 | initAllMappers(mapperClass.getProject());
49 | }
50 | Collection mappers = filterMapperDom(getAllDomElements(), mapperClass);
51 | if (mappers.isEmpty()) {
52 | initAllMappers(mapperClass.getProject());
53 | }
54 | return filterMapperDom(getAllDomElements(), mapperClass);
55 | }
56 | });
57 | }
58 |
59 | /**
60 | * filter mapper dom
61 | * @param allDocuments 所有mapper dom
62 | * @param targetClass mapper class
63 | * @return mapping mappers
64 | */
65 | private Collection filterMapperDom(Collection allDocuments, final PsiClass targetClass) {
66 | return Collections2.filter(allDocuments, new Predicate() {
67 | @Override
68 | public boolean apply(final Mapper mapper) {
69 | return ApplicationManager.getApplication().runReadAction(new Computable() {
70 | @Override
71 | public Boolean compute() {
72 | if (mapper.getXmlTag() == null || !rootTagName.equals(mapper.getXmlTag().getName())) {
73 | return false;
74 | }
75 | mapper.getNamespace();
76 | PsiClass psiClass = XmlUtils.getAttrValue(mapper.getNamespace());
77 | return psiClass == targetClass;
78 | }
79 | });
80 | }
81 | });
82 | }
83 |
84 | /**
85 | * reload all mappers
86 | * @param project current project
87 | */
88 | private void initAllMappers(Project project) {
89 | List> mapperFiles = DomService.getInstance()
90 | .getFileElements(Mapper.class, project, GlobalSearchScope.projectScope(project));
91 | for (DomFileElement mapperFile : mapperFiles) {
92 | PsiClass psiClass = XmlUtils.getAttrValue(mapperFile.getRootElement().getNamespace());
93 | if (psiClass != null) {
94 | holder.put(mapperFile.getFile(), mapperFile.getRootElement());
95 | }
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/util/domchecker/DeleteChecker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.util.domchecker;
5 |
6 | import com.intellij.psi.PsiClass;
7 | import org.qunar.plugin.mybatis.bean.mapper.Delete;
8 |
9 | /**
10 | * Author: jianyu.lin
11 | * Date: 2016/11/30 Time: 下午6:38
12 | */
13 | public class DeleteChecker extends StatementChecker {
14 |
15 | public DeleteChecker(PsiClass mapperClass) {
16 | super(mapperClass);
17 | }
18 | }
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/util/domchecker/InsertChecker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.util.domchecker;
5 |
6 | import com.intellij.psi.PsiClass;
7 | import org.jetbrains.annotations.NotNull;
8 | import org.qunar.plugin.mybatis.bean.mapper.Insert;
9 |
10 | /**
11 | * Author: jianyu.lin
12 | * Date: 2016/11/30 Time: 下午6:37
13 | */
14 | public class InsertChecker extends StatementChecker {
15 |
16 | public InsertChecker(@NotNull PsiClass mapperClass) {
17 | super(mapperClass);
18 | }
19 | }
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/util/domchecker/MappersChecker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.util.domchecker;
5 |
6 | import com.google.common.collect.Lists;
7 | import com.intellij.codeInspection.InspectionManager;
8 | import com.intellij.codeInspection.LocalQuickFix;
9 | import com.intellij.codeInspection.ProblemDescriptor;
10 | import com.intellij.codeInspection.ProblemHighlightType;
11 | import com.intellij.openapi.paths.GlobalPathReferenceProvider;
12 | import com.intellij.openapi.util.TextRange;
13 | import com.intellij.psi.PsiFile;
14 | import com.intellij.psi.xml.XmlAttributeValue;
15 | import com.intellij.util.xml.GenericAttributeValue;
16 | import org.apache.commons.lang.StringUtils;
17 | import org.jetbrains.annotations.NotNull;
18 | import org.qunar.plugin.mybatis.bean.config.Mapper;
19 | import org.qunar.plugin.mybatis.bean.config.Mappers;
20 | import org.qunar.plugin.util.DomChecker;
21 | import org.qunar.plugin.util.Inspections;
22 |
23 | import java.util.List;
24 |
25 | /**
26 | * Author: jianyu.lin
27 | * Date: 2016/11/30 Time: 下午7:22
28 | */
29 | public class MappersChecker implements DomChecker {
30 |
31 | /**
32 | * reference to 'org.apache.ibatis.builder.xml.XMLConfigBuilder#mapperElement'
33 | * @param manager inspection manager
34 | * @param mappersList mappers nodes
35 | * @return check result
36 | */
37 | @Override
38 | @NotNull
39 | public List check(@NotNull InspectionManager manager, @NotNull List mappersList) {
40 | List problemDescriptors = Lists.newArrayList();
41 | for (Mappers mappers : mappersList) {
42 | for (Mapper mapper : mappers.getMappers()) {
43 | problemDescriptors.addAll(Inspections.buildPsiClassProblems(manager, mapper.getClazz()));
44 | problemDescriptors.addAll(buildUrlAttrProblems(manager, mapper.getUrl()));
45 | }
46 | }
47 | return problemDescriptors;
48 | }
49 |
50 | /**
51 | * valid resource attribute
52 | * @param manager inspection manager
53 | * @param resourceAttr resource attribute
54 | * @return problems
55 | */
56 | @NotNull
57 | @SuppressWarnings("unused")
58 | private List buildResourceAttrProblems(@NotNull InspectionManager manager,
59 | GenericAttributeValue resourceAttr) {
60 | if (resourceAttr == null || resourceAttr.getXmlAttribute() == null) {
61 | return Lists.newArrayList();
62 | }
63 | XmlAttributeValue xmlAttrValue = resourceAttr.getXmlAttributeValue();
64 | if (resourceAttr.getValue() != null || xmlAttrValue == null) {
65 | return Lists.newArrayList();
66 | }
67 | return Inspections.buildClassPathRelatedPathProblems(manager, xmlAttrValue);
68 | }
69 |
70 | /**
71 | * valid url attribute
72 | * @param manager inspection manager
73 | * @param urlAttr url attribute
74 | * @return problems
75 | */
76 | @NotNull
77 | private List buildUrlAttrProblems(@NotNull InspectionManager manager,
78 | GenericAttributeValue urlAttr) {
79 | if (urlAttr == null || StringUtils.isBlank(urlAttr.getValue())) {
80 | return Lists.newArrayList();
81 | }
82 | if (!GlobalPathReferenceProvider.isWebReferenceUrl(urlAttr.getValue())) {
83 | String errMsg = String.format("Cannot resolve url '%s'", urlAttr.getValue());
84 | XmlAttributeValue urlAttrValue = urlAttr.getXmlAttributeValue();
85 | if (urlAttrValue == null) {
86 | return Lists.newArrayList();
87 | }
88 | TextRange textRange = TextRange.create(1, urlAttrValue.getTextLength());
89 | return Lists.newArrayList(manager.createProblemDescriptor(urlAttrValue, textRange,
90 | errMsg, ProblemHighlightType.ERROR, true, LocalQuickFix.EMPTY_ARRAY));
91 | }
92 | return Lists.newArrayList();
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/org/qunar/plugin/mybatis/util/domchecker/SelectChecker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Qunar.com. All Rights Reserved.
3 | */
4 | package org.qunar.plugin.mybatis.util.domchecker;
5 |
6 | import com.intellij.psi.PsiClass;
7 | import org.qunar.plugin.mybatis.bean.mapper.Select;
8 |
9 | /**
10 | * Author: jianyu.lin
11 | * Date: 2016/11/30 Time: 下午6:39
12 | */
13 | public class SelectChecker extends StatementChecker