├── .gitignore ├── src └── net │ └── ishchenko │ └── idea │ └── minibatis │ ├── model │ ├── sqlmap │ │ ├── Delete.java │ │ ├── Update.java │ │ ├── Procedure.java │ │ ├── Statement.java │ │ ├── Select.java │ │ ├── Insert.java │ │ ├── SelectKey.java │ │ ├── Include.java │ │ ├── ResultMap.java │ │ ├── ResultProvider.java │ │ ├── ParameterMap.java │ │ ├── TypeAlias.java │ │ ├── SqlMapIdentifiableStatement.java │ │ ├── Result.java │ │ └── SqlMap.java │ └── mapper │ │ ├── Delete.java │ │ ├── Insert.java │ │ ├── Update.java │ │ ├── Select.java │ │ ├── WithIncludes.java │ │ ├── Include.java │ │ ├── WithResultMap.java │ │ ├── MapperIdentifiableStatement.java │ │ ├── ResultMap.java │ │ └── Mapper.java │ ├── MyBatisInspectionToolsProvider.java │ ├── inspections │ └── mapper │ │ ├── MyBatisInspection.java │ │ └── NoMapperStatementInspection.java │ ├── MapperDescription.java │ ├── SqlMapDescription.java │ ├── MyBatisReferenceContributor.java │ ├── MyBatis3ProxiesDefinitionsSearcher.java │ ├── IdentifiableStatementQualifiedNameProvider.java │ ├── ResultMapReference.java │ ├── StatementDocumentationProvider.java │ ├── SqlMapReference.java │ ├── IdentifiableStatementHierarchyProvider.java │ ├── GoToSqlMapStatementContributor.java │ ├── MyBatis3ProxiesLineMarkerProvider.java │ ├── IdentifiableStatementReference.java │ └── DomFileElementsFinder.java ├── README.md └── META-INF └── plugin.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /out 3 | *.iml 4 | *.jar -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/Delete.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 22.01.12 7 | * Time: 0:33 8 | */ 9 | public interface Delete extends SqlMapIdentifiableStatement { 10 | } 11 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/Update.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 22.01.12 7 | * Time: 0:33 8 | */ 9 | public interface Update extends SqlMapIdentifiableStatement { 10 | } 11 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/Delete.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: mishchenko 6 | * Date: 26.05.12 7 | * Time: 15:55 8 | */ 9 | public interface Delete extends MapperIdentifiableStatement { 10 | } 11 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/Insert.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: mishchenko 6 | * Date: 26.05.12 7 | * Time: 15:55 8 | */ 9 | public interface Insert extends MapperIdentifiableStatement { 10 | } 11 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/Update.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: mishchenko 6 | * Date: 26.05.12 7 | * Time: 15:55 8 | */ 9 | public interface Update extends MapperIdentifiableStatement { 10 | } 11 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/Procedure.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 02.01.12 7 | * Time: 21:55 8 | */ 9 | public interface Procedure extends SqlMapIdentifiableStatement, ResultProvider { 10 | } 11 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/Statement.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 02.01.12 7 | * Time: 21:55 8 | */ 9 | public interface Statement extends SqlMapIdentifiableStatement, ResultProvider { 10 | } 11 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/Select.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: mishchenko 6 | * Date: 26.05.12 7 | * Time: 15:50 8 | */ 9 | public interface Select extends MapperIdentifiableStatement, WithResultMap { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/Select.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 02.01.12 7 | * Time: 21:55 8 | */ 9 | public interface Select extends SqlMapIdentifiableStatement, ResultProvider { 10 | 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/Insert.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | import com.intellij.util.xml.SubTagList; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 22.01.12 11 | * Time: 0:34 12 | */ 13 | public interface Insert extends SqlMapIdentifiableStatement { 14 | 15 | @SubTagList("selectKey") 16 | List getSelectKeys(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/WithIncludes.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | import com.intellij.util.xml.DomElement; 4 | import com.intellij.util.xml.SubTagList; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Created with IntelliJ IDEA. 10 | * User: mishchenko 11 | * Date: 26.05.12 12 | * Time: 15:47 13 | */ 14 | public interface WithIncludes extends DomElement { 15 | 16 | @SubTagList("include") 17 | List getIncludes(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/SelectKey.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | import com.intellij.util.xml.Attribute; 4 | import com.intellij.util.xml.DomElement; 5 | import com.intellij.util.xml.GenericAttributeValue; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 02.03.12 11 | * Time: 21:58 12 | */ 13 | public interface SelectKey extends DomElement { 14 | 15 | @Attribute("resultClass") 16 | GenericAttributeValue getResultClass(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/Include.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | import com.intellij.util.xml.Attribute; 4 | import com.intellij.util.xml.DomElement; 5 | import com.intellij.util.xml.GenericAttributeValue; 6 | 7 | /** 8 | * Created with IntelliJ IDEA. 9 | * User: mishchenko 10 | * Date: 26.05.12 11 | * Time: 15:59 12 | */ 13 | public interface Include extends DomElement { 14 | 15 | @Attribute("refid") 16 | GenericAttributeValue getRefid(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/WithResultMap.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | import com.intellij.util.xml.Attribute; 4 | import com.intellij.util.xml.DomElement; 5 | import com.intellij.util.xml.GenericAttributeValue; 6 | 7 | /** 8 | * Created with IntelliJ IDEA. 9 | * User: mishchenko 10 | * Date: 26.05.12 11 | * Time: 16:20 12 | */ 13 | public interface WithResultMap extends DomElement { 14 | 15 | @Attribute("resultMap") 16 | GenericAttributeValue getResultMap(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/Include.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | import com.intellij.util.xml.Attribute; 4 | import com.intellij.util.xml.DomElement; 5 | import com.intellij.util.xml.GenericAttributeValue; 6 | import com.intellij.util.xml.NameValue; 7 | 8 | /** 9 | * Created by IntelliJ IDEA. 10 | * User: Max 11 | * Date: 02.01.12 12 | * Time: 20:40 13 | */ 14 | public interface Include extends DomElement { 15 | 16 | @NameValue 17 | @Attribute("refid") 18 | GenericAttributeValue getRefid(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/MyBatisInspectionToolsProvider.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.codeInspection.InspectionToolProvider; 4 | import net.ishchenko.idea.minibatis.inspections.mapper.NoMapperStatementInspection; 5 | 6 | /** 7 | * Created by IntelliJ IDEA. 8 | * User: Max 9 | * Date: 02.06.12 10 | * Time: 11:38 11 | */ 12 | public class MyBatisInspectionToolsProvider implements InspectionToolProvider { 13 | 14 | @Override 15 | public Class[] getInspectionClasses() { 16 | return new Class[]{NoMapperStatementInspection.class}; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/ResultMap.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | import com.intellij.util.xml.*; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 22.01.12 11 | * Time: 0:28 12 | */ 13 | public interface ResultMap extends DomElement { 14 | 15 | @NameValue 16 | @Attribute("id") 17 | GenericAttributeValue getId(); 18 | 19 | @Attribute("class") 20 | GenericAttributeValue getClazz(); 21 | 22 | @SubTagList("result") 23 | List getResults(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/MapperIdentifiableStatement.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | import com.intellij.util.xml.Attribute; 4 | import com.intellij.util.xml.DomElement; 5 | import com.intellij.util.xml.GenericAttributeValue; 6 | import com.intellij.util.xml.NameValue; 7 | 8 | /** 9 | * Created by IntelliJ IDEA. 10 | * User: Max 11 | * Date: 23.12.11 12 | * Time: 23:43 13 | */ 14 | public interface MapperIdentifiableStatement extends DomElement, WithIncludes { 15 | 16 | @NameValue 17 | @Attribute("id") 18 | GenericAttributeValue getId(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/ResultProvider.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | import com.intellij.util.xml.Attribute; 4 | import com.intellij.util.xml.DomElement; 5 | import com.intellij.util.xml.GenericAttributeValue; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 02.01.12 11 | * Time: 21:54 12 | */ 13 | public interface ResultProvider extends DomElement { 14 | 15 | @Attribute("resultClass") 16 | GenericAttributeValue getResultClass(); 17 | 18 | @Attribute("resultMap") 19 | GenericAttributeValue getResultMap(); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/ParameterMap.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | import com.intellij.util.xml.Attribute; 4 | import com.intellij.util.xml.DomElement; 5 | import com.intellij.util.xml.GenericAttributeValue; 6 | import com.intellij.util.xml.NameValue; 7 | 8 | /** 9 | * Created by IntelliJ IDEA. 10 | * User: Max 11 | * Date: 02.03.12 12 | * Time: 21:44 13 | */ 14 | public interface ParameterMap extends DomElement { 15 | 16 | @NameValue 17 | @Attribute("id") 18 | GenericAttributeValue getId(); 19 | 20 | @Attribute("class") 21 | GenericAttributeValue getClazz(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/ResultMap.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | import com.intellij.util.xml.Attribute; 4 | import com.intellij.util.xml.DomElement; 5 | import com.intellij.util.xml.GenericAttributeValue; 6 | import com.intellij.util.xml.NameValue; 7 | 8 | /** 9 | * Created with IntelliJ IDEA. 10 | * User: mishchenko 11 | * Date: 26.05.12 12 | * Time: 16:21 13 | */ 14 | public interface ResultMap extends DomElement { 15 | 16 | @NameValue 17 | @Attribute("id") 18 | GenericAttributeValue getId(); 19 | 20 | @Attribute("extends") 21 | GenericAttributeValue getExtends(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/TypeAlias.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | import com.intellij.psi.PsiClass; 4 | import com.intellij.util.xml.Attribute; 5 | import com.intellij.util.xml.DomElement; 6 | import com.intellij.util.xml.GenericAttributeValue; 7 | import com.intellij.util.xml.NameValue; 8 | 9 | /** 10 | * Created by IntelliJ IDEA. 11 | * User: Max 12 | * Date: 02.01.12 13 | * Time: 21:50 14 | */ 15 | public interface TypeAlias extends DomElement { 16 | 17 | @NameValue 18 | @Attribute("alias") 19 | GenericAttributeValue getAlias(); 20 | 21 | @Attribute("type") 22 | GenericAttributeValue getType(); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/sqlmap/SqlMapIdentifiableStatement.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.sqlmap; 2 | 3 | import com.intellij.util.xml.*; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 23.12.11 11 | * Time: 23:43 12 | */ 13 | public interface SqlMapIdentifiableStatement extends DomElement { 14 | 15 | @NameValue 16 | @Attribute("id") 17 | GenericAttributeValue getId(); 18 | 19 | @Attribute("parameterClass") 20 | GenericAttributeValue getParameterClass(); 21 | 22 | @Attribute("parameterMap") 23 | GenericAttributeValue getParameterMap(); 24 | 25 | @SubTagList("include") 26 | List getIncludes(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/inspections/mapper/MyBatisInspection.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.inspections.mapper; 2 | 3 | import com.intellij.codeInspection.BaseJavaLocalInspectionTool; 4 | import org.jetbrains.annotations.Nls; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 02.06.12 11 | * Time: 11:47 12 | */ 13 | public abstract class MyBatisInspection extends BaseJavaLocalInspectionTool { 14 | 15 | @Nls 16 | @NotNull 17 | @Override 18 | public String getGroupDisplayName() { 19 | return "iBATIS/MyBatis issues"; 20 | } 21 | 22 | @NotNull 23 | @Override 24 | public String getShortName() { 25 | return this.getClass().getName(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/MapperDescription.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.openapi.module.Module; 4 | import com.intellij.psi.xml.XmlFile; 5 | import com.intellij.psi.xml.XmlTag; 6 | import com.intellij.util.xml.DomFileDescription; 7 | import net.ishchenko.idea.minibatis.model.mapper.Mapper; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | /** 12 | * Created by IntelliJ IDEA. 13 | * User: Max 14 | * Date: 01.01.12 15 | * Time: 18:38 16 | */ 17 | public class MapperDescription extends DomFileDescription { 18 | 19 | public MapperDescription() { 20 | super(Mapper.class, "mapper"); 21 | } 22 | 23 | @Override 24 | public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) { 25 | //todo: maybe use namespace policy? 26 | XmlTag rootTag = file.getRootTag(); 27 | return rootTag != null && rootTag.getName().equals(getRootTagName()); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/SqlMapDescription.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.openapi.module.Module; 4 | import com.intellij.psi.xml.XmlFile; 5 | import com.intellij.psi.xml.XmlTag; 6 | import com.intellij.util.xml.DomFileDescription; 7 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMap; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | /** 12 | * Created by IntelliJ IDEA. 13 | * User: Max 14 | * Date: 24.12.11 15 | * Time: 0:00 16 | */ 17 | public class SqlMapDescription extends DomFileDescription { 18 | 19 | public SqlMapDescription() { 20 | super(SqlMap.class, "sqlMap"); 21 | } 22 | 23 | @Override 24 | public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) { 25 | //todo: maybe use namespace policy? 26 | XmlTag rootTag = file.getRootTag(); 27 | return rootTag != null && rootTag.getName().equals(getRootTagName()); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/MyBatisReferenceContributor.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.patterns.PsiJavaPatterns; 4 | import com.intellij.psi.*; 5 | import com.intellij.util.ProcessingContext; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Created by IntelliJ IDEA. 10 | * User: Max 11 | * Date: 17.12.11 12 | * Time: 20:36 13 | */ 14 | public class MyBatisReferenceContributor extends PsiReferenceContributor { 15 | 16 | @Override 17 | public void registerReferenceProviders(PsiReferenceRegistrar registrar) { 18 | 19 | registrar.registerReferenceProvider(PsiJavaPatterns.psiLiteral(), new PsiReferenceProvider() { 20 | @NotNull 21 | public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { 22 | return new PsiReference[]{new IdentifiableStatementReference((PsiLiteral) element), new SqlMapReference((PsiLiteral) element)}; 23 | } 24 | }); 25 | 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/model/mapper/Mapper.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.model.mapper; 2 | 3 | import com.intellij.util.xml.*; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 01.01.12 11 | * Time: 18:37 12 | */ 13 | 14 | public interface Mapper extends DomElement { 15 | 16 | @Attribute("namespace") 17 | GenericAttributeValue getNamespace(); 18 | 19 | @SubTagsList({"sql", "select", "insert", "update", "delete"}) 20 | List getIdentifiableStatements(); 21 | 22 | @SubTagList("resultMap") 23 | List getResultMaps(); 24 | 25 | @SubTagList("sql") 26 | List getSqls(); 27 | 28 | @SubTagList("select") 29 | List getSelects(); 30 | 31 | @SubTagList("insert") 32 | List getInserts(); 33 | 34 | @SubTagList("update") 35 | List getUpdates(); 36 | 37 | @SubTagList("delete") 38 | List getDeletes(); 39 | 40 | @SubTagList("procedure") 41 | List getProcedures(); 42 | 43 | @SubTagList("typeAlias") 44 | List getTypeAliases(); 45 | 46 | @SubTagList("resultMap") 47 | List getResultMaps(); 48 | 49 | @SubTagList("parameterMap") 50 | List getParameterMap(); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/MyBatis3ProxiesDefinitionsSearcher.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.openapi.application.QueryExecutorBase; 4 | import com.intellij.openapi.components.ServiceManager; 5 | import com.intellij.psi.PsiClass; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiMethod; 8 | import com.intellij.psi.xml.XmlElement; 9 | import com.intellij.util.Processor; 10 | import com.intellij.util.xml.DomElement; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | /** 14 | * Created by IntelliJ IDEA. 15 | * User: Max 16 | * Date: 04.01.12 17 | * Time: 22:16 18 | */ 19 | public class MyBatis3ProxiesDefinitionsSearcher extends QueryExecutorBase { 20 | 21 | @Override 22 | public void processQuery(@NotNull PsiElement element, @NotNull final Processor consumer) { 23 | 24 | DomFileElementsFinder finder = ServiceManager.getService(element.getProject(), DomFileElementsFinder.class); 25 | Processor processor = new Processor() { 26 | @Override 27 | public boolean process(DomElement domElement) { 28 | return consumer.process(domElement.getXmlElement()); 29 | } 30 | }; 31 | 32 | if (element instanceof PsiClass) { 33 | finder.processMappers((PsiClass) element, processor); 34 | } else if (element instanceof PsiMethod) { 35 | finder.processMapperStatements((PsiMethod) element, processor); 36 | } 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/IdentifiableStatementQualifiedNameProvider.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.ide.actions.QualifiedNameProvider; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.util.xml.DomElement; 8 | import com.intellij.util.xml.DomUtil; 9 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMap; 10 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMapIdentifiableStatement; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | /** 14 | * Created with IntelliJ IDEA. 15 | * User: Max 16 | * Date: 30.04.13 17 | * Time: 0:06 18 | */ 19 | public class IdentifiableStatementQualifiedNameProvider implements QualifiedNameProvider { 20 | 21 | @Nullable 22 | @Override 23 | public PsiElement adjustElementToCopy(PsiElement element) { 24 | DomElement domElement = DomUtil.getDomElement(element); 25 | if (domElement != null && "id".equals(domElement.getXmlElementName()) && domElement.getParent() instanceof SqlMapIdentifiableStatement) { 26 | return domElement.getParent().getXmlElement(); 27 | } 28 | return null; 29 | } 30 | 31 | @Nullable 32 | @Override 33 | public String getQualifiedName(PsiElement element) { 34 | DomElement domElement = DomUtil.getDomElement(element); 35 | if (domElement instanceof SqlMapIdentifiableStatement) { 36 | SqlMapIdentifiableStatement statement = (SqlMapIdentifiableStatement) domElement; 37 | SqlMap sqlMap = statement.getParentOfType(SqlMap.class, true); 38 | if (sqlMap != null) { 39 | String namespace = sqlMap.getNamespace().getRawText(); 40 | return (namespace != null ? namespace + "." : "") + statement.getId(); 41 | } 42 | } 43 | return null; 44 | } 45 | 46 | @Override 47 | public PsiElement qualifiedNameToElement(String fqn, Project project) { 48 | return null; 49 | } 50 | 51 | @Override 52 | public void insertQualifiedName(String fqn, PsiElement element, Editor editor, Project project) { 53 | 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/inspections/mapper/NoMapperStatementInspection.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis.inspections.mapper; 2 | 3 | import com.intellij.codeInspection.InspectionManager; 4 | import com.intellij.codeInspection.LocalQuickFix; 5 | import com.intellij.codeInspection.ProblemDescriptor; 6 | import com.intellij.codeInspection.ProblemHighlightType; 7 | import com.intellij.openapi.components.ServiceManager; 8 | import com.intellij.psi.PsiAnnotation; 9 | import com.intellij.psi.PsiClass; 10 | import com.intellij.psi.PsiIdentifier; 11 | import com.intellij.psi.PsiMethod; 12 | import net.ishchenko.idea.minibatis.DomFileElementsFinder; 13 | import org.jetbrains.annotations.Nls; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | /** 17 | * Created by IntelliJ IDEA. 18 | * User: Max 19 | * Date: 02.06.12 20 | * Time: 11:39 21 | */ 22 | public class NoMapperStatementInspection extends MyBatisInspection { 23 | 24 | @Override 25 | public ProblemDescriptor[] checkMethod(@NotNull PsiMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) { 26 | PsiClass containingClass = method.getContainingClass(); 27 | if (containingClass != null && containingClass.isInterface()) { 28 | 29 | PsiIdentifier methodName = method.getNameIdentifier(); 30 | DomFileElementsFinder finder = ServiceManager.getService(containingClass.getProject(), DomFileElementsFinder.class); 31 | boolean existsMapperStatement = finder.existsMapperStatement(method); 32 | 33 | boolean containsIbatisAnnotation = false; 34 | for (PsiAnnotation annotation : method.getModifierList().getAnnotations()) { 35 | String annotationName = annotation.getQualifiedName(); 36 | if (annotationName != null && annotationName.startsWith("org.apache.ibatis.annotations")) { 37 | containsIbatisAnnotation = true; 38 | break; 39 | } 40 | } 41 | 42 | if (!existsMapperStatement && !containsIbatisAnnotation && methodName != null) { 43 | return new ProblemDescriptor[]{ 44 | manager.createProblemDescriptor(methodName, "Statement with id=\"#ref\" not defined in mapper xml", (LocalQuickFix) null, ProblemHighlightType.GENERIC_ERROR, isOnTheFly) 45 | }; 46 | } 47 | } 48 | return null; 49 | } 50 | 51 | @Nls 52 | @NotNull 53 | @Override 54 | public String getDisplayName() { 55 | return "Mapper interface method not defined in xml"; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/ResultMapReference.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.openapi.components.ServiceManager; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiReferenceBase; 6 | import com.intellij.psi.impl.PomTargetPsiElementImpl; 7 | import com.intellij.psi.xml.XmlElement; 8 | import com.intellij.util.CommonProcessors; 9 | import com.intellij.util.xml.DomTarget; 10 | import net.ishchenko.idea.minibatis.model.sqlmap.ResultMap; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.regex.Pattern; 14 | 15 | /** 16 | * Created by IntelliJ IDEA. 17 | * User: Max 18 | * Date: 22.04.12 19 | * Time: 10:03 20 | */ 21 | public class ResultMapReference extends PsiReferenceBase { 22 | 23 | private static final Pattern dotPattern = Pattern.compile("\\."); 24 | 25 | public ResultMapReference(@NotNull PsiElement element) { 26 | super(element); 27 | } 28 | 29 | @Override 30 | public PsiElement resolve() { 31 | 32 | String rawText = getElement().getText(); 33 | if (rawText.length() <= 2) { 34 | return null; 35 | } 36 | 37 | String[] split = dotPattern.split(rawText.substring(1, rawText.length() - 1), 2); 38 | 39 | String namespace; 40 | String id; 41 | 42 | if (split.length == 2) { 43 | namespace = split[0]; 44 | id = split[1]; 45 | } else { 46 | namespace = ""; 47 | id = split[0]; 48 | } 49 | 50 | CommonProcessors.FindFirstProcessor processor = new CommonProcessors.FindFirstProcessor(); 51 | ServiceManager.getService(getElement().getProject(), DomFileElementsFinder.class).processResultMaps(namespace, id, processor); 52 | ResultMap foundValue = processor.getFoundValue(); 53 | if (foundValue != null) { 54 | DomTarget target = DomTarget.getTarget(foundValue); 55 | if (target != null) { 56 | XmlElement xmlElement = foundValue.getXmlElement(); 57 | final String locationString = xmlElement != null ? xmlElement.getContainingFile().getName() : ""; 58 | return new PomTargetPsiElementImpl(target) { 59 | @Override 60 | public String getLocationString() { 61 | return locationString; 62 | } 63 | }; 64 | } 65 | } 66 | 67 | return null; 68 | 69 | } 70 | 71 | @NotNull 72 | @Override 73 | public Object[] getVariants() { 74 | CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(); 75 | ServiceManager.getService(getElement().getProject(), DomFileElementsFinder.class).processResultMapNames(processor); 76 | return processor.toArray(new String[processor.getResults().size()]); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/StatementDocumentationProvider.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.lang.documentation.DocumentationProvider; 4 | import com.intellij.openapi.components.ServiceManager; 5 | import com.intellij.openapi.util.text.StringUtil; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiJavaToken; 8 | import com.intellij.psi.PsiManager; 9 | import com.intellij.psi.xml.XmlElement; 10 | import com.intellij.util.CommonProcessors; 11 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMapIdentifiableStatement; 12 | 13 | import java.util.List; 14 | import java.util.regex.Pattern; 15 | 16 | /** 17 | * Created by IntelliJ IDEA. 18 | * User: Max 19 | * Date: 01.02.12 20 | * Time: 22:01 21 | */ 22 | public class StatementDocumentationProvider implements DocumentationProvider { 23 | 24 | private static final Pattern dotPattern = Pattern.compile("\\."); 25 | 26 | @Override 27 | public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { 28 | return null; 29 | } 30 | 31 | @Override 32 | public List getUrlFor(PsiElement element, PsiElement originalElement) { 33 | return null; 34 | } 35 | 36 | @Override 37 | public String generateDoc(PsiElement element, PsiElement originalElement) { 38 | 39 | if (originalElement instanceof PsiJavaToken) { 40 | 41 | String rawText = originalElement.getText(); 42 | String[] parts = dotPattern.split(rawText.substring(1, rawText.length() - 1), 2); 43 | 44 | String namespace; 45 | String id; 46 | 47 | if (parts.length == 2) { 48 | namespace = parts[0]; 49 | id = parts[1]; 50 | } else { 51 | namespace = ""; 52 | id = parts[0]; 53 | } 54 | 55 | DomFileElementsFinder finder = ServiceManager.getService(originalElement.getProject(), DomFileElementsFinder.class); 56 | CommonProcessors.FindFirstProcessor processor = new CommonProcessors.FindFirstProcessor(); 57 | finder.processSqlMapStatements(namespace, id, processor); 58 | if (processor.isFound()) { 59 | SqlMapIdentifiableStatement statement = processor.getFoundValue(); 60 | XmlElement xmlElement = statement.getXmlElement(); 61 | if (xmlElement != null) { 62 | return "
" + StringUtil.escapeXml(xmlElement.getText()) + "
"; 63 | } 64 | } 65 | 66 | return null; 67 | 68 | } 69 | return null; 70 | } 71 | 72 | @Override 73 | public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) { 74 | return null; 75 | } 76 | 77 | @Override 78 | public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) { 79 | return null; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/SqlMapReference.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.openapi.components.ServiceManager; 4 | import com.intellij.psi.PsiElementResolveResult; 5 | import com.intellij.psi.PsiLiteral; 6 | import com.intellij.psi.PsiPolyVariantReferenceBase; 7 | import com.intellij.psi.ResolveResult; 8 | import com.intellij.psi.impl.PomTargetPsiElementImpl; 9 | import com.intellij.psi.xml.XmlElement; 10 | import com.intellij.util.CommonProcessors; 11 | import com.intellij.util.xml.DomTarget; 12 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMap; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Collection; 17 | import java.util.List; 18 | 19 | /** 20 | * Created by IntelliJ IDEA. 21 | * User: Max 22 | * Date: 20.04.13 23 | * Time: 22:01 24 | */ 25 | public class SqlMapReference extends PsiPolyVariantReferenceBase { 26 | 27 | public SqlMapReference(PsiLiteral expression) { 28 | super(expression); 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public ResolveResult[] multiResolve(boolean b) { 34 | 35 | String rawText = getElement().getText(); 36 | 37 | //rawText contains quotes, i.e. only "x" count 38 | if (rawText.length() < 3) { 39 | return ResolveResult.EMPTY_ARRAY; 40 | } 41 | 42 | CommonProcessors.CollectUniquesProcessor processor = new CommonProcessors.CollectUniquesProcessor(); 43 | DomFileElementsFinder elementsFinder = ServiceManager.getService(getElement().getProject(), DomFileElementsFinder.class); 44 | 45 | String noQuotesText = rawText.substring(1, rawText.length() - 1); 46 | elementsFinder.processSqlMaps(noQuotesText, processor); 47 | if (noQuotesText.length() > 0 && noQuotesText.endsWith(".")) { 48 | elementsFinder.processSqlMaps(noQuotesText.substring(0, noQuotesText.length() - 1), processor); 49 | } 50 | 51 | Collection processorResults = processor.getResults(); 52 | final List results = new ArrayList(processorResults.size()); 53 | final SqlMap[] sqlMaps = processorResults.toArray(new SqlMap[processorResults.size()]); 54 | for (SqlMap sqlMap : sqlMaps) { 55 | DomTarget target = DomTarget.getTarget(sqlMap); 56 | if (target != null) { 57 | XmlElement xmlElement = sqlMap.getXmlElement(); 58 | final String locationString = xmlElement != null ? xmlElement.getContainingFile().getName() : ""; 59 | results.add(new PsiElementResolveResult(new PomTargetPsiElementImpl(target) { 60 | @Override 61 | public String getLocationString() { 62 | return locationString; 63 | } 64 | })); 65 | } 66 | } 67 | return results.toArray(ResolveResult.EMPTY_ARRAY); 68 | 69 | } 70 | 71 | @NotNull 72 | public Object[] getVariants() { 73 | 74 | CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(); 75 | ServiceManager.getService(getElement().getProject(), DomFileElementsFinder.class).processSqlMapNamespaceNames(processor); 76 | return processor.toArray(new String[processor.getResults().size()]); 77 | 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/IdentifiableStatementHierarchyProvider.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.codeInsight.hint.HintManager; 4 | import com.intellij.ide.hierarchy.HierarchyBrowser; 5 | import com.intellij.ide.hierarchy.HierarchyProvider; 6 | import com.intellij.ide.hierarchy.call.JavaCallHierarchyProvider; 7 | import com.intellij.navigation.NavigationItem; 8 | import com.intellij.openapi.actionSystem.DataContext; 9 | import com.intellij.openapi.actionSystem.LangDataKeys; 10 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 11 | import com.intellij.openapi.editor.Editor; 12 | import com.intellij.openapi.project.Project; 13 | import com.intellij.pom.PomTarget; 14 | import com.intellij.pom.PomTargetPsiElement; 15 | import com.intellij.psi.PsiElement; 16 | import com.intellij.psi.PsiMethod; 17 | import com.intellij.psi.PsiReference; 18 | import com.intellij.psi.search.searches.ReferencesSearch; 19 | import com.intellij.psi.util.PsiTreeUtil; 20 | import com.intellij.util.xml.DomElement; 21 | import com.intellij.util.xml.DomTarget; 22 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMapIdentifiableStatement; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.jetbrains.annotations.Nullable; 25 | 26 | import java.util.Collection; 27 | 28 | /** 29 | * Created with IntelliJ IDEA. 30 | * User: Max 31 | * Date: 02.05.13 32 | * Time: 21:40 33 | */ 34 | public class IdentifiableStatementHierarchyProvider implements HierarchyProvider { 35 | 36 | private HierarchyProvider delegate = new JavaCallHierarchyProvider(); 37 | 38 | @Nullable 39 | @Override 40 | public PsiElement getTarget(@NotNull DataContext dataContext) { 41 | 42 | final Project project = PlatformDataKeys.PROJECT.getData(dataContext); 43 | if (project == null) return null; 44 | 45 | Editor editor = LangDataKeys.EDITOR.getData(dataContext); 46 | if (editor == null) return null; 47 | 48 | PsiElement psiElement = LangDataKeys.PSI_ELEMENT.getData(dataContext); 49 | if (!isIdentifiableStatement(psiElement)) { 50 | return null; 51 | } 52 | assert psiElement != null; 53 | Collection refs = ReferencesSearch.search(psiElement).findAll(); 54 | if (refs.size() == 1) { 55 | PsiElement element = refs.iterator().next().getElement(); 56 | PsiMethod parentMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class, true); 57 | if (parentMethod == null) { 58 | HintManager.getInstance().showErrorHint(editor, "No direct usages in methods found, no hierarchy can be built"); 59 | return null; 60 | } else { 61 | return parentMethod; 62 | } 63 | } else { 64 | HintManager.getInstance().showErrorHint(editor, "Multiple usages found, no hierarchy can be built"); 65 | return null; 66 | } 67 | 68 | } 69 | 70 | @NotNull 71 | @Override 72 | public HierarchyBrowser createHierarchyBrowser(PsiElement target) { 73 | if (target instanceof NavigationItem && ((NavigationItem) target).canNavigate()) { 74 | ((NavigationItem) target).navigate(false); 75 | } 76 | return delegate.createHierarchyBrowser(target); 77 | } 78 | 79 | @Override 80 | public void browserActivated(@NotNull HierarchyBrowser hierarchyBrowser) { 81 | delegate.browserActivated(hierarchyBrowser); 82 | } 83 | 84 | private boolean isIdentifiableStatement(PsiElement element) { 85 | if (element instanceof PomTargetPsiElement) { 86 | PomTarget target = ((PomTargetPsiElement) element).getTarget(); 87 | if (target instanceof DomTarget) { 88 | DomElement domElement = ((DomTarget) target).getDomElement(); 89 | if (domElement instanceof SqlMapIdentifiableStatement) { 90 | return true; 91 | } 92 | } 93 | } 94 | return false; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/GoToSqlMapStatementContributor.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.navigation.NavigationItem; 4 | import com.intellij.openapi.components.ServiceManager; 5 | import com.intellij.openapi.module.Module; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.psi.xml.XmlElement; 8 | import com.intellij.util.CommonProcessors; 9 | import com.intellij.util.xml.ElementPresentationManager; 10 | import com.intellij.util.xml.model.gotosymbol.GoToSymbolProvider; 11 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMapIdentifiableStatement; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import javax.swing.*; 15 | import java.util.ArrayList; 16 | import java.util.Collection; 17 | import java.util.List; 18 | import java.util.Set; 19 | import java.util.regex.Pattern; 20 | 21 | /** 22 | * Created with IntelliJ IDEA. 23 | * User: Max 24 | * Date: 02.09.13 25 | * Time: 21:12 26 | */ 27 | public class GoToSqlMapStatementContributor extends GoToSymbolProvider { 28 | 29 | private static final Pattern dotPattern = Pattern.compile("\\."); 30 | 31 | @Override 32 | protected void addNames(@NotNull Module module, Set result) { 33 | ServiceManager.getService(module.getProject(), DomFileElementsFinder.class).processSqlMapStatementNames(new CommonProcessors.CollectProcessor(result)); 34 | } 35 | 36 | @Override 37 | protected void addItems(@NotNull Module module, String name, List result) { 38 | String[] parts = dotPattern.split(name); 39 | if (parts.length == 1) { 40 | result.addAll(findResults("", parts[0], module.getProject())); 41 | } else { 42 | for (int i = 0; i < parts.length - 1; i++) { 43 | result.addAll(findResults(concatBefore(parts, i), concatAfter(parts, i + 1), module.getProject())); 44 | } 45 | } 46 | } 47 | 48 | @Override 49 | protected boolean acceptModule(Module module) { 50 | return true; 51 | } 52 | 53 | private List findResults(String namespace, String id, Project project) { 54 | 55 | CommonProcessors.CollectUniquesProcessor processor = new CommonProcessors.CollectUniquesProcessor(); 56 | ServiceManager.getService(project, DomFileElementsFinder.class).processSqlMapStatements(namespace, id, processor); 57 | Collection processorResults = processor.getResults(); 58 | final List results = new ArrayList(processorResults.size()); 59 | for (SqlMapIdentifiableStatement statement : processorResults) { 60 | XmlElement psiElement = statement.getId().getXmlElement(); 61 | String value = statement.getId().getStringValue(); 62 | if (psiElement != null && value != null) { 63 | final Icon icon = ElementPresentationManager.getIcon(statement); 64 | if (namespace.length() > 0) { 65 | results.add(new BaseNavigationItem(psiElement, namespace + "." + value, icon)); 66 | } else { 67 | results.add(new BaseNavigationItem(psiElement, value, icon)); 68 | } 69 | } 70 | } 71 | return results; 72 | } 73 | 74 | private String concatBefore(String[] parts, int before) { 75 | StringBuilder sb = new StringBuilder(); 76 | for (int i = 0; i <= before; i++) { 77 | sb.append(parts[i]); 78 | if (i + 1 <= before) { 79 | sb.append("."); 80 | } 81 | } 82 | return sb.toString(); 83 | } 84 | 85 | private String concatAfter(String[] parts, int after) { 86 | StringBuilder sb = new StringBuilder(); 87 | for (int i = after; i < parts.length; i++) { 88 | sb.append(parts[i]); 89 | if (i + 1 < parts.length) { 90 | sb.append("."); 91 | } 92 | } 93 | return sb.toString(); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/MyBatis3ProxiesLineMarkerProvider.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.codeHighlighting.Pass; 4 | import com.intellij.codeInsight.daemon.GutterIconNavigationHandler; 5 | import com.intellij.codeInsight.daemon.LineMarkerInfo; 6 | import com.intellij.codeInsight.daemon.LineMarkerProvider; 7 | import com.intellij.openapi.components.ServiceManager; 8 | import com.intellij.openapi.editor.markup.GutterIconRenderer; 9 | import com.intellij.openapi.util.IconLoader; 10 | import com.intellij.pom.Navigatable; 11 | import com.intellij.psi.*; 12 | import com.intellij.psi.xml.XmlElement; 13 | import com.intellij.util.CommonProcessors; 14 | import com.intellij.util.Function; 15 | import com.intellij.util.NullableFunction; 16 | import com.intellij.util.xml.DomElement; 17 | 18 | import javax.swing.*; 19 | import java.awt.event.MouseEvent; 20 | import java.util.Collection; 21 | import java.util.List; 22 | 23 | /** 24 | * Created by IntelliJ IDEA. 25 | * User: Max 26 | * Date: 01.01.12 27 | * Time: 15:45 28 | */ 29 | public class MyBatis3ProxiesLineMarkerProvider implements LineMarkerProvider { 30 | 31 | private static final Icon navigateToDeclarationIcon = IconLoader.getIcon("/gutter/implementedMethod.png"); 32 | 33 | @Override 34 | public LineMarkerInfo getLineMarkerInfo(PsiElement element) { 35 | 36 | if (element instanceof PsiNameIdentifierOwner) { 37 | 38 | DomFileElementsFinder finder = ServiceManager.getService(element.getProject(), DomFileElementsFinder.class); 39 | CommonProcessors.FindFirstProcessor processor = new CommonProcessors.FindFirstProcessor(); 40 | 41 | if (element instanceof PsiClass) { 42 | finder.processMappers((PsiClass) element, processor); 43 | } else if (element instanceof PsiMethod) { 44 | finder.processMapperStatements((PsiMethod) element, processor); 45 | } 46 | 47 | PsiElement nameIdentifier = ((PsiNameIdentifierOwner) element).getNameIdentifier(); 48 | if (processor.isFound() && nameIdentifier != null) { 49 | return new LineMarkerInfo( 50 | (PsiIdentifier) nameIdentifier, //we just know it, ok 51 | nameIdentifier.getTextRange(), 52 | navigateToDeclarationIcon, 53 | Pass.UPDATE_ALL, 54 | getTooltipProvider(processor.getFoundValue()), 55 | getNavigationHandler(processor.getFoundValue().getXmlElement()), 56 | GutterIconRenderer.Alignment.CENTER 57 | ); 58 | } 59 | } 60 | 61 | return null; 62 | 63 | } 64 | 65 | @Override 66 | public void collectSlowLineMarkers(List elements, Collection result) { 67 | 68 | } 69 | 70 | private Function getTooltipProvider(final DomElement element) { 71 | 72 | return new NullableFunction() { 73 | @Override 74 | public String fun(PsiIdentifier psiIdentifier) { 75 | XmlElement xmlElement = element.getXmlElement(); 76 | if (xmlElement != null) { 77 | return element.getXmlElementName() + " in " + xmlElement.getContainingFile().getName(); 78 | } else { 79 | return null; 80 | } 81 | } 82 | }; 83 | 84 | } 85 | 86 | private GutterIconNavigationHandler getNavigationHandler(final XmlElement statement) { 87 | return new GutterIconNavigationHandler() { 88 | @Override 89 | public void navigate(MouseEvent e, PsiIdentifier elt) { 90 | if (statement instanceof Navigatable) { 91 | ((Navigatable) statement).navigate(true); 92 | } else { 93 | throw new AssertionError("Could not navigate statement " + statement); 94 | } 95 | } 96 | }; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | idea-mini-ibatis 4 | iBATIS/MyBatis mini-plugin 5 | 1.14 6 | Max Ishchenko 7 | 8 | 9 | 11 | Contains essential features only, no datasource integration (yet)
12 | Works for IDEA >= 10.0.3 13 | ]]> 14 |
15 | 16 | 17 | 19 | 1.14 20 | 21 | 22 |
    1.13 23 |
  • Find Usages of Spring beans exception fixed
  • 24 |
25 |
    1.12 26 |
  • Call Hierarchy support for sqlMap statements
  • 27 |
28 |
    1.11 29 |
  • Fixed ClassCastException for groovy strings
  • 30 |
  • Copy Reference support for sqlMap statements
  • 31 |
32 |
    1.10 33 |
  • Not fully qualified statement names support
  • 34 |
  • Red circle of death fixed when you had some empty namespaces and invoked auto completion
  • 35 |
36 |
    1.9 37 |
  • Multiple dots in fully qualified statement name support
  • 38 |
  • Any string literal is a reference now
  • 39 |
  • Computing concatenations for literals
  • 40 |
  • Better File Structure popup presentation
  • 41 |
42 |
    1.8 43 |
  • Better mapper file navigation
  • 44 |
  • Mapper method definition inspection
  • 45 |
46 |
    1.7 47 |
  • result resultMap attribute support
  • 48 |
49 |
    1.6 50 |
  • Occasional StringIndexOutOfBoundsException fixed
  • 51 |
  • parameterMap attribute support
  • 52 |
  • selectKey resultClass attribute support
  • 53 |
54 |
    1.5 55 |
  • Quick Documentation for statement names in Java code
  • 56 |
57 |
    1.4 58 |
  • Support for sqlMaps with no namespace attribute defined
  • 59 |
  • Better sqlMap file navigation
  • 60 |
61 |
    1.3 62 |
  • Error on background mapper detection fixed
  • 63 |
  • Resolving multiple statements with same namespace and id
  • 64 |
65 |
    1.2 66 |
  • include tags support
  • 67 |
  • typeAlias support
  • 68 |
  • MyBatis 3 proxies - Go to Implementation for proxy methods jumps right into xml declaration for the mapper method
  • 69 |
  • Find Usages for sqlMap statements. Finds self-reference as well, that should be fixed
  • 70 |
71 |
    1.1 72 |
  • Showing clickable gutter icons for mapper interface and their methods, no Go to Implementation hotkey support yet
  • 73 |
  • Searching for sqlMaps and mappers in libraries as well
  • 74 |
75 |
    1.0 76 |
  • Go to Declaration for string literals in method arguments
  • 77 |
  • Autocompletion of statement names in string literals in method arguments
  • 78 |
79 | ]]> 80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/IdentifiableStatementReference.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.openapi.components.ServiceManager; 4 | import com.intellij.psi.*; 5 | import com.intellij.psi.impl.JavaConstantExpressionEvaluator; 6 | import com.intellij.psi.impl.PomTargetPsiElementImpl; 7 | import com.intellij.psi.util.PsiTreeUtil; 8 | import com.intellij.psi.xml.XmlElement; 9 | import com.intellij.util.CommonProcessors; 10 | import com.intellij.util.xml.DomTarget; 11 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMapIdentifiableStatement; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Collection; 16 | import java.util.List; 17 | import java.util.regex.Pattern; 18 | 19 | /** 20 | * Created by IntelliJ IDEA. 21 | * User: Max 22 | * Date: 24.12.11 23 | * Time: 23:59 24 | */ 25 | public class IdentifiableStatementReference extends PsiPolyVariantReferenceBase { 26 | 27 | private static final Pattern dotPattern = Pattern.compile("\\."); 28 | 29 | public IdentifiableStatementReference(PsiLiteral expression) { 30 | super(expression); 31 | } 32 | 33 | @NotNull 34 | @Override 35 | public ResolveResult[] multiResolve(boolean b) { 36 | 37 | String value = tryComputeConcatenatedValue(); 38 | if (value.length() == 0) { 39 | return ResolveResult.EMPTY_ARRAY; 40 | } 41 | 42 | String[] parts = dotPattern.split(value); 43 | 44 | if (parts.length == 1) { 45 | return findResults("", parts[0]).toArray(ResolveResult.EMPTY_ARRAY); 46 | } else { 47 | List results = new ArrayList(); 48 | for (int i = 0; i < parts.length - 1; i++) { 49 | results.addAll(findResults(concatBefore(parts, i), concatAfter(parts, i + 1))); 50 | } 51 | return results.toArray(new ResolveResult[results.size()]); 52 | } 53 | 54 | } 55 | 56 | @NotNull 57 | public Object[] getVariants() { 58 | 59 | CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(); 60 | ServiceManager.getService(getElement().getProject(), DomFileElementsFinder.class).processSqlMapStatementNames(processor); 61 | return processor.toArray(new String[processor.getResults().size()]); 62 | 63 | } 64 | 65 | private String tryComputeConcatenatedValue() { 66 | 67 | PsiPolyadicExpression parentExpression = PsiTreeUtil.getParentOfType(getElement(), PsiPolyadicExpression.class); 68 | 69 | if (parentExpression != null) { 70 | StringBuilder computedValue = new StringBuilder(); 71 | for (PsiExpression operand : parentExpression.getOperands()) { 72 | if (operand instanceof PsiReference) { 73 | PsiElement probableDefinition = ((PsiReference) operand).resolve(); 74 | if (probableDefinition instanceof PsiVariable) { 75 | PsiExpression initializer = ((PsiVariable) probableDefinition).getInitializer(); 76 | if (initializer != null) { 77 | Object value = JavaConstantExpressionEvaluator.computeConstantExpression(initializer, true); 78 | if (value instanceof String) { 79 | computedValue.append(value); 80 | } 81 | } 82 | } 83 | } else { 84 | Object value = JavaConstantExpressionEvaluator.computeConstantExpression(operand, true); 85 | if (value instanceof String) { 86 | computedValue.append(value); 87 | } 88 | } 89 | } 90 | return computedValue.toString(); 91 | } else { 92 | String rawText = getElement().getText(); 93 | //with quotes, i.e. at least "x" count 94 | if (rawText.length() < 3) { 95 | return ""; 96 | } 97 | //clean up quotes 98 | return rawText.substring(1, rawText.length() - 1); 99 | } 100 | 101 | } 102 | 103 | private List findResults(String namespace, String id) { 104 | 105 | CommonProcessors.CollectUniquesProcessor processor = new CommonProcessors.CollectUniquesProcessor(); 106 | ServiceManager.getService(getElement().getProject(), DomFileElementsFinder.class).processSqlMapStatements(namespace, id, processor); 107 | 108 | Collection processorResults = processor.getResults(); 109 | final List results = new ArrayList(processorResults.size()); 110 | final SqlMapIdentifiableStatement[] statements = processorResults.toArray(new SqlMapIdentifiableStatement[processorResults.size()]); 111 | for (SqlMapIdentifiableStatement statement : statements) { 112 | DomTarget target = DomTarget.getTarget(statement); 113 | if (target != null) { 114 | XmlElement xmlElement = statement.getXmlElement(); 115 | final String locationString = xmlElement != null ? xmlElement.getContainingFile().getName() : ""; 116 | results.add(new PsiElementResolveResult(new PomTargetPsiElementImpl(target) { 117 | @Override 118 | public String getLocationString() { 119 | return locationString; 120 | } 121 | })); 122 | } 123 | } 124 | return results; 125 | } 126 | 127 | private String concatBefore(String[] parts, int before) { 128 | StringBuilder sb = new StringBuilder(); 129 | for (int i = 0; i <= before; i++) { 130 | sb.append(parts[i]); 131 | if (i + 1 <= before) { 132 | sb.append("."); 133 | } 134 | } 135 | return sb.toString(); 136 | } 137 | 138 | private String concatAfter(String[] parts, int after) { 139 | StringBuilder sb = new StringBuilder(); 140 | for (int i = after; i < parts.length; i++) { 141 | sb.append(parts[i]); 142 | if (i + 1 < parts.length) { 143 | sb.append("."); 144 | } 145 | } 146 | return sb.toString(); 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/net/ishchenko/idea/minibatis/DomFileElementsFinder.java: -------------------------------------------------------------------------------- 1 | package net.ishchenko.idea.minibatis; 2 | 3 | import com.intellij.openapi.application.Application; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.psi.PsiClass; 6 | import com.intellij.psi.PsiIdentifier; 7 | import com.intellij.psi.PsiMethod; 8 | import com.intellij.psi.search.GlobalSearchScope; 9 | import com.intellij.util.CommonProcessors; 10 | import com.intellij.util.Processor; 11 | import com.intellij.util.xml.DomElement; 12 | import com.intellij.util.xml.DomFileElement; 13 | import com.intellij.util.xml.DomService; 14 | import net.ishchenko.idea.minibatis.model.mapper.Mapper; 15 | import net.ishchenko.idea.minibatis.model.mapper.MapperIdentifiableStatement; 16 | import net.ishchenko.idea.minibatis.model.sqlmap.ResultMap; 17 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMap; 18 | import net.ishchenko.idea.minibatis.model.sqlmap.SqlMapIdentifiableStatement; 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.List; 22 | 23 | /** 24 | * Created by IntelliJ IDEA. 25 | * User: Max 26 | * Date: 01.01.12 27 | * Time: 16:03 28 | */ 29 | public class DomFileElementsFinder { 30 | 31 | private final Project project; 32 | private final DomService domService; 33 | private final Application application; 34 | 35 | public DomFileElementsFinder(Project project, DomService domService, Application application) { 36 | this.project = project; 37 | this.domService = domService; 38 | this.application = application; 39 | } 40 | 41 | public void processSqlMapStatements(@NotNull String targetNamespace, @NotNull String targetId, @NotNull Processor processor) { 42 | 43 | nsloop: 44 | for (DomFileElement fileElement : findSqlMapFileElements()) { 45 | SqlMap sqlMap = fileElement.getRootElement(); 46 | String namespace = sqlMap.getNamespace().getRawText(); 47 | if (targetNamespace.equals(namespace) || targetNamespace.length() == 0) { 48 | for (SqlMapIdentifiableStatement statement : sqlMap.getIdentifiableStatements()) { 49 | if (targetId.equals(statement.getId().getRawText())) { 50 | if (!processor.process(statement)) { 51 | return; 52 | } 53 | continue nsloop; 54 | } 55 | } 56 | } 57 | } 58 | 59 | } 60 | 61 | public void processSqlMapStatementNames(@NotNull Processor processor) { 62 | 63 | for (DomFileElement fileElement : findSqlMapFileElements()) { 64 | SqlMap rootElement = fileElement.getRootElement(); 65 | String namespace = rootElement.getNamespace().getRawText(); 66 | for (SqlMapIdentifiableStatement statement : rootElement.getIdentifiableStatements()) { 67 | String id = statement.getId().getRawText(); 68 | if (id != null && (namespace != null && !processor.process(namespace + "." + id) || namespace == null && !processor.process(id))) { 69 | return; 70 | } 71 | } 72 | } 73 | 74 | } 75 | 76 | public void processSqlMaps(@NotNull String targetNamespace, @NotNull Processor processor) { 77 | 78 | for (DomFileElement fileElement : findSqlMapFileElements()) { 79 | SqlMap sqlMap = fileElement.getRootElement(); 80 | String namespace = sqlMap.getNamespace().getRawText(); 81 | if (targetNamespace.equals(namespace)) { 82 | if (!processor.process(sqlMap)) { 83 | return; 84 | } 85 | } 86 | } 87 | 88 | } 89 | 90 | public void processSqlMapNamespaceNames(CommonProcessors.CollectProcessor processor) { 91 | 92 | for (DomFileElement fileElement : findSqlMapFileElements()) { 93 | SqlMap sqlMap = fileElement.getRootElement(); 94 | if (sqlMap.getNamespace().getRawText() != null && !processor.process(sqlMap.getNamespace().getRawText())) { 95 | return; 96 | } 97 | } 98 | } 99 | 100 | public void processResultMaps(@NotNull String targetNamespace, @NotNull String targetId, @NotNull Processor processor) { 101 | 102 | nsloop: 103 | for (DomFileElement fileElement : findSqlMapFileElements()) { 104 | SqlMap rootElement = fileElement.getRootElement(); 105 | String namespace = rootElement.getNamespace().getRawText(); 106 | if (targetNamespace.equals(namespace) || targetNamespace.length() == 0 && namespace == null) { 107 | for (ResultMap resultMap : rootElement.getResultMaps()) { 108 | if (targetId.equals(resultMap.getId().getRawText())) { 109 | if (!processor.process(resultMap)) { 110 | return; 111 | } 112 | continue nsloop; 113 | } 114 | } 115 | } 116 | 117 | } 118 | 119 | } 120 | 121 | public void processResultMapNames(@NotNull Processor processor) { 122 | 123 | for (DomFileElement fileElement : findSqlMapFileElements()) { 124 | SqlMap rootElement = fileElement.getRootElement(); 125 | String namespace = rootElement.getNamespace().getRawText(); 126 | for (ResultMap resultMap : rootElement.getResultMaps()) { 127 | String id = resultMap.getId().getRawText(); 128 | if (id != null && (namespace != null && !processor.process(namespace + "." + id) || namespace == null && !processor.process(id))) { 129 | return; 130 | } 131 | } 132 | } 133 | 134 | } 135 | 136 | public void processMappers(@NotNull final PsiClass clazz, @NotNull final Processor processor) { 137 | application.runReadAction(new Runnable() { 138 | @Override 139 | public void run() { 140 | if (clazz.isInterface()) { 141 | PsiIdentifier nameIdentifier = clazz.getNameIdentifier(); 142 | String qualifiedName = clazz.getQualifiedName(); 143 | if (nameIdentifier != null && qualifiedName != null) { 144 | processMappers(qualifiedName, processor); 145 | } 146 | } 147 | } 148 | }); 149 | } 150 | 151 | public void processMapperStatements(@NotNull final PsiMethod method, @NotNull final Processor processor) { 152 | 153 | application.runReadAction(new Runnable() { 154 | @Override 155 | public void run() { 156 | PsiClass clazz = method.getContainingClass(); 157 | if (clazz != null && clazz.isInterface()) { 158 | String qualifiedName = clazz.getQualifiedName(); 159 | String methodName = method.getName(); 160 | if (qualifiedName != null) { 161 | processMapperStatements(qualifiedName, methodName, processor); 162 | } 163 | } 164 | } 165 | }); 166 | 167 | } 168 | 169 | public boolean existsMapperStatement(PsiMethod method) { 170 | CommonProcessors.FindFirstProcessor processor = new CommonProcessors.FindFirstProcessor(); 171 | processMapperStatements(method, processor); 172 | return processor.isFound(); 173 | } 174 | 175 | private void processMappers(String className, Processor processor) { 176 | for (DomFileElement fileElement : findMapperFileElements()) { 177 | Mapper mapper = fileElement.getRootElement(); 178 | if (className.equals(mapper.getNamespace().getRawText())) { 179 | if (!processor.process(mapper)) { 180 | return; 181 | } 182 | } 183 | } 184 | } 185 | 186 | private void processMapperStatements(String className, String methodName, Processor processor) { 187 | for (DomFileElement fileElement : findMapperFileElements()) { 188 | Mapper mapper = fileElement.getRootElement(); 189 | if (className.equals(mapper.getNamespace().getRawText())) { 190 | for (MapperIdentifiableStatement statement : mapper.getIdentifiableStatements()) { 191 | if (methodName.equals(statement.getId().getRawText())) { 192 | if (!processor.process(statement)) { 193 | return; 194 | } 195 | } 196 | } 197 | } 198 | } 199 | } 200 | 201 | private List> findSqlMapFileElements() { 202 | return domService.getFileElements(SqlMap.class, project, GlobalSearchScope.allScope(project)); 203 | } 204 | 205 | private List> findMapperFileElements() { 206 | return domService.getFileElements(Mapper.class, project, GlobalSearchScope.allScope(project)); 207 | } 208 | } 209 | 210 | 211 | --------------------------------------------------------------------------------