├── .gitignore ├── README.md ├── docker-compose.yml ├── pom.xml └── src ├── main ├── antlr4 │ └── evolution │ │ └── analysis │ │ ├── jv │ │ ├── JavaLexer.g4 │ │ └── JavaParser.g4 │ │ └── sql │ │ └── Sql.g4 ├── docker │ └── Dockerfile ├── java │ └── evolution │ │ ├── Main.java │ │ ├── analysis │ │ └── jv │ │ │ ├── ParseClassApp.java │ │ │ ├── ParseClassService.java │ │ │ ├── ParsePackageService.java │ │ │ ├── ProcessFiles.java │ │ │ ├── calls │ │ │ ├── JavaCallApp.java │ │ │ ├── JavaCallVisitor.java │ │ │ ├── JavaDaoParser.java │ │ │ ├── JavaMethodCallStore.java │ │ │ ├── model │ │ │ │ └── JMethodCall.java │ │ │ └── plugins │ │ │ │ ├── JavaDaoStringParser.java │ │ │ │ ├── MyBatisParser.java │ │ │ │ └── sql │ │ │ │ ├── TableOpParser.java │ │ │ │ └── TableVisitor.java │ │ │ └── identifier │ │ │ ├── JIdentifier.java │ │ │ ├── JMethod.java │ │ │ ├── JavaClassQuery.java │ │ │ ├── JavaFileParser.java │ │ │ ├── JavaIdentifierApp.java │ │ │ ├── JavaIdentifierStore.java │ │ │ └── JavaIdentifierVisitor.java │ │ ├── configuration │ │ └── ConfigReader.java │ │ ├── factory │ │ ├── ServiceFactory.java │ │ └── daoparser │ │ │ ├── DaoParserProvider.java │ │ │ ├── DaoParserTypeEnum.java │ │ │ ├── JavaDaoParserFactory.java │ │ │ └── OutOfJavaDaoParserEnumError.java │ │ └── store │ │ ├── HelloWorldExample.java │ │ ├── Neo4JDriverFactory.java │ │ └── StoreManager.java └── resources │ ├── application.yaml │ └── logging.properties └── test └── java └── evolution ├── ConfigReaderTest.java ├── MainTest.java ├── analysis └── jv │ └── calls │ └── plugins │ └── JavaCallVisitorTest.java └── factory └── daoparser ├── FakeConfigReader.java └── JavaDaoParserFactoryTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # BlueJ files 4 | *.ctxt 5 | 6 | # Mobile Tools for Java (J2ME) 7 | .mtj.tmp/ 8 | 9 | # Package Files # 10 | *.jar 11 | *.war 12 | *.ear 13 | 14 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 15 | hs_err_pid* 16 | 17 | # ANTLR4 and program generated files 18 | target/ 19 | 20 | ParseClassClientDemo.java 21 | prod.yaml 22 | 23 | .settings 24 | .vscode 25 | bin 26 | .classpath 27 | .project 28 | *.iml 29 | *.ipr 30 | *.iws 31 | **/.DS_Store 32 | 33 | **/example/ 34 | # Created by https://www.gitignore.io/api/intellij+all 35 | 36 | ### Intellij+all ### 37 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 38 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 39 | 40 | # User-specific stuff 41 | .idea/**/workspace.xml 42 | .idea/**/tasks.xml 43 | .idea/**/usage.statistics.xml 44 | .idea/**/dictionaries 45 | .idea/**/shelf 46 | 47 | # Generated files 48 | .idea/**/contentModel.xml 49 | 50 | # Sensitive or high-churn files 51 | .idea/**/dataSources/ 52 | .idea/**/dataSources.ids 53 | .idea/**/dataSources.local.xml 54 | .idea/**/sqlDataSources.xml 55 | .idea/**/dynamic.xml 56 | .idea/**/uiDesigner.xml 57 | .idea/**/dbnavigator.xml 58 | 59 | # Gradle 60 | .idea/**/gradle.xml 61 | .idea/**/libraries 62 | 63 | # Gradle and Maven with auto-import 64 | # When using Gradle or Maven with auto-import, you should exclude module files, 65 | # since they will be recreated, and may cause churn. Uncomment if using 66 | # auto-import. 67 | # .idea/modules.xml 68 | # .idea/*.iml 69 | # .idea/modules 70 | 71 | # CMake 72 | cmake-build-*/ 73 | 74 | # Mongo Explorer plugin 75 | .idea/**/mongoSettings.xml 76 | 77 | # File-based project format 78 | *.iws 79 | 80 | # IntelliJ 81 | out/ 82 | 83 | # mpeltonen/sbt-idea plugin 84 | .idea_modules/ 85 | 86 | # JIRA plugin 87 | atlassian-ide-plugin.xml 88 | 89 | # Cursive Clojure plugin 90 | .idea/replstate.xml 91 | 92 | # Crashlytics plugin (for Android Studio and IntelliJ) 93 | com_crashlytics_export_strings.xml 94 | crashlytics.properties 95 | crashlytics-build.properties 96 | fabric.properties 97 | 98 | # Editor-based Rest Client 99 | .idea/httpRequests 100 | 101 | # Android studio 3.1+ serialized cache file 102 | .idea/caches/build_file_checksums.ser 103 | 104 | ### Intellij+all Patch ### 105 | # Ignores the whole .idea folder and all .iml files 106 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 107 | 108 | .idea/ 109 | 110 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 111 | 112 | *.iml 113 | modules.xml 114 | .idea/misc.xml 115 | *.ipr 116 | 117 | 118 | # End of https://www.gitignore.io/api/intellij+all 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Analysis Java Dependence 2 | 3 | #Setup analysis java server 4 | ``` 5 | docker build -t analysis_java -f src/main/docker/Dockerfile . 6 | docker-compose up 7 | ``` 8 | 9 | #Useage 10 | the server is running 11 | ``` 12 | GET http://localhost:8080/greet/world 13 | ``` 14 | 15 | analysis API 16 | ``` 17 | POST http://localhost:8080/analysis/class/{class} 18 | POST http://localhost:8080/analysis/package/{package} 19 | ``` -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | networks: 4 | neo4j: 5 | driver: bridge 6 | 7 | services: 8 | 9 | analysis_java: 10 | image: analysis_java 11 | depends_on: 12 | - neo4j 13 | volumes: ## adds app folder to the container 14 | - /Users/xfwu/Workspace/petclinet/:/workspace 15 | networks: ## connects neo4j to app container 16 | - neo4j 17 | ports: ## publish ports 18 | - "8080:8080" 19 | working_dir: /app ## uses work dir /app 20 | 21 | neo4j: 22 | image: neo4j:3.4 ## we use neo4j v3 23 | ports: ## publish ports to have Web UI 24 | - "7474:7474" 25 | - "7687:7687" 26 | networks: 27 | - neo4j 28 | volumes: ## adds folder with login/password 29 | - $HOME/neo4j/data:/data 30 | #--env=NEO4J_dbms_memory_pagecache_size=2G --env=NEO4J_dbms_memory_heap_max__size=2G 31 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | me.refactoring.analysis 6 | dependencies_java 7 | 1.0 8 | jar 9 | 10 | dependencies_java 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | true 16 | true 17 | 18 | 19 | 20 | 21 | 22 | org.neo4j.driver 23 | neo4j-java-driver 24 | 1.4.4 25 | 26 | 27 | 28 | org.antlr 29 | antlr4-runtime 30 | 4.7 31 | 32 | 33 | io.helidon.webserver 34 | helidon-webserver-bundle 35 | 0.10.0 36 | 37 | 38 | io.helidon.config 39 | helidon-config-yaml 40 | 0.10.0 41 | 42 | 43 | org.junit.jupiter 44 | junit-jupiter-api 45 | 5.1.0 46 | test 47 | 48 | 49 | org.junit.jupiter 50 | junit-jupiter-engine 51 | 5.1.0 52 | test 53 | 54 | 55 | org.junit.platform 56 | junit-platform-surefire-provider 57 | 1.0.3 58 | 59 | 60 | org.hamcrest 61 | hamcrest-library 62 | 1.3 63 | test 64 | 65 | 66 | 67 | 68 | 69 | 70 | src/main/resources 71 | 72 | 73 | 74 | 75 | 76 | org.apache.maven.plugins 77 | maven-compiler-plugin 78 | 3.1 79 | 80 | 1.8 81 | 1.8 82 | 83 | 84 | 91 | 92 | org.antlr 93 | antlr4-maven-plugin 94 | 4.7 95 | 96 | 97 | 98 | antlr4 99 | 100 | 101 | 102 | 103 | 104 | org.apache.maven.plugins 105 | maven-resources-plugin 106 | 3.0.2 107 | 108 | 112 | 137 | 138 | org.apache.maven.plugins 139 | maven-dependency-plugin 140 | 141 | 142 | copy-dependencies 143 | prepare-package 144 | 145 | copy-dependencies 146 | 147 | 148 | ${project.build.directory}/libs 149 | false 150 | false 151 | true 152 | true 153 | runtime 154 | test 155 | 156 | 157 | 158 | 159 | 160 | 161 | org.apache.maven.plugins 162 | maven-jar-plugin 163 | 3.1.0 164 | 165 | 166 | 167 | true 168 | libs 169 | evolution.Main 170 | 171 | 172 | 173 | 174 | 175 | org.apache.maven.plugins 176 | maven-surefire-plugin 177 | 2.19.1 178 | 179 | 180 | org.junit.platform 181 | junit-platform-surefire-provider 182 | 1.1.0 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /src/main/antlr4/evolution/analysis/jv/JavaLexer.g4: -------------------------------------------------------------------------------- 1 | /* 2 | [The "BSD licence"] 3 | Copyright (c) 2013 Terence Parr, Sam Harwell 4 | Copyright (c) 2017 Ivan Kochurkin (upgrade to Java 8) 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 3. The name of the author may not be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | lexer grammar JavaLexer; 31 | 32 | // Keywords 33 | 34 | ABSTRACT: 'abstract'; 35 | ASSERT: 'assert'; 36 | BOOLEAN: 'boolean'; 37 | BREAK: 'break'; 38 | BYTE: 'byte'; 39 | CASE: 'case'; 40 | CATCH: 'catch'; 41 | CHAR: 'char'; 42 | CLASS: 'class'; 43 | CONST: 'const'; 44 | CONTINUE: 'continue'; 45 | DEFAULT: 'default'; 46 | DO: 'do'; 47 | DOUBLE: 'double'; 48 | ELSE: 'else'; 49 | ENUM: 'enum'; 50 | EXTENDS: 'extends'; 51 | FINAL: 'final'; 52 | FINALLY: 'finally'; 53 | FLOAT: 'float'; 54 | FOR: 'for'; 55 | IF: 'if'; 56 | GOTO: 'goto'; 57 | IMPLEMENTS: 'implements'; 58 | IMPORT: 'import'; 59 | INSTANCEOF: 'instanceof'; 60 | INT: 'int'; 61 | INTERFACE: 'interface'; 62 | LONG: 'long'; 63 | NATIVE: 'native'; 64 | NEW: 'new'; 65 | PACKAGE: 'package'; 66 | PRIVATE: 'private'; 67 | PROTECTED: 'protected'; 68 | PUBLIC: 'public'; 69 | RETURN: 'return'; 70 | SHORT: 'short'; 71 | STATIC: 'static'; 72 | STRICTFP: 'strictfp'; 73 | SUPER: 'super'; 74 | SWITCH: 'switch'; 75 | SYNCHRONIZED: 'synchronized'; 76 | THIS: 'this'; 77 | THROW: 'throw'; 78 | THROWS: 'throws'; 79 | TRANSIENT: 'transient'; 80 | TRY: 'try'; 81 | VOID: 'void'; 82 | VOLATILE: 'volatile'; 83 | WHILE: 'while'; 84 | 85 | // Literals 86 | 87 | DECIMAL_LITERAL: ('0' | [1-9] (Digits? | '_'+ Digits)) [lL]?; 88 | HEX_LITERAL: '0' [xX] [0-9a-fA-F] ([0-9a-fA-F_]* [0-9a-fA-F])? [lL]?; 89 | OCT_LITERAL: '0' '_'* [0-7] ([0-7_]* [0-7])? [lL]?; 90 | BINARY_LITERAL: '0' [bB] [01] ([01_]* [01])? [lL]?; 91 | 92 | FLOAT_LITERAL: (Digits '.' Digits? | '.' Digits) ExponentPart? [fFdD]? 93 | | Digits (ExponentPart [fFdD]? | [fFdD]) 94 | ; 95 | 96 | HEX_FLOAT_LITERAL: '0' [xX] (HexDigits '.'? | HexDigits? '.' HexDigits) [pP] [+-]? Digits [fFdD]?; 97 | 98 | BOOL_LITERAL: 'true' 99 | | 'false' 100 | ; 101 | 102 | CHAR_LITERAL: '\'' (~['\\\r\n] | EscapeSequence) '\''; 103 | 104 | STRING_LITERAL: '"' (~["\\\r\n] | EscapeSequence)* '"'; 105 | 106 | NULL_LITERAL: 'null'; 107 | 108 | // Separators 109 | 110 | LPAREN: '('; 111 | RPAREN: ')'; 112 | LBRACE: '{'; 113 | RBRACE: '}'; 114 | LBRACK: '['; 115 | RBRACK: ']'; 116 | SEMI: ';'; 117 | COMMA: ','; 118 | DOT: '.'; 119 | 120 | // Operators 121 | 122 | ASSIGN: '='; 123 | GT: '>'; 124 | LT: '<'; 125 | BANG: '!'; 126 | TILDE: '~'; 127 | QUESTION: '?'; 128 | COLON: ':'; 129 | EQUAL: '=='; 130 | LE: '<='; 131 | GE: '>='; 132 | NOTEQUAL: '!='; 133 | AND: '&&'; 134 | OR: '||'; 135 | INC: '++'; 136 | DEC: '--'; 137 | ADD: '+'; 138 | SUB: '-'; 139 | MUL: '*'; 140 | DIV: '/'; 141 | BITAND: '&'; 142 | BITOR: '|'; 143 | CARET: '^'; 144 | MOD: '%'; 145 | 146 | ADD_ASSIGN: '+='; 147 | SUB_ASSIGN: '-='; 148 | MUL_ASSIGN: '*='; 149 | DIV_ASSIGN: '/='; 150 | AND_ASSIGN: '&='; 151 | OR_ASSIGN: '|='; 152 | XOR_ASSIGN: '^='; 153 | MOD_ASSIGN: '%='; 154 | LSHIFT_ASSIGN: '<<='; 155 | RSHIFT_ASSIGN: '>>='; 156 | URSHIFT_ASSIGN: '>>>='; 157 | 158 | // Java 8 tokens 159 | 160 | ARROW: '->'; 161 | COLONCOLON: '::'; 162 | 163 | // Additional symbols not defined in the lexical specification 164 | 165 | AT: '@'; 166 | ELLIPSIS: '...'; 167 | 168 | // Whitespace and comments 169 | 170 | WS: [ \t\r\n\u000C]+ -> channel(HIDDEN); 171 | COMMENT: '/*' .*? '*/' -> channel(HIDDEN); 172 | LINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN); 173 | 174 | // Identifiers 175 | 176 | IDENTIFIER: Letter LetterOrDigit*; 177 | 178 | // Fragment rules 179 | 180 | fragment ExponentPart 181 | : [eE] [+-]? Digits 182 | ; 183 | 184 | fragment EscapeSequence 185 | : '\\' [btnfr"'\\] 186 | | '\\' ([0-3]? [0-7])? [0-7] 187 | | '\\' 'u'+ HexDigit HexDigit HexDigit HexDigit 188 | ; 189 | 190 | fragment HexDigits 191 | : HexDigit ((HexDigit | '_')* HexDigit)? 192 | ; 193 | 194 | fragment HexDigit 195 | : [0-9a-fA-F] 196 | ; 197 | 198 | fragment Digits 199 | : [0-9] ([0-9_]* [0-9])? 200 | ; 201 | 202 | fragment LetterOrDigit 203 | : Letter 204 | | [0-9] 205 | ; 206 | 207 | fragment Letter 208 | : [a-zA-Z$_] // these are the "java letters" below 0x7F 209 | | ~[\u0000-\u007F\uD800-\uDBFF] // covers all characters above 0x7F which are not a surrogate 210 | | [\uD800-\uDBFF] [\uDC00-\uDFFF] // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF 211 | ; 212 | -------------------------------------------------------------------------------- /src/main/antlr4/evolution/analysis/jv/JavaParser.g4: -------------------------------------------------------------------------------- 1 | /* 2 | [The "BSD licence"] 3 | Copyright (c) 2013 Terence Parr, Sam Harwell 4 | Copyright (c) 2017 Ivan Kochurkin (upgrade to Java 8) 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 3. The name of the author may not be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | parser grammar JavaParser; 31 | 32 | options { tokenVocab=JavaLexer; } 33 | 34 | compilationUnit 35 | : packageDeclaration? importDeclaration* typeDeclaration* EOF 36 | ; 37 | 38 | packageDeclaration 39 | : annotation* PACKAGE qualifiedName ';' 40 | ; 41 | 42 | importDeclaration 43 | : IMPORT STATIC? qualifiedName ('.' '*')? ';' 44 | ; 45 | 46 | typeDeclaration 47 | : classOrInterfaceModifier* 48 | (classDeclaration | enumDeclaration | interfaceDeclaration | annotationTypeDeclaration) 49 | | ';' 50 | ; 51 | 52 | modifier 53 | : classOrInterfaceModifier 54 | | NATIVE 55 | | SYNCHRONIZED 56 | | TRANSIENT 57 | | VOLATILE 58 | ; 59 | 60 | classOrInterfaceModifier 61 | : annotation 62 | | PUBLIC 63 | | PROTECTED 64 | | PRIVATE 65 | | STATIC 66 | | ABSTRACT 67 | | FINAL // FINAL for class only -- does not apply to interfaces 68 | | STRICTFP 69 | ; 70 | 71 | variableModifier 72 | : FINAL 73 | | annotation 74 | ; 75 | 76 | classDeclaration 77 | : CLASS IDENTIFIER typeParameters? 78 | (EXTENDS typeType)? 79 | (IMPLEMENTS typeList)? 80 | classBody 81 | ; 82 | 83 | typeParameters 84 | : '<' typeParameter (',' typeParameter)* '>' 85 | ; 86 | 87 | typeParameter 88 | : annotation* IDENTIFIER (EXTENDS typeBound)? 89 | ; 90 | 91 | typeBound 92 | : typeType ('&' typeType)* 93 | ; 94 | 95 | enumDeclaration 96 | : ENUM IDENTIFIER (IMPLEMENTS typeList)? '{' enumConstants? ','? enumBodyDeclarations? '}' 97 | ; 98 | 99 | enumConstants 100 | : enumConstant (',' enumConstant)* 101 | ; 102 | 103 | enumConstant 104 | : annotation* IDENTIFIER arguments? classBody? 105 | ; 106 | 107 | enumBodyDeclarations 108 | : ';' classBodyDeclaration* 109 | ; 110 | 111 | interfaceDeclaration 112 | : INTERFACE IDENTIFIER typeParameters? (EXTENDS typeList)? interfaceBody 113 | ; 114 | 115 | classBody 116 | : '{' classBodyDeclaration* '}' 117 | ; 118 | 119 | interfaceBody 120 | : '{' interfaceBodyDeclaration* '}' 121 | ; 122 | 123 | classBodyDeclaration 124 | : ';' 125 | | STATIC? block 126 | | modifier* memberDeclaration 127 | ; 128 | 129 | memberDeclaration 130 | : methodDeclaration 131 | | genericMethodDeclaration 132 | | fieldDeclaration 133 | | constructorDeclaration 134 | | genericConstructorDeclaration 135 | | interfaceDeclaration 136 | | annotationTypeDeclaration 137 | | classDeclaration 138 | | enumDeclaration 139 | ; 140 | 141 | /* We use rule this even for void methods which cannot have [] after parameters. 142 | This simplifies grammar and we can consider void to be a type, which 143 | renders the [] matching as a context-sensitive issue or a semantic check 144 | for invalid return type after parsing. 145 | */ 146 | methodDeclaration 147 | : typeTypeOrVoid IDENTIFIER formalParameters ('[' ']')* 148 | (THROWS qualifiedNameList)? 149 | methodBody 150 | ; 151 | 152 | methodBody 153 | : block 154 | | ';' 155 | ; 156 | 157 | typeTypeOrVoid 158 | : typeType 159 | | VOID 160 | ; 161 | 162 | genericMethodDeclaration 163 | : typeParameters methodDeclaration 164 | ; 165 | 166 | genericConstructorDeclaration 167 | : typeParameters constructorDeclaration 168 | ; 169 | 170 | constructorDeclaration 171 | : IDENTIFIER formalParameters (THROWS qualifiedNameList)? constructorBody=block 172 | ; 173 | 174 | fieldDeclaration 175 | : typeType variableDeclarators ';' 176 | ; 177 | 178 | interfaceBodyDeclaration 179 | : modifier* interfaceMemberDeclaration 180 | | ';' 181 | ; 182 | 183 | interfaceMemberDeclaration 184 | : constDeclaration 185 | | interfaceMethodDeclaration 186 | | genericInterfaceMethodDeclaration 187 | | interfaceDeclaration 188 | | annotationTypeDeclaration 189 | | classDeclaration 190 | | enumDeclaration 191 | ; 192 | 193 | constDeclaration 194 | : typeType constantDeclarator (',' constantDeclarator)* ';' 195 | ; 196 | 197 | constantDeclarator 198 | : IDENTIFIER ('[' ']')* '=' variableInitializer 199 | ; 200 | 201 | // see matching of [] comment in methodDeclaratorRest 202 | // methodBody from Java8 203 | interfaceMethodDeclaration 204 | : interfaceMethodModifier* (typeTypeOrVoid | typeParameters annotation* typeTypeOrVoid) 205 | IDENTIFIER formalParameters ('[' ']')* (THROWS qualifiedNameList)? methodBody 206 | ; 207 | 208 | // Java8 209 | interfaceMethodModifier 210 | : annotation 211 | | PUBLIC 212 | | ABSTRACT 213 | | DEFAULT 214 | | STATIC 215 | | STRICTFP 216 | ; 217 | 218 | genericInterfaceMethodDeclaration 219 | : typeParameters interfaceMethodDeclaration 220 | ; 221 | 222 | variableDeclarators 223 | : variableDeclarator (',' variableDeclarator)* 224 | ; 225 | 226 | variableDeclarator 227 | : variableDeclaratorId ('=' variableInitializer)? 228 | ; 229 | 230 | variableDeclaratorId 231 | : IDENTIFIER ('[' ']')* 232 | ; 233 | 234 | variableInitializer 235 | : arrayInitializer 236 | | expression 237 | ; 238 | 239 | arrayInitializer 240 | : '{' (variableInitializer (',' variableInitializer)* (',')? )? '}' 241 | ; 242 | 243 | classOrInterfaceType 244 | : IDENTIFIER typeArguments? ('.' IDENTIFIER typeArguments?)* 245 | ; 246 | 247 | typeArgument 248 | : typeType 249 | | '?' ((EXTENDS | SUPER) typeType)? 250 | ; 251 | 252 | qualifiedNameList 253 | : qualifiedName (',' qualifiedName)* 254 | ; 255 | 256 | formalParameters 257 | : '(' formalParameterList? ')' 258 | ; 259 | 260 | formalParameterList 261 | : formalParameter (',' formalParameter)* (',' lastFormalParameter)? 262 | | lastFormalParameter 263 | ; 264 | 265 | formalParameter 266 | : variableModifier* typeType variableDeclaratorId 267 | ; 268 | 269 | lastFormalParameter 270 | : variableModifier* typeType '...' variableDeclaratorId 271 | ; 272 | 273 | qualifiedName 274 | : IDENTIFIER ('.' IDENTIFIER)* 275 | ; 276 | 277 | literal 278 | : integerLiteral 279 | | floatLiteral 280 | | CHAR_LITERAL 281 | | STRING_LITERAL 282 | | BOOL_LITERAL 283 | | NULL_LITERAL 284 | ; 285 | 286 | integerLiteral 287 | : DECIMAL_LITERAL 288 | | HEX_LITERAL 289 | | OCT_LITERAL 290 | | BINARY_LITERAL 291 | ; 292 | 293 | floatLiteral 294 | : FLOAT_LITERAL 295 | | HEX_FLOAT_LITERAL 296 | ; 297 | 298 | // ANNOTATIONS 299 | 300 | annotation 301 | : '@' qualifiedName ('(' ( elementValuePairs | elementValue )? ')')? 302 | ; 303 | 304 | elementValuePairs 305 | : elementValuePair (',' elementValuePair)* 306 | ; 307 | 308 | elementValuePair 309 | : IDENTIFIER '=' elementValue 310 | ; 311 | 312 | elementValue 313 | : expression 314 | | annotation 315 | | elementValueArrayInitializer 316 | ; 317 | 318 | elementValueArrayInitializer 319 | : '{' (elementValue (',' elementValue)*)? (',')? '}' 320 | ; 321 | 322 | annotationTypeDeclaration 323 | : '@' INTERFACE IDENTIFIER annotationTypeBody 324 | ; 325 | 326 | annotationTypeBody 327 | : '{' (annotationTypeElementDeclaration)* '}' 328 | ; 329 | 330 | annotationTypeElementDeclaration 331 | : modifier* annotationTypeElementRest 332 | | ';' // this is not allowed by the grammar, but apparently allowed by the actual compiler 333 | ; 334 | 335 | annotationTypeElementRest 336 | : typeType annotationMethodOrConstantRest ';' 337 | | classDeclaration ';'? 338 | | interfaceDeclaration ';'? 339 | | enumDeclaration ';'? 340 | | annotationTypeDeclaration ';'? 341 | ; 342 | 343 | annotationMethodOrConstantRest 344 | : annotationMethodRest 345 | | annotationConstantRest 346 | ; 347 | 348 | annotationMethodRest 349 | : IDENTIFIER '(' ')' defaultValue? 350 | ; 351 | 352 | annotationConstantRest 353 | : variableDeclarators 354 | ; 355 | 356 | defaultValue 357 | : DEFAULT elementValue 358 | ; 359 | 360 | // STATEMENTS / BLOCKS 361 | 362 | block 363 | : '{' blockStatement* '}' 364 | ; 365 | 366 | blockStatement 367 | : localVariableDeclaration ';' 368 | | statement 369 | | localTypeDeclaration 370 | ; 371 | 372 | localVariableDeclaration 373 | : variableModifier* typeType variableDeclarators 374 | ; 375 | 376 | localTypeDeclaration 377 | : classOrInterfaceModifier* 378 | (classDeclaration | interfaceDeclaration) 379 | | ';' 380 | ; 381 | 382 | statement 383 | : blockLabel=block 384 | | ASSERT expression (':' expression)? ';' 385 | | IF parExpression statement (ELSE statement)? 386 | | FOR '(' forControl ')' statement 387 | | WHILE parExpression statement 388 | | DO statement WHILE parExpression ';' 389 | | TRY block (catchClause+ finallyBlock? | finallyBlock) 390 | | TRY resourceSpecification block catchClause* finallyBlock? 391 | | SWITCH parExpression '{' switchBlockStatementGroup* switchLabel* '}' 392 | | SYNCHRONIZED parExpression block 393 | | RETURN expression? ';' 394 | | THROW expression ';' 395 | | BREAK IDENTIFIER? ';' 396 | | CONTINUE IDENTIFIER? ';' 397 | | SEMI 398 | | statementExpression=expression ';' 399 | | identifierLabel=IDENTIFIER ':' statement 400 | ; 401 | 402 | catchClause 403 | : CATCH '(' variableModifier* catchType IDENTIFIER ')' block 404 | ; 405 | 406 | catchType 407 | : qualifiedName ('|' qualifiedName)* 408 | ; 409 | 410 | finallyBlock 411 | : FINALLY block 412 | ; 413 | 414 | resourceSpecification 415 | : '(' resources ';'? ')' 416 | ; 417 | 418 | resources 419 | : resource (';' resource)* 420 | ; 421 | 422 | resource 423 | : variableModifier* classOrInterfaceType variableDeclaratorId '=' expression 424 | ; 425 | 426 | /** Matches cases then statements, both of which are mandatory. 427 | * To handle empty cases at the end, we add switchLabel* to statement. 428 | */ 429 | switchBlockStatementGroup 430 | : switchLabel+ blockStatement+ 431 | ; 432 | 433 | switchLabel 434 | : CASE (constantExpression=expression | enumConstantName=IDENTIFIER) ':' 435 | | DEFAULT ':' 436 | ; 437 | 438 | forControl 439 | : enhancedForControl 440 | | forInit? ';' expression? ';' forUpdate=expressionList? 441 | ; 442 | 443 | forInit 444 | : localVariableDeclaration 445 | | expressionList 446 | ; 447 | 448 | enhancedForControl 449 | : variableModifier* typeType variableDeclaratorId ':' expression 450 | ; 451 | 452 | // EXPRESSIONS 453 | 454 | parExpression 455 | : '(' expression ')' 456 | ; 457 | 458 | expressionList 459 | : expression (',' expression)* 460 | ; 461 | 462 | methodCall 463 | : IDENTIFIER '(' expressionList? ')' 464 | ; 465 | 466 | expression 467 | : primary 468 | | expression bop='.' 469 | ( IDENTIFIER 470 | | methodCall 471 | | THIS 472 | | NEW nonWildcardTypeArguments? innerCreator 473 | | SUPER superSuffix 474 | | explicitGenericInvocation 475 | ) 476 | | expression '[' expression ']' 477 | | methodCall 478 | | NEW creator 479 | | '(' typeType ')' expression 480 | | expression postfix=('++' | '--') 481 | | prefix=('+'|'-'|'++'|'--') expression 482 | | prefix=('~'|'!') expression 483 | | expression bop=('*'|'/'|'%') expression 484 | | expression bop=('+'|'-') expression 485 | | expression ('<' '<' | '>' '>' '>' | '>' '>') expression 486 | | expression bop=('<=' | '>=' | '>' | '<') expression 487 | | expression bop=INSTANCEOF typeType 488 | | expression bop=('==' | '!=') expression 489 | | expression bop='&' expression 490 | | expression bop='^' expression 491 | | expression bop='|' expression 492 | | expression bop='&&' expression 493 | | expression bop='||' expression 494 | | expression bop='?' expression ':' expression 495 | | expression 496 | bop=('=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^=' | '>>=' | '>>>=' | '<<=' | '%=') 497 | expression 498 | | lambdaExpression // Java8 499 | 500 | // Java 8 methodReference 501 | | expression '::' typeArguments? IDENTIFIER 502 | | typeType '::' (typeArguments? IDENTIFIER | NEW) 503 | | classType '::' typeArguments? NEW 504 | ; 505 | 506 | // Java8 507 | lambdaExpression 508 | : lambdaParameters '->' lambdaBody 509 | ; 510 | 511 | // Java8 512 | lambdaParameters 513 | : IDENTIFIER 514 | | '(' formalParameterList? ')' 515 | | '(' IDENTIFIER (',' IDENTIFIER)* ')' 516 | ; 517 | 518 | // Java8 519 | lambdaBody 520 | : expression 521 | | block 522 | ; 523 | 524 | primary 525 | : '(' expression ')' 526 | | THIS 527 | | SUPER 528 | | literal 529 | | IDENTIFIER 530 | | typeTypeOrVoid '.' CLASS 531 | | nonWildcardTypeArguments (explicitGenericInvocationSuffix | THIS arguments) 532 | ; 533 | 534 | classType 535 | : (classOrInterfaceType '.')? annotation* IDENTIFIER typeArguments? 536 | ; 537 | 538 | creator 539 | : nonWildcardTypeArguments createdName classCreatorRest 540 | | createdName (arrayCreatorRest | classCreatorRest) 541 | ; 542 | 543 | createdName 544 | : IDENTIFIER typeArgumentsOrDiamond? ('.' IDENTIFIER typeArgumentsOrDiamond?)* 545 | | primitiveType 546 | ; 547 | 548 | innerCreator 549 | : IDENTIFIER nonWildcardTypeArgumentsOrDiamond? classCreatorRest 550 | ; 551 | 552 | arrayCreatorRest 553 | : '[' (']' ('[' ']')* arrayInitializer | expression ']' ('[' expression ']')* ('[' ']')*) 554 | ; 555 | 556 | classCreatorRest 557 | : arguments classBody? 558 | ; 559 | 560 | explicitGenericInvocation 561 | : nonWildcardTypeArguments explicitGenericInvocationSuffix 562 | ; 563 | 564 | typeArgumentsOrDiamond 565 | : '<' '>' 566 | | typeArguments 567 | ; 568 | 569 | nonWildcardTypeArgumentsOrDiamond 570 | : '<' '>' 571 | | nonWildcardTypeArguments 572 | ; 573 | 574 | nonWildcardTypeArguments 575 | : '<' typeList '>' 576 | ; 577 | 578 | typeList 579 | : typeType (',' typeType)* 580 | ; 581 | 582 | typeType 583 | : annotation? (classOrInterfaceType | primitiveType) ('[' ']')* 584 | ; 585 | 586 | primitiveType 587 | : BOOLEAN 588 | | CHAR 589 | | BYTE 590 | | SHORT 591 | | INT 592 | | LONG 593 | | FLOAT 594 | | DOUBLE 595 | ; 596 | 597 | typeArguments 598 | : '<' typeArgument (',' typeArgument)* '>' 599 | ; 600 | 601 | superSuffix 602 | : arguments 603 | | '.' IDENTIFIER arguments? 604 | ; 605 | 606 | explicitGenericInvocationSuffix 607 | : SUPER superSuffix 608 | | IDENTIFIER arguments 609 | ; 610 | 611 | arguments 612 | : '(' expressionList? ')' 613 | ; -------------------------------------------------------------------------------- /src/main/antlr4/evolution/analysis/sql/Sql.g4: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014 by Bart Kiers 5 | * 6 | * Permission is hereby granted, free of charge, to any person 7 | * obtaining a copy of this software and associated documentation 8 | * files (the "Software"), to deal in the Software without 9 | * restriction, including without limitation the rights to use, 10 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following 13 | * conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be 16 | * included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | * OTHER DEALINGS IN THE SOFTWARE. 26 | * 27 | * Project : sqlite-parser; an ANTLR4 grammar for SQLite 28 | * https://github.com/bkiers/sqlite-parser 29 | * Developed by : Bart Kiers, bart@big-o.nl 30 | */ 31 | grammar Sql; 32 | 33 | parse 34 | : ( sql_stmt_list | error )* EOF 35 | ; 36 | 37 | error 38 | : UNEXPECTED_CHAR 39 | { 40 | throw new RuntimeException("UNEXPECTED_CHAR=" + $UNEXPECTED_CHAR.text); 41 | } 42 | ; 43 | 44 | sql_stmt_list 45 | : ';'* sql_stmt ( ';' + sql_stmt )* ';'* 46 | ; 47 | 48 | sql_stmt 49 | : ( K_EXPLAIN ( K_QUERY K_PLAN )? )? ( alter_table_stmt 50 | | analyze_stmt 51 | | attach_stmt 52 | | begin_stmt 53 | | commit_stmt 54 | | compound_select_stmt 55 | | create_index_stmt 56 | | create_table_stmt 57 | | create_trigger_stmt 58 | | create_view_stmt 59 | | create_force_view_stmt 60 | | create_virtual_table_stmt 61 | | delete_stmt 62 | | delete_stmt_limited 63 | | detach_stmt 64 | | drop_index_stmt 65 | | drop_table_stmt 66 | | drop_trigger_stmt 67 | | drop_view_stmt 68 | | factored_select_stmt 69 | | insert_stmt 70 | | pragma_stmt 71 | | reindex_stmt 72 | | release_stmt 73 | | rollback_stmt 74 | | savepoint_stmt 75 | | simple_select_stmt 76 | | select_stmt 77 | | update_stmt 78 | | update_stmt_limited 79 | | vacuum_stmt ) 80 | ; 81 | 82 | alter_table_stmt 83 | : K_ALTER K_TABLE K_ONLY? ( database_name '.' )? source_table_name 84 | ( K_RENAME K_TO new_table_name 85 | | alter_table_add 86 | | K_ADD K_COLUMN? column_def 87 | | alter_table_add_constraint 88 | ) 89 | K_ENABLE? 90 | ; 91 | 92 | alter_table_add_constraint 93 | : K_ADD K_CONSTRAINT any_name table_constraint 94 | ; 95 | 96 | alter_table_add 97 | : K_ADD table_constraint 98 | ; 99 | 100 | analyze_stmt 101 | : K_ANALYZE ( database_name | table_or_index_name | database_name '.' table_or_index_name )? 102 | ; 103 | 104 | attach_stmt 105 | : K_ATTACH K_DATABASE? expr K_AS database_name 106 | ; 107 | 108 | begin_stmt 109 | : K_BEGIN ( K_DEFERRED | K_IMMEDIATE | K_EXCLUSIVE )? ( K_TRANSACTION transaction_name? )? 110 | ; 111 | 112 | commit_stmt 113 | : ( K_COMMIT | K_END ) ( K_TRANSACTION transaction_name? )? 114 | ; 115 | 116 | compound_select_stmt 117 | : ( K_WITH K_RECURSIVE? common_table_expression ( ',' common_table_expression )* )? 118 | select_core ( ( K_UNION K_ALL? | K_INTERSECT | K_EXCEPT ) select_core )+ 119 | ( K_ORDER K_BY ordering_term ( ',' ordering_term )* )? 120 | ( K_LIMIT expr ( ( K_OFFSET | ',' ) expr )? )? 121 | ; 122 | 123 | create_index_stmt 124 | : K_CREATE K_UNIQUE? K_INDEX ( K_IF K_NOT K_EXISTS )? 125 | ( database_name '.' )? index_name K_ON table_name '(' indexed_column ( ',' indexed_column )* ')' 126 | ( K_WHERE expr )? 127 | ; 128 | 129 | create_table_stmt 130 | : K_CREATE ( K_TEMP | K_TEMPORARY )? K_TABLE ( K_IF K_NOT K_EXISTS )? 131 | ( database_name '.' )? table_name 132 | ( '(' column_def ( ',' table_constraint | ',' column_def )* ')' ( K_WITHOUT IDENTIFIER )? 133 | | K_AS select_stmt 134 | ) 135 | ; 136 | 137 | create_trigger_stmt 138 | : K_CREATE ( K_TEMP | K_TEMPORARY )? K_TRIGGER ( K_IF K_NOT K_EXISTS )? 139 | ( database_name '.' )? trigger_name ( K_BEFORE | K_AFTER | K_INSTEAD K_OF )? 140 | ( K_DELETE | K_INSERT | K_UPDATE ( K_OF column_name ( ',' column_name )* )? ) K_ON ( database_name '.' )? table_name 141 | ( K_FOR K_EACH K_ROW )? ( K_WHEN expr )? 142 | K_BEGIN ( ( update_stmt | insert_stmt | delete_stmt | select_stmt ) ';' )+ K_END 143 | ; 144 | 145 | create_view_stmt 146 | : K_CREATE ( K_TEMP | K_TEMPORARY )? K_VIEW ( K_IF K_NOT K_EXISTS )? 147 | ( database_name '.' )? view_name K_AS select_stmt 148 | ; 149 | 150 | create_force_view_stmt 151 | : K_CREATE ( K_TEMP | K_TEMPORARY )? K_FORCE K_VIEW ( K_IF K_NOT K_EXISTS )? 152 | ( database_name '.' )? view_name ( '(' column_name ( ',' column_name )* ')' )? K_AS select_stmt 153 | ; 154 | 155 | 156 | create_virtual_table_stmt 157 | : K_CREATE K_VIRTUAL K_TABLE ( K_IF K_NOT K_EXISTS )? 158 | ( database_name '.' )? table_name 159 | K_USING module_name ( '(' module_argument ( ',' module_argument )* ')' )? 160 | ; 161 | 162 | delete_stmt 163 | : with_clause? K_DELETE K_FROM qualified_table_name 164 | ( K_WHERE expr )? 165 | ; 166 | 167 | delete_stmt_limited 168 | : with_clause? K_DELETE K_FROM qualified_table_name 169 | ( K_WHERE expr )? 170 | ( ( K_ORDER K_BY ordering_term ( ',' ordering_term )* )? 171 | K_LIMIT expr ( ( K_OFFSET | ',' ) expr )? 172 | )? 173 | ; 174 | 175 | detach_stmt 176 | : K_DETACH K_DATABASE? database_name 177 | ; 178 | 179 | drop_index_stmt 180 | : K_DROP K_INDEX ( K_IF K_EXISTS )? ( database_name '.' )? index_name 181 | ; 182 | 183 | drop_table_stmt 184 | : K_DROP K_TABLE ( K_IF K_EXISTS )? ( database_name '.' )? table_name 185 | ; 186 | 187 | drop_trigger_stmt 188 | : K_DROP K_TRIGGER ( K_IF K_EXISTS )? ( database_name '.' )? trigger_name 189 | ; 190 | 191 | drop_view_stmt 192 | : K_DROP K_VIEW ( K_IF K_EXISTS )? ( database_name '.' )? view_name 193 | ; 194 | 195 | factored_select_stmt 196 | : ( K_WITH K_RECURSIVE? common_table_expression ( ',' common_table_expression )* )? 197 | select_core ( compound_operator select_core )* 198 | ( K_ORDER K_BY ordering_term ( ',' ordering_term )* )? 199 | ( K_LIMIT expr ( ( K_OFFSET | ',' ) expr )? )? 200 | ; 201 | 202 | insert_stmt 203 | : with_clause? ( K_INSERT 204 | | K_REPLACE 205 | | K_INSERT K_OR K_REPLACE 206 | | K_INSERT K_OR K_ROLLBACK 207 | | K_INSERT K_OR K_ABORT 208 | | K_INSERT K_OR K_FAIL 209 | | K_INSERT K_OR K_IGNORE ) K_INTO 210 | ( database_name '.' )? table_name ( '(' column_name ( ',' column_name )* ')' )? 211 | ( K_VALUES '(' expr ( ',' expr )* ')' ( ',' '(' expr ( ',' expr )* ')' )* 212 | | select_stmt 213 | | K_DEFAULT K_VALUES 214 | ) 215 | ; 216 | 217 | pragma_stmt 218 | : K_PRAGMA ( database_name '.' )? pragma_name ( '=' pragma_value 219 | | '(' pragma_value ')' )? 220 | ; 221 | 222 | reindex_stmt 223 | : K_REINDEX ( collation_name 224 | | ( database_name '.' )? ( table_name | index_name ) 225 | )? 226 | ; 227 | 228 | release_stmt 229 | : K_RELEASE K_SAVEPOINT? savepoint_name 230 | ; 231 | 232 | rollback_stmt 233 | : K_ROLLBACK ( K_TRANSACTION transaction_name? )? ( K_TO K_SAVEPOINT? savepoint_name )? 234 | ; 235 | 236 | savepoint_stmt 237 | : K_SAVEPOINT savepoint_name 238 | ; 239 | 240 | simple_select_stmt 241 | : ( K_WITH K_RECURSIVE? common_table_expression ( ',' common_table_expression )* )? 242 | select_core ( K_ORDER K_BY ordering_term ( ',' ordering_term )* )? 243 | ( K_LIMIT expr ( ( K_OFFSET | ',' ) expr )? )? 244 | ; 245 | 246 | select_stmt 247 | : ( K_WITH K_RECURSIVE? common_table_expression ( ',' common_table_expression )* )? 248 | select_or_values ( compound_operator select_or_values )* 249 | ( K_ORDER K_BY ordering_term ( ',' ordering_term )* )? 250 | ( K_LIMIT expr ( ( K_OFFSET | ',' ) expr )? )? 251 | ; 252 | 253 | select_or_values 254 | : K_SELECT ( K_DISTINCT | K_ALL )? result_column ( ',' result_column )* 255 | ( K_FROM ( table_or_subquery ( ',' table_or_subquery )* | join_clause ) )? 256 | ( K_WHERE expr )? 257 | ( K_GROUP K_BY expr ( ',' expr )* ( K_HAVING expr )? )? 258 | | K_VALUES '(' expr ( ',' expr )* ')' ( ',' '(' expr ( ',' expr )* ')' )* 259 | ; 260 | 261 | update_stmt 262 | : with_clause? K_UPDATE ( K_OR K_ROLLBACK 263 | | K_OR K_ABORT 264 | | K_OR K_REPLACE 265 | | K_OR K_FAIL 266 | | K_OR K_IGNORE )? qualified_table_name 267 | K_SET column_name '=' expr ( ',' column_name '=' expr )* ( K_WHERE expr )? 268 | ; 269 | 270 | update_stmt_limited 271 | : with_clause? K_UPDATE ( K_OR K_ROLLBACK 272 | | K_OR K_ABORT 273 | | K_OR K_REPLACE 274 | | K_OR K_FAIL 275 | | K_OR K_IGNORE )? qualified_table_name 276 | K_SET column_name '=' expr ( ',' column_name '=' expr )* ( K_WHERE expr )? 277 | ( ( K_ORDER K_BY ordering_term ( ',' ordering_term )* )? 278 | K_LIMIT expr ( ( K_OFFSET | ',' ) expr )? 279 | )? 280 | ; 281 | 282 | vacuum_stmt 283 | : K_VACUUM 284 | ; 285 | 286 | column_def 287 | : column_name ( column_constraint | type_name )* 288 | ; 289 | 290 | type_name 291 | : name ( '(' signed_number (any_name)? ')' 292 | | '(' signed_number (any_name)? ',' signed_number (any_name)? ')' )? 293 | ; 294 | 295 | column_constraint 296 | : ( K_CONSTRAINT name )? 297 | ( column_constraint_primary_key 298 | | column_constraint_foreign_key 299 | | column_constraint_not_null 300 | | column_constraint_null 301 | | K_UNIQUE conflict_clause 302 | | K_CHECK '(' expr ')' 303 | | column_default 304 | | K_COLLATE collation_name 305 | ) 306 | ; 307 | 308 | column_constraint_primary_key 309 | : K_PRIMARY K_KEY ( K_ASC | K_DESC )? conflict_clause K_AUTOINCREMENT? 310 | ; 311 | 312 | column_constraint_foreign_key 313 | : foreign_key_clause 314 | ; 315 | 316 | column_constraint_not_null 317 | : K_NOT K_NULL conflict_clause 318 | ; 319 | 320 | column_constraint_null 321 | : K_NULL conflict_clause 322 | ; 323 | 324 | column_default 325 | : K_DEFAULT (column_default_value | '(' expr ')' | K_NEXTVAL '(' expr ')' | any_name ) ( '::' any_name+ )? 326 | ; 327 | 328 | column_default_value 329 | : ( signed_number | literal_value ) 330 | ; 331 | 332 | conflict_clause 333 | : ( K_ON K_CONFLICT ( K_ROLLBACK 334 | | K_ABORT 335 | | K_FAIL 336 | | K_IGNORE 337 | | K_REPLACE 338 | ) 339 | )? 340 | ; 341 | 342 | /* 343 | SQLite understands the following binary operators, in order from highest to 344 | lowest precedence: 345 | 346 | || 347 | * / % 348 | + - 349 | << >> & | 350 | < <= > >= 351 | = == != <> IS IS NOT IN LIKE GLOB MATCH REGEXP 352 | AND 353 | OR 354 | */ 355 | expr 356 | : literal_value 357 | | BIND_PARAMETER 358 | | ( ( database_name '.' )? table_name '.' )? column_name 359 | | unary_operator expr 360 | | expr '||' expr 361 | | expr ( '*' | '/' | '%' ) expr 362 | | expr ( '+' | '-' ) expr 363 | | expr ( '<<' | '>>' | '&' | '|' ) expr 364 | | expr ( '<' | '<=' | '>' | '>=' ) expr 365 | | expr ( '=' | '==' | '!=' | '<>' | K_IS | K_IS K_NOT | K_IN | K_LIKE | K_GLOB | K_MATCH | K_REGEXP ) expr 366 | | expr K_AND expr 367 | | expr K_OR expr 368 | | function_name '(' ( K_DISTINCT? expr ( ',' expr )* | '*' )? ')' 369 | | '(' expr ')' 370 | | K_CAST '(' expr K_AS type_name ')' 371 | | expr K_COLLATE collation_name 372 | | expr K_NOT? ( K_LIKE | K_GLOB | K_REGEXP | K_MATCH ) expr ( K_ESCAPE expr )? 373 | | expr ( K_ISNULL | K_NOTNULL | K_NOT K_NULL ) 374 | | expr K_IS K_NOT? expr 375 | | expr K_NOT? K_BETWEEN expr K_AND expr 376 | | expr K_NOT? K_IN ( '(' ( select_stmt 377 | | expr ( ',' expr )* 378 | )? 379 | ')' 380 | | ( database_name '.' )? table_name ) 381 | | ( ( K_NOT )? K_EXISTS )? '(' select_stmt ')' 382 | | K_CASE expr? ( K_WHEN expr K_THEN expr )+ ( K_ELSE expr )? K_END 383 | | raise_function 384 | ; 385 | 386 | foreign_key_clause 387 | : K_REFERENCES ( database_name '.' )? foreign_table ( '(' fk_target_column_name ( ',' fk_target_column_name )* ')' )? 388 | ( ( K_ON ( K_DELETE | K_UPDATE ) ( K_SET K_NULL 389 | | K_SET K_DEFAULT 390 | | K_CASCADE 391 | | K_RESTRICT 392 | | K_NO K_ACTION ) 393 | | K_MATCH name 394 | ) 395 | )* 396 | ( K_NOT? K_DEFERRABLE? ( K_INITIALLY K_DEFERRED | K_INITIALLY K_IMMEDIATE | K_ENABLE K_NOVALIDATE)? K_ENABLE? K_DISABLE? )? 397 | ; 398 | 399 | fk_target_column_name 400 | : name 401 | ; 402 | 403 | raise_function 404 | : K_RAISE '(' ( K_IGNORE 405 | | ( K_ROLLBACK | K_ABORT | K_FAIL ) ',' error_message ) 406 | ')' 407 | ; 408 | 409 | indexed_column 410 | : column_name ( K_COLLATE collation_name )? ( K_ASC | K_DESC )? 411 | ; 412 | 413 | table_constraint 414 | : ( K_CONSTRAINT name )? 415 | ( table_constraint_primary_key 416 | | table_constraint_key 417 | | table_constraint_unique 418 | | K_CHECK '(' expr ')' 419 | | table_constraint_foreign_key 420 | ) 421 | ; 422 | 423 | table_constraint_primary_key 424 | : K_PRIMARY K_KEY '(' indexed_column ( ',' indexed_column )* ')' conflict_clause 425 | ; 426 | 427 | table_constraint_foreign_key 428 | : K_FOREIGN K_KEY '(' fk_origin_column_name ( ',' fk_origin_column_name )* ')' foreign_key_clause 429 | ; 430 | 431 | table_constraint_unique 432 | : K_UNIQUE K_KEY? name? '(' indexed_column ( ',' indexed_column )* ')' conflict_clause 433 | ; 434 | 435 | table_constraint_key 436 | : K_KEY name? '(' indexed_column ( ',' indexed_column )* ')' conflict_clause 437 | ; 438 | 439 | fk_origin_column_name 440 | : column_name 441 | ; 442 | 443 | with_clause 444 | : K_WITH K_RECURSIVE? cte_table_name K_AS '(' select_stmt ')' ( ',' cte_table_name K_AS '(' select_stmt ')' )* 445 | ; 446 | 447 | qualified_table_name 448 | : ( database_name '.' )? table_name ( K_INDEXED K_BY index_name 449 | | K_NOT K_INDEXED )? 450 | ; 451 | 452 | ordering_term 453 | : expr ( K_COLLATE collation_name )? ( K_ASC | K_DESC )? 454 | ; 455 | 456 | pragma_value 457 | : signed_number 458 | | name 459 | | STRING_LITERAL 460 | ; 461 | 462 | common_table_expression 463 | : table_name ( '(' column_name ( ',' column_name )* ')' )? K_AS '(' select_stmt ')' 464 | ; 465 | 466 | result_column 467 | : '*' 468 | | table_name '.' '*' 469 | | expr ( K_AS? column_alias )? 470 | ; 471 | 472 | table_or_subquery 473 | : ( database_name '.' )? table_name ( K_AS? table_alias )? 474 | ( K_INDEXED K_BY index_name 475 | | K_NOT K_INDEXED )? 476 | | '(' ( table_or_subquery ( ',' table_or_subquery )* 477 | | join_clause ) 478 | ')' ( K_AS? table_alias )? 479 | | '(' select_stmt ')' ( K_AS? table_alias )? 480 | ; 481 | 482 | join_clause 483 | : table_or_subquery ( join_operator table_or_subquery join_constraint )* 484 | ; 485 | 486 | join_operator 487 | : ',' 488 | | K_NATURAL? ( K_LEFT K_OUTER? | K_INNER | K_CROSS )? K_JOIN 489 | ; 490 | 491 | join_constraint 492 | : ( K_ON expr 493 | | K_USING '(' column_name ( ',' column_name )* ')' )? 494 | ; 495 | 496 | select_core 497 | : K_SELECT ( K_DISTINCT | K_ALL )? result_column ( ',' result_column )* 498 | ( K_FROM ( table_or_subquery ( ',' table_or_subquery )* | join_clause ) )? 499 | ( K_WHERE expr )? 500 | ( K_GROUP K_BY expr ( ',' expr )* ( K_HAVING expr )? )? 501 | | K_VALUES '(' expr ( ',' expr )* ')' ( ',' '(' expr ( ',' expr )* ')' )* 502 | ; 503 | 504 | compound_operator 505 | : K_UNION 506 | | K_UNION K_ALL 507 | | K_INTERSECT 508 | | K_EXCEPT 509 | ; 510 | 511 | cte_table_name 512 | : table_name ( '(' column_name ( ',' column_name )* ')' )? 513 | ; 514 | 515 | signed_number 516 | : ( ( '+' | '-' )? NUMERIC_LITERAL | '*' ) 517 | ; 518 | 519 | literal_value 520 | : NUMERIC_LITERAL 521 | | STRING_LITERAL 522 | | BLOB_LITERAL 523 | | K_NULL 524 | | K_CURRENT_TIME 525 | | K_CURRENT_DATE 526 | | K_CURRENT_TIMESTAMP 527 | ; 528 | 529 | unary_operator 530 | : '-' 531 | | '+' 532 | | '~' 533 | | K_NOT 534 | ; 535 | 536 | error_message 537 | : STRING_LITERAL 538 | ; 539 | 540 | module_argument // TODO check what exactly is permitted here 541 | : expr 542 | | column_def 543 | ; 544 | 545 | column_alias 546 | : IDENTIFIER 547 | | STRING_LITERAL 548 | ; 549 | 550 | keyword 551 | : K_ABORT 552 | | K_ACTION 553 | | K_ADD 554 | | K_AFTER 555 | | K_ALL 556 | | K_ALTER 557 | | K_ANALYZE 558 | | K_AND 559 | | K_AS 560 | | K_ASC 561 | | K_ATTACH 562 | | K_AUTOINCREMENT 563 | | K_BEFORE 564 | | K_BEGIN 565 | | K_BETWEEN 566 | | K_BY 567 | | K_CASCADE 568 | | K_CASE 569 | | K_CAST 570 | | K_CHECK 571 | | K_COLLATE 572 | | K_COLUMN 573 | | K_COMMIT 574 | | K_CONFLICT 575 | | K_CONSTRAINT 576 | | K_CREATE 577 | | K_CROSS 578 | | K_CURRENT_DATE 579 | | K_CURRENT_TIME 580 | | K_CURRENT_TIMESTAMP 581 | | K_DATABASE 582 | | K_DEFAULT 583 | | K_DEFERRABLE 584 | | K_DEFERRED 585 | | K_DELETE 586 | | K_DESC 587 | | K_DETACH 588 | | K_DISTINCT 589 | | K_DROP 590 | | K_EACH 591 | | K_ELSE 592 | | K_END 593 | | K_ENABLE 594 | | K_ESCAPE 595 | | K_EXCEPT 596 | | K_EXCLUSIVE 597 | | K_EXISTS 598 | | K_EXPLAIN 599 | | K_FAIL 600 | | K_FOR 601 | | K_FOREIGN 602 | | K_FROM 603 | | K_FULL 604 | | K_GLOB 605 | | K_GROUP 606 | | K_HAVING 607 | | K_IF 608 | | K_IGNORE 609 | | K_IMMEDIATE 610 | | K_IN 611 | | K_INDEX 612 | | K_INDEXED 613 | | K_INITIALLY 614 | | K_INNER 615 | | K_INSERT 616 | | K_INSTEAD 617 | | K_INTERSECT 618 | | K_INTO 619 | | K_IS 620 | | K_ISNULL 621 | | K_JOIN 622 | | K_KEY 623 | | K_LEFT 624 | | K_LIKE 625 | | K_LIMIT 626 | | K_MATCH 627 | | K_NATURAL 628 | | K_NO 629 | | K_NOT 630 | | K_NOTNULL 631 | | K_NULL 632 | | K_OF 633 | | K_OFFSET 634 | | K_ON 635 | | K_OR 636 | | K_ORDER 637 | | K_OUTER 638 | | K_PLAN 639 | | K_PRAGMA 640 | | K_PRIMARY 641 | | K_QUERY 642 | | K_RAISE 643 | | K_RECURSIVE 644 | | K_REFERENCES 645 | | K_REGEXP 646 | | K_REINDEX 647 | | K_RELEASE 648 | | K_RENAME 649 | | K_REPLACE 650 | | K_RESTRICT 651 | | K_RIGHT 652 | | K_ROLLBACK 653 | | K_ROW 654 | | K_SAVEPOINT 655 | | K_SELECT 656 | | K_SET 657 | | K_TABLE 658 | | K_TEMP 659 | | K_TEMPORARY 660 | | K_THEN 661 | | K_TO 662 | | K_TRANSACTION 663 | | K_TRIGGER 664 | | K_UNION 665 | | K_UNIQUE 666 | | K_UPDATE 667 | | K_USING 668 | | K_VACUUM 669 | | K_VALUES 670 | | K_VIEW 671 | | K_VIRTUAL 672 | | K_WHEN 673 | | K_WHERE 674 | | K_WITH 675 | | K_WITHOUT 676 | | K_NEXTVAL 677 | ; 678 | 679 | // TODO check all names below 680 | 681 | //[a-zA-Z_0-9\t \-\[\]\=]+ 682 | unknown 683 | : .+ 684 | ; 685 | 686 | name 687 | : any_name 688 | ; 689 | 690 | function_name 691 | : any_name 692 | ; 693 | 694 | database_name 695 | : any_name 696 | ; 697 | 698 | source_table_name 699 | : any_name 700 | ; 701 | 702 | table_name 703 | : any_name 704 | ; 705 | 706 | table_or_index_name 707 | : any_name 708 | ; 709 | 710 | new_table_name 711 | : any_name 712 | ; 713 | 714 | column_name 715 | : any_name 716 | ; 717 | 718 | collation_name 719 | : any_name 720 | ; 721 | 722 | foreign_table 723 | : any_name 724 | ; 725 | 726 | index_name 727 | : any_name 728 | ; 729 | 730 | trigger_name 731 | : any_name 732 | ; 733 | 734 | view_name 735 | : any_name 736 | ; 737 | 738 | module_name 739 | : any_name 740 | ; 741 | 742 | pragma_name 743 | : any_name 744 | ; 745 | 746 | savepoint_name 747 | : any_name 748 | ; 749 | 750 | table_alias 751 | : any_name 752 | ; 753 | 754 | transaction_name 755 | : any_name 756 | ; 757 | 758 | any_name 759 | : IDENTIFIER 760 | | keyword 761 | | STRING_LITERAL 762 | | '(' any_name ')' 763 | ; 764 | 765 | SCOL : ';'; 766 | DOT : '.'; 767 | OPEN_PAR : '('; 768 | CLOSE_PAR : ')'; 769 | COMMA : ','; 770 | ASSIGN : '='; 771 | STAR : '*'; 772 | PLUS : '+'; 773 | MINUS : '-'; 774 | TILDE : '~'; 775 | PIPE2 : '||'; 776 | DIV : '/'; 777 | MOD : '%'; 778 | LT2 : '<<'; 779 | GT2 : '>>'; 780 | AMP : '&'; 781 | PIPE : '|'; 782 | LT : '<'; 783 | LT_EQ : '<='; 784 | GT : '>'; 785 | GT_EQ : '>='; 786 | EQ : '=='; 787 | NOT_EQ1 : '!='; 788 | NOT_EQ2 : '<>'; 789 | 790 | // http://www.sqlite.org/lang_keywords.html 791 | K_ABORT : A B O R T; 792 | K_ACTION : A C T I O N; 793 | K_ADD : A D D; 794 | K_AFTER : A F T E R; 795 | K_ALL : A L L; 796 | K_ALTER : A L T E R; 797 | K_ANALYZE : A N A L Y Z E; 798 | K_AND : A N D; 799 | K_AS : A S; 800 | K_ASC : A S C; 801 | K_ATTACH : A T T A C H; 802 | K_AUTOINCREMENT : A U T O I N C R E M E N T; 803 | K_BEFORE : B E F O R E; 804 | K_BEGIN : B E G I N; 805 | K_BETWEEN : B E T W E E N; 806 | K_BY : B Y; 807 | K_CASCADE : C A S C A D E; 808 | K_CASE : C A S E; 809 | K_CAST : C A S T; 810 | K_CHECK : C H E C K; 811 | K_COLLATE : C O L L A T E; 812 | K_COLUMN : C O L U M N; 813 | K_COMMIT : C O M M I T; 814 | K_CONFLICT : C O N F L I C T; 815 | K_CONSTRAINT : C O N S T R A I N T; 816 | K_CREATE : C R E A T E; 817 | K_CROSS : C R O S S; 818 | K_CURRENT_DATE : C U R R E N T '_' D A T E; 819 | K_CURRENT_TIME : C U R R E N T '_' T I M E; 820 | K_CURRENT_TIMESTAMP : C U R R E N T '_' T I M E S T A M P; 821 | K_DATABASE : D A T A B A S E; 822 | K_DEFAULT : D E F A U L T; 823 | K_DEFERRABLE : D E F E R R A B L E; 824 | K_DEFERRED : D E F E R R E D; 825 | K_DELETE : D E L E T E; 826 | K_DESC : D E S C; 827 | K_DETACH : D E T A C H; 828 | K_DISTINCT : D I S T I N C T; 829 | K_DROP : D R O P; 830 | K_EACH : E A C H; 831 | K_ELSE : E L S E; 832 | K_END : E N D; 833 | K_ENABLE : E N A B L E; 834 | K_DISABLE: D I S A B L E; 835 | K_NOVALIDATE: N O V A L I D A T E; 836 | K_ESCAPE : E S C A P E; 837 | K_EXCEPT : E X C E P T; 838 | K_EXCLUSIVE : E X C L U S I V E; 839 | K_EXISTS : E X I S T S; 840 | K_EXPLAIN : E X P L A I N; 841 | K_FAIL : F A I L; 842 | K_FOR : F O R; 843 | K_FOREIGN : F O R E I G N; 844 | K_FROM : F R O M; 845 | K_FULL : F U L L; 846 | K_GLOB : G L O B; 847 | K_GROUP : G R O U P; 848 | K_HAVING : H A V I N G; 849 | K_IF : I F; 850 | K_IGNORE : I G N O R E; 851 | K_IMMEDIATE : I M M E D I A T E; 852 | K_IN : I N; 853 | K_INDEX : I N D E X; 854 | K_INDEXED : I N D E X E D; 855 | K_INITIALLY : I N I T I A L L Y; 856 | K_INNER : I N N E R; 857 | K_INSERT : I N S E R T; 858 | K_INSTEAD : I N S T E A D; 859 | K_INTERSECT : I N T E R S E C T; 860 | K_INTO : I N T O; 861 | K_IS : I S; 862 | K_ISNULL : I S N U L L; 863 | K_JOIN : J O I N; 864 | K_KEY : K E Y; 865 | K_LEFT : L E F T; 866 | K_LIKE : L I K E; 867 | K_LIMIT : L I M I T; 868 | K_MATCH : M A T C H; 869 | K_NATURAL : N A T U R A L; 870 | K_NEXTVAL : N E X T V A L; 871 | K_NO : N O; 872 | K_NOT : N O T; 873 | K_NOTNULL : N O T N U L L; 874 | K_NULL : N U L L; 875 | K_OF : O F; 876 | K_OFFSET : O F F S E T; 877 | K_ON : O N; 878 | K_ONLY : O N L Y; 879 | K_OR : O R; 880 | K_ORDER : O R D E R; 881 | K_OUTER : O U T E R; 882 | K_PLAN : P L A N; 883 | K_PRAGMA : P R A G M A; 884 | K_PRIMARY : P R I M A R Y; 885 | K_QUERY : Q U E R Y; 886 | K_RAISE : R A I S E; 887 | K_RECURSIVE : R E C U R S I V E; 888 | K_REFERENCES : R E F E R E N C E S; 889 | K_REGEXP : R E G E X P; 890 | K_REINDEX : R E I N D E X; 891 | K_RELEASE : R E L E A S E; 892 | K_RENAME : R E N A M E; 893 | K_REPLACE : R E P L A C E; 894 | K_RESTRICT : R E S T R I C T; 895 | K_RIGHT : R I G H T; 896 | K_ROLLBACK : R O L L B A C K; 897 | K_ROW : R O W; 898 | K_SAVEPOINT : S A V E P O I N T; 899 | K_SELECT : S E L E C T; 900 | K_SET : S E T; 901 | K_TABLE : T A B L E; 902 | K_TEMP : T E M P; 903 | K_TEMPORARY : T E M P O R A R Y; 904 | K_THEN : T H E N; 905 | K_TO : T O; 906 | K_TRANSACTION : T R A N S A C T I O N; 907 | K_TRIGGER : T R I G G E R; 908 | K_UNION : U N I O N; 909 | K_UNIQUE : U N I Q U E; 910 | K_UPDATE : U P D A T E; 911 | K_USING : U S I N G; 912 | K_VACUUM : V A C U U M; 913 | K_VALUES : V A L U E S; 914 | K_VIEW : V I E W; 915 | K_FORCE : F O R C E; 916 | K_VIRTUAL : V I R T U A L; 917 | K_WHEN : W H E N; 918 | K_WHERE : W H E R E; 919 | K_WITH : W I T H; 920 | K_WITHOUT : W I T H O U T; 921 | 922 | IDENTIFIER 923 | : '"' (~'"' | '""')* '"' 924 | | '`' (~'`' | '``')* '`' 925 | | '[' ~']'* ']' 926 | | [a-zA-Z_] [a-zA-Z_0-9]* // TODO check: needs more chars in set 927 | ; 928 | 929 | NUMERIC_LITERAL 930 | : DIGIT+ ( '.' DIGIT* )? ( E [-+]? DIGIT+ )? 931 | | '.' DIGIT+ ( E [-+]? DIGIT+ )? 932 | ; 933 | 934 | BIND_PARAMETER 935 | : '?' DIGIT* 936 | | [:@$] IDENTIFIER 937 | ; 938 | 939 | STRING_LITERAL 940 | : '\'' ( ~'\'' | '\'\'' )* '\'' 941 | ; 942 | 943 | BLOB_LITERAL 944 | : X STRING_LITERAL 945 | ; 946 | 947 | SINGLE_LINE_COMMENT 948 | : '--' ~[\r\n]* -> channel(HIDDEN) 949 | ; 950 | 951 | MULTILINE_COMMENT 952 | : '/*' .*? ( '*/' | EOF ) -> channel(HIDDEN) 953 | ; 954 | 955 | SPACES 956 | : [ \u000B\t\r\n] -> channel(HIDDEN) 957 | ; 958 | 959 | UNEXPECTED_CHAR 960 | : . 961 | ; 962 | 963 | fragment DIGIT : [0-9]; 964 | 965 | fragment A : [aA]; 966 | fragment B : [bB]; 967 | fragment C : [cC]; 968 | fragment D : [dD]; 969 | fragment E : [eE]; 970 | fragment F : [fF]; 971 | fragment G : [gG]; 972 | fragment H : [hH]; 973 | fragment I : [iI]; 974 | fragment J : [jJ]; 975 | fragment K : [kK]; 976 | fragment L : [lL]; 977 | fragment M : [mM]; 978 | fragment N : [nN]; 979 | fragment O : [oO]; 980 | fragment P : [pP]; 981 | fragment Q : [qQ]; 982 | fragment R : [rR]; 983 | fragment S : [sS]; 984 | fragment T : [tT]; 985 | fragment U : [uU]; 986 | fragment V : [vV]; 987 | fragment W : [wW]; 988 | fragment X : [xX]; 989 | fragment Y : [yY]; 990 | fragment Z : [zZ]; 991 | -------------------------------------------------------------------------------- /src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | FROM openjdk:8-jre-alpine 18 | 19 | RUN mkdir /app 20 | COPY target/dependencies_java-1.0.jar /app 21 | COPY target/libs /app/libs 22 | 23 | EXPOSE 8080 24 | 25 | ENTRYPOINT ["java"] 26 | CMD ["-jar", "/app/dependencies_java-1.0.jar"] 27 | 28 | #docker build -t dependencies_java -f src/main/docker/Dockerfile . 29 | #docker run --rm -it -p 8080:8080 -v /Users/xfwu/Workspace/petclient:/workspace dependencies_java bash -------------------------------------------------------------------------------- /src/main/java/evolution/Main.java: -------------------------------------------------------------------------------- 1 | package evolution; 2 | 3 | 4 | import evolution.analysis.jv.ParseClassService; 5 | import evolution.configuration.ConfigReader; 6 | import evolution.factory.ServiceFactory; 7 | import evolution.factory.daoparser.DaoParserProvider; 8 | import io.helidon.config.Config; 9 | import io.helidon.webserver.*; 10 | import io.helidon.webserver.json.JsonSupport; 11 | 12 | import javax.json.Json; 13 | import javax.json.JsonObject; 14 | import java.io.IOException; 15 | import java.net.URISyntaxException; 16 | import java.net.URL; 17 | import java.nio.file.Path; 18 | import java.nio.file.Paths; 19 | import java.util.logging.LogManager; 20 | 21 | /** 22 | * Simple rest application. 23 | */ 24 | public final class Main { 25 | 26 | /** 27 | * Cannot be instantiated. 28 | */ 29 | private Main() { } 30 | 31 | /** 32 | * Creates new {@link Routing}. 33 | * 34 | * @return the new instance 35 | */ 36 | private static Routing createRouting() { 37 | DaoParserProvider reader = new ConfigReader(); 38 | ServiceFactory factory = new ServiceFactory(reader); 39 | 40 | return Routing.builder() 41 | .register(JsonSupport.get()) 42 | .register("/greet", new GreetService()) 43 | .register("/analysis/class", factory.createParseClassService()) 44 | .register("/analysis/package", factory.createParsePackageService()) 45 | .build(); 46 | } 47 | 48 | /** 49 | * Application main entry point. 50 | * @param args command line arguments. 51 | * @throws IOException if there are problems reading logging properties 52 | */ 53 | public static void main(final String[] args) throws IOException { 54 | System.out.println("start server"); 55 | startServer(); 56 | } 57 | 58 | /** 59 | * Start the server. 60 | * @return the created {@link WebServer} instance 61 | * @throws IOException if there are problems reading logging properties 62 | */ 63 | protected static WebServer startServer() throws IOException { 64 | 65 | // load logging configuration 66 | LogManager.getLogManager().readConfiguration( 67 | Main.class.getResourceAsStream("/logging.properties")); 68 | 69 | // By default this will pick up application.yaml from the classpath 70 | Config config = Config.create(); 71 | 72 | // Get webserver config from the "server" section of application.yaml 73 | ServerConfiguration serverConfig = 74 | ServerConfiguration.fromConfig(config.get("server")); 75 | 76 | WebServer server = WebServer.create(serverConfig, createRouting()); 77 | 78 | // Start the server and print some info. 79 | server.start().thenAccept(ws -> { 80 | System.out.println( 81 | "WEB server is up! http://localhost:" + ws.port()); 82 | }); 83 | 84 | // Server threads are not demon. NO need to block. Just react. 85 | server.whenShutdown().thenRun(() 86 | -> System.out.println("WEB server is DOWN. Good bye!")); 87 | 88 | return server; 89 | } 90 | 91 | static Path resourcePath(String resourceName) throws URISyntaxException { 92 | URL resourceUrl = Thread.currentThread().getContextClassLoader().getResource(resourceName); 93 | if (resourceUrl != null) { 94 | return Paths.get(resourceUrl.toURI()); 95 | } else { 96 | return null; 97 | } 98 | } 99 | 100 | public static class GreetService implements Service { 101 | 102 | 103 | private String greeting = "Hello"; 104 | /** 105 | * A service registers itself by updating the routine rules. 106 | * @param rules the routing rules. 107 | */ 108 | @Override 109 | public final void update(final Routing.Rules rules) { 110 | rules 111 | .get("/{name}", this::getMessage) 112 | .put("/greeting/{greeting}", this::updateGreeting); 113 | } 114 | 115 | /** 116 | * Return a greeting message using the name that was provided. 117 | * @param request the server request 118 | * @param response the server response 119 | */ 120 | private void getMessage(final ServerRequest request, 121 | final ServerResponse response) { 122 | String name = request.path().param("name"); 123 | String msg = String.format("%s %s!", greeting, name); 124 | 125 | JsonObject returnObject = Json.createObjectBuilder() 126 | .add("message", msg) 127 | .build(); 128 | response.send(returnObject); 129 | } 130 | 131 | /** 132 | * Set the greeting to use in future messages. 133 | * @param request the server request 134 | * @param response the server response 135 | */ 136 | private void updateGreeting(final ServerRequest request, 137 | final ServerResponse response) { 138 | greeting = request.path().param("greeting"); 139 | 140 | JsonObject returnObject = Json.createObjectBuilder() 141 | .add("greeting", greeting) 142 | .build(); 143 | response.send(returnObject); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/ParseClassApp.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv; 2 | 3 | import evolution.analysis.jv.calls.JavaCallApp; 4 | import evolution.analysis.jv.calls.JavaDaoParser; 5 | import evolution.analysis.jv.identifier.JavaClassQuery; 6 | import evolution.analysis.jv.identifier.JavaIdentifierApp; 7 | import evolution.store.Neo4JDriverFactory; 8 | import evolution.store.StoreManager; 9 | import io.helidon.config.Config; 10 | import org.neo4j.driver.v1.Driver; 11 | 12 | import java.io.IOException; 13 | import java.nio.file.Path; 14 | import java.nio.file.Paths; 15 | import java.util.List; 16 | import java.util.logging.Logger; 17 | 18 | public class ParseClassApp { 19 | 20 | private static final Logger LOGGER = Logger.getLogger(ParseClassApp.class.getName()); 21 | private String neo4jServer = Config.create().get("app").get("neo4j-server").asString("localhost"); 22 | public ParseClassApp(){} 23 | public ParseClassApp(String neo4jServer){ 24 | this.neo4jServer = neo4jServer; 25 | } 26 | public void parse(String rootDir, String clz, JavaDaoParser daoParser) throws IOException { 27 | Driver driver = Neo4JDriverFactory.create(neo4jServer); 28 | JavaClassQuery classQuery = new JavaClassQuery(driver); 29 | List clzs = classQuery.load(); 30 | StoreManager store = new StoreManager(driver); 31 | String deleteState=String.format("MATCH (c1:Class{fullname:'%s'})-[r:Has]->(m2) DETACH DELETE c1,r,m2",clz); 32 | System.out.println("Delete: " + clz); 33 | store.update(deleteState); 34 | String file = String.format("%s/src/main/java/%s.java",rootDir,clz.replaceAll("\\.","/")); 35 | 36 | Path path = Paths.get(file); 37 | new JavaIdentifierApp(driver).parse(path); 38 | new JavaCallApp(driver, daoParser).parse(path,clzs); 39 | driver.close(); 40 | LOGGER.info("finished and close driver."); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/ParseClassService.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv; 2 | 3 | import evolution.analysis.jv.calls.plugins.MyBatisParser; 4 | import evolution.factory.daoparser.JavaDaoParserFactory; 5 | import io.helidon.config.Config; 6 | import io.helidon.webserver.Routing; 7 | import io.helidon.webserver.ServerRequest; 8 | import io.helidon.webserver.ServerResponse; 9 | import io.helidon.webserver.Service; 10 | 11 | import javax.json.Json; 12 | import javax.json.JsonObject; 13 | 14 | public class ParseClassService implements Service { 15 | 16 | /** 17 | * This gets config from application.yaml on classpath 18 | * and uses "app" section. 19 | */ 20 | private final Config CONFIG = Config.create().get("app"); 21 | private final String rootDir = CONFIG.get("root").asString("~/workspace"); 22 | private final ParseClassApp clzParser = new ParseClassApp(); 23 | private final JavaDaoParserFactory javaDaoParserFactory; 24 | 25 | public ParseClassService(JavaDaoParserFactory javaDaoParserFactory) { 26 | 27 | this.javaDaoParserFactory = javaDaoParserFactory; 28 | } 29 | 30 | @Override 31 | public void update(Routing.Rules rules) { 32 | rules 33 | .post("/{class}", this::parse); 34 | } 35 | 36 | /** 37 | * Return a wordly greeting message. 38 | * @param request the server request 39 | * @param response the server response 40 | */ 41 | private void parse(final ServerRequest request, 42 | final ServerResponse response) { 43 | String clz = request.path().param("class"); 44 | 45 | try { 46 | clzParser.parse(rootDir,clz, javaDaoParserFactory.createDaoParser()); 47 | JsonObject returnObject = Json.createObjectBuilder() 48 | .add("message", clz) 49 | .build(); 50 | response.send(returnObject); 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | JsonObject returnObject = Json.createObjectBuilder() 54 | .add("message", e.getMessage()) 55 | .build(); 56 | response.send(returnObject); 57 | } 58 | 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/ParsePackageService.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv; 2 | 3 | import evolution.analysis.jv.calls.JavaCallApp; 4 | import evolution.analysis.jv.calls.JavaDaoParser; 5 | import evolution.factory.daoparser.JavaDaoParserFactory; 6 | import evolution.analysis.jv.calls.plugins.JavaDaoStringParser; 7 | import evolution.analysis.jv.identifier.JavaClassQuery; 8 | import evolution.analysis.jv.identifier.JavaIdentifierApp; 9 | import evolution.store.Neo4JDriverFactory; 10 | import io.helidon.config.Config; 11 | import io.helidon.webserver.Routing; 12 | import io.helidon.webserver.ServerRequest; 13 | import io.helidon.webserver.ServerResponse; 14 | import io.helidon.webserver.Service; 15 | import org.neo4j.driver.v1.Driver; 16 | 17 | import javax.json.Json; 18 | import javax.json.JsonObject; 19 | import java.util.List; 20 | import java.util.logging.Logger; 21 | 22 | public class ParsePackageService implements Service { 23 | 24 | private static final Logger LOGGER = Logger.getLogger(ParsePackageService.class.getName()); 25 | /** 26 | * This gets config from application.yaml on classpath 27 | * and uses "app" section. 28 | */ 29 | private final Config CONFIG = Config.create().get("app"); 30 | private final String rootDir = CONFIG.get("root").asString("~/workspace"); 31 | private String neo4jServer = CONFIG.get("neo4j-server").asString("localhost"); 32 | private JavaDaoParser daoParser; 33 | 34 | public ParsePackageService(JavaDaoParserFactory javaDaoParserFactory) { 35 | daoParser = javaDaoParserFactory.createDaoParser(); 36 | } 37 | 38 | @Override 39 | public void update(Routing.Rules rules) { 40 | rules 41 | .post("/{package}", this::parse); 42 | } 43 | 44 | /** 45 | * Return a wordly greeting message. 46 | * @param request the server request 47 | * @param response the server response 48 | */ 49 | private void parse(final ServerRequest request, 50 | final ServerResponse response) { 51 | String pkg = request.path().param("package"); 52 | 53 | try { 54 | parse(pkg); 55 | JsonObject returnObject = Json.createObjectBuilder() 56 | .add("message", pkg) 57 | .build(); 58 | response.send(returnObject); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | JsonObject returnObject = Json.createObjectBuilder() 62 | .add("message", e.getMessage()) 63 | .build(); 64 | response.send(returnObject); 65 | } 66 | 67 | } 68 | 69 | private void parse(String pkg) throws Exception { 70 | Driver driver = Neo4JDriverFactory.create(neo4jServer); 71 | String dir = String.format("%s/cbs/src/main/java/%s",rootDir,pkg.replaceAll("\\.","/")); 72 | new JavaIdentifierApp(driver).analysisDir(dir); 73 | JavaClassQuery classQuery = new JavaClassQuery(driver); 74 | List clzs = classQuery.load(); 75 | JavaCallApp javaCallApp = new JavaCallApp(driver, daoParser); 76 | javaCallApp.analysisDir(dir,clzs); 77 | LOGGER.info("finished and close driver."); 78 | driver.close(); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/ProcessFiles.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.FileVisitResult; 5 | import java.nio.file.Path; 6 | import java.nio.file.SimpleFileVisitor; 7 | import java.nio.file.attribute.BasicFileAttributes; 8 | import java.util.List; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Future; 11 | import java.util.function.Consumer; 12 | 13 | import static java.nio.file.FileVisitResult.CONTINUE; 14 | 15 | public class ProcessFiles extends SimpleFileVisitor { 16 | 17 | private final Consumer process; 18 | private final ExecutorService pool; 19 | private final List futures; 20 | public ProcessFiles(Consumer process, ExecutorService pool,List futures) { 21 | this.pool = pool; 22 | this.process = process; 23 | this.futures = futures; 24 | } 25 | 26 | // Print information about 27 | // each type of file. 28 | @Override 29 | public FileVisitResult visitFile(Path file, 30 | BasicFileAttributes attr) { 31 | if (attr.isSymbolicLink()) { 32 | //System.out.format("Symbolic link: %s ", file); 33 | } else if (attr.isRegularFile()) { 34 | // System.out.format("Regular file: %s , name: %s ", file, file.getFileName()); 35 | // System.out.format("%s, %s",file.endsWith("java"),file.toString().endsWith(".java")); 36 | // System.out.println("(" + attr.size() + "bytes)"); 37 | } else { 38 | //System.out.format("Other: %s ", file); 39 | } 40 | 41 | if (attr.isRegularFile()) { 42 | //System.out.format("Regular file: %s ", file); 43 | //System.out.println("(" + attr.size() + "bytes)"); 44 | if (pool != null) { 45 | Future f = pool.submit(() -> process.accept(file)); 46 | futures.add(f); 47 | } else { 48 | process.accept(file); 49 | } 50 | } 51 | return CONTINUE; 52 | } 53 | 54 | // Print each directory visited. 55 | @Override 56 | public FileVisitResult postVisitDirectory(Path dir, 57 | IOException exc) { 58 | //System.out.format("Directory: %s%n", dir); 59 | return CONTINUE; 60 | } 61 | 62 | // If there is some error accessing 63 | // the file, let the user know. 64 | // If you don't override this method 65 | // and an error occurs, an IOException 66 | // is thrown. 67 | @Override 68 | public FileVisitResult visitFileFailed(Path file, 69 | IOException exc) { 70 | System.err.println(exc); 71 | return CONTINUE; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/calls/JavaCallApp.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls; 2 | 3 | import evolution.analysis.jv.JavaParserBaseVisitor; 4 | import evolution.analysis.jv.ProcessFiles; 5 | import evolution.analysis.jv.calls.model.JMethodCall; 6 | import evolution.analysis.jv.identifier.JavaFileParser; 7 | import org.antlr.v4.runtime.tree.ParseTree; 8 | import org.neo4j.driver.v1.Driver; 9 | 10 | import java.io.IOException; 11 | import java.nio.file.Files; 12 | import java.nio.file.Path; 13 | import java.nio.file.Paths; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.concurrent.ExecutionException; 17 | import java.util.concurrent.ExecutorService; 18 | import java.util.concurrent.Executors; 19 | import java.util.concurrent.Future; 20 | import java.util.concurrent.atomic.AtomicInteger; 21 | import java.util.function.Consumer; 22 | 23 | public class JavaCallApp { 24 | 25 | private final JavaMethodCallStore store; 26 | private AtomicInteger counter = new AtomicInteger(0); 27 | private JavaDaoParser daoParser; 28 | public JavaCallApp(Driver driver,JavaDaoParser daoParser) { 29 | this.store = new JavaMethodCallStore(driver); 30 | this.daoParser = daoParser; 31 | } 32 | 33 | public void analysisDir(String dir, List clzs) throws IOException, InterruptedException, ExecutionException { 34 | Path startingDir = Paths.get(dir); 35 | Consumer fileAnalysis = parse(clzs); 36 | int poolSize = 8; 37 | ExecutorService pool = Executors.newFixedThreadPool(poolSize); 38 | List futures = new ArrayList<>(); 39 | ProcessFiles pf = new ProcessFiles(fileAnalysis,pool,futures); 40 | Files.walkFileTree(startingDir, pf); 41 | for(Future f: futures) { 42 | f.get(); 43 | } 44 | pool.shutdown(); 45 | } 46 | 47 | private Consumer parse(List clzs) { 48 | return (Path path) -> { 49 | try { 50 | if (!path.toString().endsWith("Tests.java") 51 | && !path.toString().endsWith("Test.java") && path.toString().endsWith(".java")) { 52 | parse(path, clzs); 53 | } 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } 57 | }; 58 | } 59 | 60 | public void parse(Path path, List clzs) throws IOException { 61 | System.out.println("Start parse java call: " + path.getFileName()); 62 | ParseTree tree = JavaFileParser.parse(path); 63 | List calls = new ArrayList<>(); 64 | JavaParserBaseVisitor visitor = new JavaCallVisitor(calls,clzs, daoParser); 65 | visitor.visit(tree); 66 | long start = System.currentTimeMillis(); 67 | store.save(calls); 68 | long stop = System.currentTimeMillis(); 69 | int current = counter.incrementAndGet(); 70 | System.out.println(current + ": Save "+path.getFileName().toString()+", Spend Time: " + (stop - start) / 1000 + " s @" + Thread.currentThread().getName()); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/calls/JavaCallVisitor.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls; 2 | 3 | import evolution.analysis.jv.JavaParser; 4 | import evolution.analysis.jv.JavaParserBaseVisitor; 5 | import evolution.analysis.jv.calls.model.JMethodCall; 6 | import org.antlr.v4.runtime.tree.ParseTree; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.logging.Logger; 13 | 14 | public class JavaCallVisitor extends JavaParserBaseVisitor { 15 | 16 | private static final Logger LOGGER = Logger.getLogger(JavaCallVisitor.class.getName()); 17 | private Map fields = new HashMap<>(); 18 | private Map formalParameters = new HashMap<>(); 19 | private Map localVars = new HashMap<>(); 20 | private String currentClz = null; 21 | private String currentPkg = null; 22 | private List imports = new ArrayList<>(); 23 | private JavaDaoParser daoParser; 24 | 25 | private final List clzs; 26 | private JMethodCall currentMethodCall; 27 | 28 | private List methodCalls; 29 | 30 | public JavaCallVisitor(List methodCalls,List clzs,JavaDaoParser daoParser) { 31 | this.clzs = clzs; 32 | this.methodCalls = methodCalls; 33 | this.daoParser = daoParser; 34 | } 35 | 36 | @Override 37 | public Object visitPackageDeclaration(evolution.analysis.jv.JavaParser.PackageDeclarationContext ctx) { 38 | currentPkg = ctx.qualifiedName().getText(); 39 | return super.visitPackageDeclaration(ctx); 40 | } 41 | 42 | @Override 43 | public Object visitImportDeclaration(evolution.analysis.jv.JavaParser.ImportDeclarationContext ctx) { 44 | imports.add(ctx.qualifiedName().getText()); 45 | return super.visitImportDeclaration(ctx); 46 | } 47 | 48 | @Override 49 | public Object visitClassDeclaration(evolution.analysis.jv.JavaParser.ClassDeclarationContext ctx) { 50 | currentClz = ctx.IDENTIFIER().getText(); 51 | return super.visitClassDeclaration(ctx); 52 | } 53 | 54 | @Override 55 | public Object visitTypeDeclaration(evolution.analysis.jv.JavaParser.TypeDeclarationContext ctx) { 56 | //System.out.println(ctx.getText()); 57 | return super.visitTypeDeclaration(ctx); 58 | } 59 | 60 | @Override public Object visitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { 61 | currentClz = ctx.IDENTIFIER().getText(); 62 | return super.visitChildren(ctx); 63 | } 64 | 65 | @Override public Object visitInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) { 66 | currentMethodCall = new JMethodCall(); 67 | methodCalls.add(currentMethodCall); 68 | currentMethodCall.setPkg(currentPkg); 69 | currentMethodCall.setClz(currentClz); 70 | currentMethodCall.setMethodName(ctx.IDENTIFIER().getText()); 71 | daoParser.parse(currentMethodCall,ctx.IDENTIFIER().getText()); 72 | return super.visitChildren(ctx); 73 | } 74 | 75 | @Override 76 | public Object visitMethodDeclaration(evolution.analysis.jv.JavaParser.MethodDeclarationContext ctx) { 77 | //System.out.println("\nMethod: " + ctx.IDENTIFIER().getText()); 78 | currentMethodCall = new JMethodCall(); 79 | methodCalls.add(currentMethodCall); 80 | currentMethodCall.setPkg(currentPkg); 81 | currentMethodCall.setClz(currentClz); 82 | currentMethodCall.setMethodName(ctx.IDENTIFIER().getText()); 83 | 84 | String body = ctx.getText().toUpperCase(); 85 | daoParser.parse(currentMethodCall,body); 86 | 87 | return super.visitMethodDeclaration(ctx); 88 | } 89 | 90 | @Override 91 | public Object visitMethodCall(evolution.analysis.jv.JavaParser.MethodCallContext ctx) { 92 | 93 | if (currentMethodCall != null) { 94 | String targetType = parseTargetType(ctx); 95 | String callee = ctx.getChild(0).getText(); 96 | 97 | String warpTargetFullType = warpTargetFullType(targetType); 98 | if(warpTargetFullType != null) { 99 | currentMethodCall.addMethodCall(warpTargetFullType, callee); 100 | } else { 101 | //System.out.println("Can not wrap:\t" + targetType); 102 | } 103 | 104 | } 105 | return super.visitMethodCall(ctx); 106 | } 107 | 108 | private String warpTargetFullType(String targetType) { 109 | if (currentClz.equalsIgnoreCase(targetType)) { 110 | return currentPkg + "." + targetType; 111 | } 112 | for (String imp : imports) { 113 | if (imp.endsWith(targetType)) { 114 | return imp; 115 | } 116 | } 117 | //maybe the same package 118 | for(String c: clzs) { 119 | if(c.endsWith(targetType)) { 120 | return c; 121 | } 122 | } 123 | //1. current package, 2. import by * 124 | return null; 125 | } 126 | 127 | private String parseTargetType(JavaParser.MethodCallContext ctx) { 128 | ParseTree targetCtx = ctx.getParent().getChild(0); 129 | String targetVar = targetCtx.getText(); 130 | String targetType = targetVar; 131 | String parentCtxClz = targetCtx.getClass().getCanonicalName(); 132 | if ("me.analysis.jv.JavaParser.MethodCallContext".equals(parentCtxClz)) { 133 | targetType = currentClz; 134 | } else if ("this".equalsIgnoreCase(targetVar)) { 135 | targetType = currentClz; 136 | } else if (targetVar.matches(".*new.*\\)\\..*") && isNotSpecialNewWord(targetVar)) { 137 | try { 138 | targetType = parseNewType(targetCtx); 139 | //System.out.println("Matched: " + targetVar + " , " +targetType); 140 | } catch (NullPointerException e) { 141 | //not create object new method. but name include new word. 142 | LOGGER.info(ctx.getParent().getText()); 143 | //System.out.println(currentClz + " . " + currentMethodCall.getMethodName()); 144 | //System.out.println(targetCtx.getText()); 145 | LOGGER.info(e.getMessage()); 146 | } 147 | } else { 148 | String fieldType = fields.get(targetVar); 149 | String formalType = formalParameters.get(targetVar); 150 | String localVarType = localVars.get(targetVar); 151 | if (fieldType != null) { 152 | targetType = fieldType; 153 | } else if (formalType != null) { 154 | targetType = formalType; 155 | } else if (localVarType != null) { 156 | targetType = localVarType; 157 | } 158 | } 159 | return targetType; 160 | } 161 | 162 | private boolean isNotSpecialNewWord(String targetVar) { 163 | return !targetVar.contains("inspectionnew") && !targetVar.contains("renew") && !targetVar.contains("Renew") 164 | && !targetVar.contains("newcoverages") && !targetVar.contains("newCoverages"); 165 | } 166 | 167 | private String parseNewType(ParseTree ctx) { 168 | ParseTree creatorCxt = getJavaParserCreatorCxt(ctx); 169 | return creatorCxt.getChild(0).getText(); 170 | } 171 | 172 | private ParseTree getJavaParserCreatorCxt(ParseTree ctx) { 173 | if ("me.analysis.jv.JavaParser.CreatorContext".equals(ctx.getClass().getCanonicalName())) { 174 | return ctx; 175 | } else { 176 | ParseTree res = null; 177 | for (int i = 0; i < ctx.getChildCount(); i++) { 178 | ParseTree c = getJavaParserCreatorCxt(ctx.getChild(i)); 179 | if (c != null) { 180 | res = c; 181 | break; 182 | } 183 | } 184 | return res; 185 | } 186 | } 187 | 188 | @Override 189 | public Object visitFormalParameters(evolution.analysis.jv.JavaParser.FormalParametersContext ctx) { 190 | //System.out.println(ctx.getText()); 191 | return super.visitFormalParameters(ctx); 192 | } 193 | 194 | @Override 195 | public Object visitFormalParameter(evolution.analysis.jv.JavaParser.FormalParameterContext ctx) { 196 | //System.out.println(ctx.typeType().getText() + ":" + ctx.variableDeclaratorId().getText() + "@me.analysis.jv.JavaParser.FormalParameterContext"); 197 | formalParameters.put(ctx.variableDeclaratorId().getText(), ctx.typeType().getText()); 198 | return super.visitFormalParameter(ctx); 199 | } 200 | 201 | @Override 202 | public Object visitFieldDeclaration(evolution.analysis.jv.JavaParser.FieldDeclarationContext ctx) { 203 | JavaParser.VariableDeclaratorsContext variableDeclaratorsContext = ctx.variableDeclarators(); 204 | String variableName = variableDeclaratorsContext.getChild(0).getChild(0).getText(); 205 | //System.out.println(ctx.typeType().getText() + ":" + variableName); 206 | fields.put(variableName, ctx.typeType().getText()); 207 | return super.visitFieldDeclaration(ctx); 208 | } 209 | 210 | @Override 211 | public Object visitLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx) { 212 | String typ = ctx.getChild(0).getText(); 213 | String variableName = ctx.getChild(1).getChild(0).getChild(0).getText(); 214 | localVars.put(variableName, typ); 215 | return super.visitChildren(ctx); 216 | } 217 | 218 | @Override 219 | public Object visitVariableDeclarators(evolution.analysis.jv.JavaParser.VariableDeclaratorsContext ctx) { 220 | return super.visitVariableDeclarators(ctx); 221 | } 222 | 223 | @Override 224 | public Object visitArguments(evolution.analysis.jv.JavaParser.ArgumentsContext ctx) { 225 | //调其他方法的参数 226 | // System.out.println("===="); 227 | // System.out.println(ctx.getText()+"@me.analysis.jv.JavaParser.ArgumentsContext"); 228 | // System.out.println("===="); 229 | return super.visitArguments(ctx); 230 | } 231 | 232 | } 233 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/calls/JavaDaoParser.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls; 2 | 3 | import evolution.analysis.jv.calls.model.JMethodCall; 4 | 5 | public interface JavaDaoParser { 6 | void parse(JMethodCall currentMethodCall, String body); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/calls/JavaMethodCallStore.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls; 2 | 3 | import evolution.analysis.jv.calls.model.JMethodCall; 4 | import io.helidon.config.Config; 5 | import org.neo4j.driver.v1.*; 6 | 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.logging.Logger; 12 | 13 | import static org.neo4j.driver.v1.Values.parameters; 14 | 15 | public class JavaMethodCallStore { 16 | 17 | private static final Logger LOGGER = Logger.getLogger(JavaMethodCallStore.class.getName()); 18 | private final Config config = Config.create().get("app"); 19 | private final List includeKeyWorks = config.get("keywords").asList(String.class); 20 | private Driver driver; 21 | 22 | public JavaMethodCallStore(Driver driver) { 23 | this.driver = driver; 24 | } 25 | 26 | private boolean isIgnoreCallee(String callee) { 27 | //return callee.startsWith("get") || callee.startsWith("set"); 28 | return true; //ignore all java callee 29 | } 30 | 31 | private boolean isTargetClass(String clz) { 32 | boolean res = false; 33 | for (String keyword : includeKeyWorks) { 34 | res = res || clz.contains(keyword); 35 | } 36 | return res; 37 | } 38 | 39 | public void save(List methodCalls) { 40 | try (Session session = driver.session()) { 41 | session.writeTransaction(new TransactionWork() { 42 | @Override 43 | public Integer execute(Transaction tx) { 44 | for (JMethodCall ident : methodCalls) { 45 | String pkg = ident.getPkg(); 46 | String clz = ident.getClz(); 47 | String callerFullName = pkg + "." + clz + "." + ident.getMethodName(); 48 | saveCallJavaMethod(tx, ident, callerFullName); 49 | saveAccessTable(tx, ident, callerFullName); 50 | saveCallProcedure(tx, ident, callerFullName); 51 | 52 | } 53 | return methodCalls.size(); 54 | } 55 | }); 56 | } 57 | } 58 | 59 | private void saveCallProcedure(Transaction tx, JMethodCall ident, String callerFullName) { 60 | for (String pl : ident.getProcedures()) { 61 | tx.run("MATCH (caller:JMethod {fullname: $callerfullname}) " + 62 | "MATCH (callee:PLProcedure {fullname: $calleefullname}) " + 63 | "MERGE (caller)-[:Call {date:$date}]->(callee)", 64 | parameters("callerfullname", callerFullName, "date", getToday(), 65 | "calleefullname", pl)); 66 | } 67 | } 68 | 69 | private void saveAccessTable(Transaction tx, JMethodCall ident, String callerFullName) { 70 | for (Map.Entry s : ident.getTableOps().entrySet()) { 71 | String table = s.getKey().toString(); 72 | String op = s.getValue().toString(); 73 | LOGGER.info("save table: " + table); 74 | tx.run("MATCH (caller:JMethod {fullname: $callerfullname}) " + 75 | "MERGE (t:Table {name: $table}) " + 76 | "MERGE (caller)-[:__op__ {date:$date}]->(t)".replace("__op__", op), 77 | parameters("callerfullname", callerFullName, "date", getToday(), 78 | "table", table)); 79 | } 80 | } 81 | 82 | private void saveCallJavaMethod(Transaction tx, JMethodCall ident, String callerFullName) { 83 | for (String calleeClz : ident.getMethodCalls().keySet()) { 84 | if (isTargetClass(calleeClz)) { 85 | //System.out.println("try to save: " + calleeClz); 86 | for (String callee : ident.getMethodCalls().get(calleeClz)) { 87 | if (!isIgnoreCallee(callee)) { 88 | //System.out.println("\t" + callee); 89 | tx.run("MATCH (caller:JMethod {fullname: $callerfullname}) " + 90 | "MATCH (callee:JMethod {fullname: $calleefullname}) " + 91 | "MERGE (caller)-[:Call {date:$date}]->(callee)", 92 | parameters("callerfullname", callerFullName, "date", getToday(), 93 | "calleefullname", calleeClz + "." + callee)); 94 | } 95 | } 96 | } 97 | } 98 | } 99 | 100 | private String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); 101 | 102 | private String getToday() { 103 | return today; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/calls/model/JMethodCall.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls.model; 2 | 3 | import java.util.*; 4 | 5 | public class JMethodCall { 6 | private String pkg; 7 | private String clz; 8 | private String methodName; 9 | private Map> methodCalls = new HashMap<>(); 10 | private Map tableOps = new HashMap<>(); 11 | private Set procedures = new HashSet<>(); 12 | 13 | public String getPkg() { 14 | return pkg; 15 | } 16 | 17 | public void setPkg(String pkg) { 18 | this.pkg = pkg; 19 | } 20 | 21 | public String getClz() { 22 | return clz; 23 | } 24 | 25 | public void setClz(String clz) { 26 | this.clz = clz; 27 | } 28 | 29 | public String getMethodName() { 30 | return methodName; 31 | } 32 | 33 | public void setMethodName(String methodName) { 34 | this.methodName = methodName; 35 | } 36 | 37 | public Map> getMethodCalls() { 38 | return methodCalls; 39 | } 40 | 41 | public void addMethodCall(String targetType, String method) { 42 | //System.out.println(targetType+"->"+method); 43 | Set methods = methodCalls.get(targetType); 44 | if(methods == null) { 45 | methods = new HashSet<>(); 46 | methodCalls.put(targetType,methods); 47 | } 48 | methods.add(method); 49 | } 50 | 51 | public Set getProcedures() { 52 | return procedures; 53 | } 54 | 55 | public void addProcedures(List procedures) { 56 | for(String p:procedures) { 57 | this.procedures.add(p.toUpperCase()); 58 | } 59 | } 60 | 61 | public Map getTableOps() { 62 | return tableOps; 63 | } 64 | 65 | public void addTableOps(Map tableOps) { 66 | this.tableOps.putAll(tableOps); 67 | } 68 | 69 | public void addTableOp(String table,String op) { 70 | this.tableOps.put(table,op.toUpperCase()); 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | return "JMethodCall{" + 76 | "pkg='" + pkg + '\'' + 77 | ", clz='" + clz + '\'' + 78 | ", methodName='" + methodName + '\'' + 79 | ", methodCalls=" + methodCalls + 80 | ", tableOps=" + tableOps + 81 | '}'; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/calls/plugins/JavaDaoStringParser.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls.plugins; 2 | 3 | import evolution.analysis.jv.calls.JavaDaoParser; 4 | import evolution.analysis.jv.calls.model.JMethodCall; 5 | 6 | import java.util.*; 7 | import java.util.logging.Logger; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | public class JavaDaoStringParser implements JavaDaoParser { 12 | private static final Logger LOGGER = Logger.getLogger(JavaDaoStringParser.class.getName()); 13 | 14 | @Override 15 | public void parse(JMethodCall currentMethod, String body) { 16 | if (!isContainTable(body)) { 17 | return; 18 | } 19 | Map tableOpsMap = buildTableOps(body); 20 | currentMethod.addTableOps(tableOpsMap); 21 | LOGGER.info(currentMethod.getMethodName() + " use table size: " + currentMethod.getTableOps().size()); 22 | List procedures = parseProcedureCalls(body); 23 | currentMethod.addProcedures(procedures); 24 | 25 | } 26 | 27 | private boolean isContainTable(String body) { 28 | return body.contains("T_") || body.contains("CALL"); 29 | } 30 | 31 | 32 | protected List parseProcedureCalls(String body) { 33 | ArrayList res = new ArrayList<>(); 34 | String s = "(?:\\{.?(call|select|SELECT|CALL)\\s+)([a-zA-Z_\\d]+\\.[a-zA-Z_\\d]+)\\("; 35 | final Pattern p = Pattern.compile(s); 36 | final Matcher m = p.matcher(body); 37 | while (m.find()) { 38 | String pl = m.group(2); 39 | res.add(pl); 40 | } 41 | return res; 42 | } 43 | 44 | 45 | private Map buildTableOps(String body) { 46 | Map tableOpsMap = new HashMap<>(); 47 | List tableOps = parseTables(body); 48 | LOGGER.info("buildTableOps: " + tableOps.toString()); 49 | if (tableOps == null || tableOps.size() == 0) { 50 | return tableOpsMap; 51 | } 52 | 53 | String op = tableOps.get(0); 54 | if (!isTableOperator(op)) { 55 | LOGGER.warning(body); 56 | } 57 | LOGGER.info("tableOps.size: " + tableOps.size()); 58 | for (int i = 1; i < tableOps.size(); i++) { 59 | String s = tableOps.get(i); 60 | if (isTableOperator(s)) { 61 | op = s; 62 | } else { 63 | tableOpsMap.put(cleanTableName(s.toUpperCase()), op); 64 | } 65 | } 66 | 67 | return tableOpsMap; 68 | } 69 | 70 | 71 | public String cleanTableName(String table) { 72 | String pattern = "([A-Z_]+).*"; 73 | Pattern r = Pattern.compile(pattern); 74 | Matcher matcher = r.matcher(table); 75 | matcher.find(); 76 | return matcher.group(1); 77 | } 78 | 79 | 80 | private boolean isTableOperator(String s) { 81 | return "INSERT".equalsIgnoreCase(s) 82 | || "SELECT".equalsIgnoreCase(s) 83 | || "UPDATE".equalsIgnoreCase(s) 84 | || "DELETE".equalsIgnoreCase(s); 85 | } 86 | 87 | protected List parseTables(String body) { 88 | List result = new ArrayList<>(); 89 | String[] ts = body.split("[\\s{2,}|\"|,]"); 90 | Object[] ss = Arrays.stream(ts).filter(s -> !s.trim().isEmpty()).toArray(); 91 | 92 | for (int i = 0; i < ss.length - 1; i++) { 93 | String s = ss[i].toString(); 94 | if (s.startsWith("t_") || s.startsWith("T_") || s.startsWith("vdm_") || s.startsWith("VDM_")) { 95 | //select from, insert into,delete from,update 96 | String op = parseTableOperate(ss, i); 97 | if (op != null) { 98 | result.add(op); 99 | } 100 | result.add(s); 101 | } 102 | } 103 | return result; 104 | } 105 | 106 | private String parseTableOperate(Object[] ts, int index) { 107 | String pre = ts[index - 1].toString(); 108 | while (!("from".equalsIgnoreCase(pre.trim()) || isTableOperator(pre)) && index > 0) { 109 | index = index - 1; 110 | pre = ts[index - 1].toString(); 111 | } 112 | String op = null; 113 | if ("update".equalsIgnoreCase(pre)) { 114 | op = "UPDATE"; 115 | } else if ("into".equalsIgnoreCase(pre)) { 116 | op = "INSERT"; 117 | } else if ("from".equalsIgnoreCase(pre)) { 118 | String prePre = ts[index - 2].toString(); 119 | if ("delete".equalsIgnoreCase(prePre)) { 120 | op = "DELETE"; 121 | } else { 122 | op = "SELECT"; 123 | } 124 | } else if ("delete".equalsIgnoreCase(pre)) { 125 | op = "DELETE"; 126 | } 127 | return op; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/calls/plugins/MyBatisParser.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls.plugins; 2 | 3 | import evolution.analysis.jv.calls.JavaDaoParser; 4 | import evolution.analysis.jv.calls.model.JMethodCall; 5 | 6 | import evolution.analysis.jv.calls.plugins.sql.TableOpParser; 7 | import evolution.analysis.jv.calls.plugins.sql.TableVisitor; 8 | import org.antlr.v4.runtime.tree.ParseTree; 9 | import org.w3c.dom.*; 10 | import org.xml.sax.SAXException; 11 | 12 | import javax.xml.parsers.*; 13 | import java.io.*; 14 | 15 | import java.nio.file.Files; 16 | import java.nio.file.Paths; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.logging.Logger; 20 | 21 | public class MyBatisParser implements JavaDaoParser { 22 | 23 | private static final Logger LOGGER = Logger.getLogger(MyBatisParser.class.getName()); 24 | 25 | private String rootDir; 26 | public MyBatisParser(String rootDir) { 27 | this.rootDir = rootDir; 28 | } 29 | @Override 30 | public void parse(JMethodCall currentMethod, String body) { 31 | String pkg = currentMethod.getPkg(); 32 | String clz = currentMethod.getClz(); 33 | String clzFullName = pkg + "." + clz; 34 | String file = String.format("%s/src/main/resources/%s.xml",rootDir,clzFullName.replaceAll("\\.","/")); 35 | if(!(clzFullName.toLowerCase().contains("mapper") || clzFullName.toLowerCase().contains("dao")) 36 | || !Files.exists(Paths.get(file))){ 37 | return; 38 | } 39 | String sql = ""; 40 | try { 41 | sql = findMethodSql(file,currentMethod.getMethodName()); 42 | 43 | System.out.println(currentMethod.getMethodName()); 44 | //System.out.println(sql.trim()); 45 | Map tableOpsMap = parse(replaceVariable(sql.trim())); 46 | System.out.println(tableOpsMap); 47 | currentMethod.addTableOps(tableOpsMap); 48 | } catch (ParserConfigurationException e) { 49 | e.printStackTrace(); 50 | } catch (IOException e) { 51 | e.printStackTrace(); 52 | } catch (SAXException e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | private Map parse(String sql) throws IOException { 58 | Map tableOpsMap = new HashMap<>(); 59 | TableOpParser parser = new TableOpParser(); 60 | ParseTree tree = parser.parse(sql); 61 | tree.accept(new TableVisitor(tableOpsMap)); 62 | return tableOpsMap; 63 | } 64 | 65 | private String replaceVariable(String sql) { 66 | return sql.replaceAll("#\\{","").replaceAll("\\}",""); 67 | } 68 | 69 | private String findMethodSql(String path, String method) throws ParserConfigurationException, IOException, SAXException { 70 | File inputFile = new File(path); 71 | //parse mapper xml 72 | DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 73 | DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); 74 | Document doc = dBuilder.parse(inputFile); 75 | doc.getDocumentElement().normalize(); 76 | //find method 77 | 78 | NodeList nList = doc.getDocumentElement().getChildNodes(); 79 | for (int temp = 0; temp < nList.getLength(); temp++) { 80 | Node nNode = nList.item(temp); 81 | if(nNode.getAttributes() != null && nNode.getAttributes().getNamedItem("id") != null) { 82 | String id = nNode.getAttributes().getNamedItem("id").getNodeValue(); 83 | if (method.equalsIgnoreCase(id)) { 84 | //extract sql string 85 | String sql = nNode.getLastChild().getNodeValue(); 86 | return sql; 87 | } 88 | } 89 | } 90 | return ""; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/calls/plugins/sql/TableOpParser.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls.plugins.sql; 2 | 3 | import evolution.analysis.sql.SqlLexer; 4 | import evolution.analysis.sql.SqlParser; 5 | import org.antlr.v4.runtime.CharStream; 6 | import org.antlr.v4.runtime.CharStreams; 7 | import org.antlr.v4.runtime.CommonTokenStream; 8 | import org.antlr.v4.runtime.tree.ParseTree; 9 | 10 | import java.io.IOException; 11 | 12 | 13 | public class TableOpParser { 14 | 15 | public ParseTree parse(String sql) throws IOException { 16 | CharStream stream = CharStreams.fromString(sql); 17 | SqlLexer lexer = new SqlLexer(stream); 18 | CommonTokenStream tokens = new CommonTokenStream( lexer ); 19 | SqlParser parser = new SqlParser(tokens); 20 | return parser.parse(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/calls/plugins/sql/TableVisitor.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls.plugins.sql; 2 | 3 | 4 | import evolution.analysis.sql.SqlBaseVisitor; 5 | import evolution.analysis.sql.SqlParser; 6 | import org.antlr.v4.runtime.tree.ParseTree; 7 | 8 | import java.util.Map; 9 | 10 | public class TableVisitor extends SqlBaseVisitor { 11 | 12 | private Map tableOps; 13 | public TableVisitor(Map tableOps) { 14 | this.tableOps = tableOps; 15 | } 16 | 17 | 18 | @Override 19 | public Void visitSelect_stmt(SqlParser.Select_stmtContext ctx) { 20 | System.out.println("SELECT: " + ctx.getText()); 21 | return super.visitChildren(ctx); 22 | } 23 | 24 | @Override 25 | public Void visitSimple_select_stmt(SqlParser.Simple_select_stmtContext ctx) { 26 | System.out.printf("visitSimple_select SELECT: %s%n", ctx.getText()); 27 | return super.visitChildren(ctx); 28 | } 29 | 30 | @Override 31 | public Void visitSelect_or_values(SqlParser.Select_or_valuesContext ctx) { 32 | System.out.printf("visitSelect_or_values SELECT: %s%n", ctx.getText()); 33 | return super.visitChildren(ctx); 34 | } 35 | 36 | @Override 37 | public Void visitTable_or_subquery(SqlParser.Table_or_subqueryContext ctx) { 38 | ParseTree child = ctx.getChild(0); 39 | if(child instanceof evolution.analysis.sql.SqlParser.Table_nameContext) { 40 | tableOps.put(child.getText(),"SELECT"); 41 | } else { 42 | //System.out.printf("visitTable_or_subquery SELECT: %s @%s \n", ctx.getText(), child.getClass().getCanonicalName()); 43 | } 44 | return super.visitChildren(ctx); 45 | } 46 | 47 | @Override 48 | public Void visitSelect_core(SqlParser.Select_coreContext ctx) { 49 | //System.out.printf("visitSelect_core SELECT: %s%n", ctx.getText()); 50 | return super.visitChildren(ctx); 51 | } 52 | 53 | @Override 54 | public Void visitCompound_select_stmt(SqlParser.Compound_select_stmtContext ctx) { 55 | System.out.printf("visitCompound_select_stmt SELECT: %s%n", ctx.getText()); 56 | return super.visitChildren(ctx); 57 | } 58 | 59 | @Override 60 | public Void visitFactored_select_stmt(SqlParser.Factored_select_stmtContext ctx) { 61 | //System.out.printf("visitFactored_select_stmt SELECT: %s%n", ctx.getText()); 62 | return super.visitChildren(ctx); 63 | } 64 | 65 | @Override 66 | public Void visitUpdate_stmt(SqlParser.Update_stmtContext ctx) { 67 | //System.out.println("UPDATE: " + ctx.getText()); 68 | tableOps.put(ctx.getChild(1).getText(),"UPDATE"); 69 | return super.visitChildren(ctx); 70 | } 71 | 72 | @Override 73 | public Void visitDelete_stmt(SqlParser.Delete_stmtContext ctx) { 74 | System.out.println("DELETE: " + ctx.getText()); 75 | tableOps.put(ctx.getChild(2).getText(),"DELETE"); 76 | return super.visitChildren(ctx); 77 | } 78 | 79 | @Override 80 | public Void visitInsert_stmt(SqlParser.Insert_stmtContext ctx) { 81 | //System.out.println("INSERT: " + ctx.getText()); 82 | tableOps.put(ctx.getChild(2).getText(),"INSERT"); 83 | return super.visitChildren(ctx); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/identifier/JIdentifier.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.identifier; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class JIdentifier { 7 | 8 | private String pkg; 9 | private String name; 10 | private String typ; 11 | 12 | private List methods = new ArrayList<>(); 13 | 14 | public String getPkg() { 15 | return pkg; 16 | } 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | 23 | public List getMethods() { 24 | return methods; 25 | } 26 | 27 | public void setPkg(String pkg) { 28 | this.pkg = pkg; 29 | } 30 | 31 | public void setName(String interfaceName) { 32 | this.name = interfaceName; 33 | } 34 | 35 | public void addMethod(JMethod method) { 36 | this.methods.add(method); 37 | } 38 | 39 | public String getType() { 40 | return typ; 41 | } 42 | 43 | public void setType(String typ) { 44 | this.typ = typ; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "JIdentifier{" + 50 | "pkg='" + pkg + '\'' + 51 | ", name='" + name + '\'' + 52 | ", methods=" + methods + 53 | '}'; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/identifier/JMethod.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.identifier; 2 | 3 | public class JMethod { 4 | 5 | private String name; 6 | private int startLine; 7 | private int startLinePosition; 8 | private int stopLine; 9 | private int stopLinePosition; 10 | 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | public void setName(String name) { 16 | this.name = name; 17 | } 18 | 19 | public int getStartLine() { 20 | return startLine; 21 | } 22 | 23 | public void setStartLine(int startLine) { 24 | this.startLine = startLine; 25 | } 26 | 27 | public int getStartLinePosition() { 28 | return startLinePosition; 29 | } 30 | 31 | public void setStartLinePosition(int startLinePosition) { 32 | this.startLinePosition = startLinePosition; 33 | } 34 | 35 | public int getStopLine() { 36 | return stopLine; 37 | } 38 | 39 | public void setStopLine(int stopLine) { 40 | this.stopLine = stopLine; 41 | } 42 | 43 | public int getStopLinePosition() { 44 | return stopLinePosition; 45 | } 46 | 47 | public void setStopLinePosition(int stopLinePosition) { 48 | this.stopLinePosition = stopLinePosition; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/identifier/JavaClassQuery.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.identifier; 2 | 3 | import org.neo4j.driver.v1.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class JavaClassQuery { 9 | 10 | private Driver driver; 11 | 12 | public JavaClassQuery(Driver driver) { 13 | this.driver = driver; 14 | } 15 | 16 | public List load() { 17 | try(Session session = driver.session()) { 18 | return session.readTransaction(new TransactionWork>() { 19 | @Override 20 | public List execute(Transaction tx) { 21 | StatementResult res = tx.run("MATCH (c:Class) RETURN c"); 22 | List clzs = new ArrayList<>(); 23 | while(res.hasNext()) { 24 | Value c1 = res.next().get("c"); 25 | String c = c1.get("fullname").asString(); 26 | clzs.add(c); 27 | } 28 | return clzs; 29 | } 30 | }); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/identifier/JavaFileParser.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.identifier; 2 | 3 | import evolution.analysis.jv.JavaLexer; 4 | import evolution.analysis.jv.JavaParser; 5 | import org.antlr.v4.runtime.CharStream; 6 | import org.antlr.v4.runtime.CharStreams; 7 | import org.antlr.v4.runtime.CommonTokenStream; 8 | import org.antlr.v4.runtime.tree.ParseTree; 9 | 10 | import java.io.IOException; 11 | import java.nio.file.Path; 12 | 13 | public class JavaFileParser { 14 | 15 | public static ParseTree parse(Path path) throws IOException { 16 | CharStream stream = CharStreams.fromPath(path); 17 | JavaLexer lexer = new JavaLexer(stream); 18 | CommonTokenStream tokens = new CommonTokenStream( lexer ); 19 | JavaParser parser = new JavaParser(tokens); 20 | 21 | return parser.compilationUnit(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/identifier/JavaIdentifierApp.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.identifier; 2 | 3 | 4 | import evolution.analysis.jv.JavaParserBaseVisitor; 5 | import evolution.analysis.jv.ProcessFiles; 6 | import org.antlr.v4.runtime.tree.ParseTree; 7 | import org.neo4j.driver.v1.Driver; 8 | 9 | import java.io.IOException; 10 | import java.nio.file.Files; 11 | import java.nio.file.Path; 12 | import java.nio.file.Paths; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.concurrent.ExecutionException; 16 | import java.util.concurrent.ExecutorService; 17 | import java.util.concurrent.Executors; 18 | import java.util.concurrent.Future; 19 | 20 | public class JavaIdentifierApp { 21 | 22 | private final JavaIdentifierStore identStore; 23 | public JavaIdentifierApp(Driver driver) { 24 | this.identStore = new JavaIdentifierStore(driver); 25 | } 26 | 27 | public void analysisDir(String dir) throws IOException, InterruptedException, ExecutionException { 28 | Path startingDir = Paths.get(dir); 29 | int poolSize = 8; 30 | ExecutorService pool = Executors.newFixedThreadPool(poolSize); 31 | List futures = new ArrayList<>(); 32 | ProcessFiles pf = new ProcessFiles(this::parse, pool,futures); 33 | Files.walkFileTree(startingDir, pf); 34 | for(Future f: futures) { 35 | f.get(); 36 | } 37 | pool.shutdown(); 38 | } 39 | 40 | public void parse(Path path) { 41 | try { 42 | 43 | if (!path.toString().endsWith("Tests.java") 44 | && !path.toString().endsWith("Test.java") && path.toString().endsWith(".java")) { 45 | ParseTree tree = JavaFileParser.parse(path); 46 | JIdentifier interfaceIdent = new JIdentifier(); 47 | JavaParserBaseVisitor interfaceVisitor = new JavaIdentifierVisitor(interfaceIdent); 48 | interfaceVisitor.visit(tree); 49 | if (interfaceIdent.getName() != null && interfaceIdent.getName() != "") { 50 | identStore.save(interfaceIdent); 51 | } 52 | } 53 | } catch (IOException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/identifier/JavaIdentifierStore.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.identifier; 2 | 3 | import org.neo4j.driver.v1.Driver; 4 | import org.neo4j.driver.v1.Session; 5 | import org.neo4j.driver.v1.Transaction; 6 | import org.neo4j.driver.v1.TransactionWork; 7 | 8 | import java.text.SimpleDateFormat; 9 | import java.util.Date; 10 | import java.util.logging.Logger; 11 | 12 | import static org.neo4j.driver.v1.Values.parameters; 13 | 14 | public class JavaIdentifierStore { 15 | private static final Logger LOGGER = Logger.getLogger(JavaIdentifierStore.class.getName()); 16 | private Driver driver; 17 | 18 | public JavaIdentifierStore(Driver driver) { 19 | this.driver = driver; 20 | } 21 | 22 | public void save(JIdentifier ident) { 23 | System.out.println(ident); 24 | try(Session session = driver.session()) { 25 | session.writeTransaction(new TransactionWork() { 26 | @Override 27 | public Integer execute(Transaction tx) { 28 | String pkg = ident.getPkg(); 29 | String clz = ident.getName(); 30 | tx.run("MERGE (p:Package {name: $pkg}) " + 31 | "MERGE (c:__typ__ {name: $clz, fullname: $clzFullname}) ".replace("__typ__",ident.getType()) + 32 | "MERGE (p)-[:Has]->(c)", 33 | parameters("pkg", ident.getPkg(), 34 | "clz", clz, "clzFullname", pkg + "." + clz)); 35 | LOGGER.info(clz); 36 | for (JMethod m : ident.getMethods()) { 37 | String mFullName = pkg + "." + clz + "." + m.getName(); 38 | LOGGER.info("\t"+m.getName()); 39 | tx.run("MATCH (c {fullname: $clzFullname}) \n" + 40 | "MERGE (m:JMethod {name: $name, fullname: $fullname,date:$date," + 41 | "startline: $startline, startlinePos: $startlinePos," + 42 | "stopline: $stopline, stoplinePos: $stoplinePos}) " + 43 | "MERGE (c)-[:Has]->(m)", 44 | parameters("clzFullname", pkg + "." + clz, 45 | "name", m.getName(), "fullname", mFullName,"date",getToday(), 46 | "startline",m.getStartLine(),"startlinePos",m.getStartLinePosition(), 47 | "stopline",m.getStopLine(),"stoplinePos",m.getStopLinePosition())); 48 | } 49 | return ident.getMethods().size(); 50 | } 51 | }); 52 | } 53 | } 54 | private String getToday() { 55 | return new SimpleDateFormat("yyyy-MM-dd").format(new Date()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/evolution/analysis/jv/identifier/JavaIdentifierVisitor.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.identifier; 2 | 3 | import evolution.analysis.jv.JavaParser; 4 | import evolution.analysis.jv.JavaParserBaseVisitor; 5 | 6 | public class JavaIdentifierVisitor extends JavaParserBaseVisitor { 7 | 8 | private JIdentifier node; 9 | public JavaIdentifierVisitor(JIdentifier node){ 10 | this.node = node; 11 | } 12 | 13 | @Override 14 | public Object visitPackageDeclaration(evolution.analysis.jv.JavaParser.PackageDeclarationContext ctx) { 15 | node.setPkg(ctx.qualifiedName().getText()); 16 | return super.visitPackageDeclaration(ctx); 17 | } 18 | 19 | 20 | @Override 21 | public Object visitClassDeclaration(evolution.analysis.jv.JavaParser.ClassDeclarationContext ctx) { 22 | node.setType("Class"); 23 | node.setName(ctx.IDENTIFIER().getText()); 24 | //XXX: implement interface 25 | return super.visitClassDeclaration(ctx); 26 | } 27 | 28 | @Override 29 | public Object visitMethodDeclaration(evolution.analysis.jv.JavaParser.MethodDeclarationContext ctx) { 30 | JMethod method = new JMethod(); 31 | //XXX: find the start position of {, not public 32 | method.setStartLine(ctx.start.getLine()); 33 | method.setStartLinePosition(ctx.start.getCharPositionInLine()); 34 | method.setStopLine(ctx.stop.getLine()); 35 | method.setStopLinePosition(ctx.stop.getCharPositionInLine()); 36 | method.setName(ctx.IDENTIFIER().getText()); 37 | node.addMethod(method); 38 | return super.visitMethodDeclaration(ctx); 39 | } 40 | 41 | @Override 42 | public Object visitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { 43 | node.setType("Interface"); 44 | node.setName(ctx.IDENTIFIER().getText()); 45 | return super.visitInterfaceDeclaration(ctx); 46 | } 47 | 48 | @Override 49 | public Object visitInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) { 50 | JMethod method = new JMethod(); 51 | //XXX: find the start position of {, not public 52 | method.setStartLine(ctx.start.getLine()); 53 | method.setStartLinePosition(ctx.start.getCharPositionInLine()); 54 | method.setStopLine(ctx.stop.getLine()); 55 | method.setStopLinePosition(ctx.stop.getCharPositionInLine()); 56 | method.setName(ctx.IDENTIFIER().getText()); 57 | node.addMethod(method); 58 | return super.visitInterfaceMethodDeclaration(ctx); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/evolution/configuration/ConfigReader.java: -------------------------------------------------------------------------------- 1 | package evolution.configuration; 2 | 3 | import evolution.factory.daoparser.DaoParserTypeEnum; 4 | import evolution.factory.daoparser.DaoParserProvider; 5 | import io.helidon.config.Config; 6 | 7 | public class ConfigReader implements DaoParserProvider { 8 | private final Config CONFIG = Config.create().get("app"); 9 | @Override 10 | public DaoParserTypeEnum getDaoParserType() { 11 | String daoParseType = CONFIG.get("dao-parse-type").asString(); 12 | return DaoParserTypeEnum.valueOf(daoParseType); 13 | } 14 | 15 | 16 | @Override 17 | public String getDaoParseRootPath() { 18 | return CONFIG.get("root").asString("~/workspace"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/evolution/factory/ServiceFactory.java: -------------------------------------------------------------------------------- 1 | package evolution.factory; 2 | 3 | import evolution.analysis.jv.ParseClassService; 4 | import evolution.analysis.jv.ParsePackageService; 5 | import evolution.factory.daoparser.DaoParserProvider; 6 | import evolution.factory.daoparser.JavaDaoParserFactory; 7 | 8 | public class ServiceFactory { 9 | private JavaDaoParserFactory javaDaoParserFactory; 10 | 11 | public ServiceFactory(DaoParserProvider provider) { 12 | javaDaoParserFactory = new JavaDaoParserFactory(provider); 13 | } 14 | 15 | public ParsePackageService createParsePackageService() { 16 | return new ParsePackageService(javaDaoParserFactory); 17 | } 18 | 19 | public ParseClassService createParseClassService() { 20 | return new ParseClassService(javaDaoParserFactory); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/evolution/factory/daoparser/DaoParserProvider.java: -------------------------------------------------------------------------------- 1 | package evolution.factory.daoparser; 2 | 3 | import evolution.factory.daoparser.DaoParserTypeEnum; 4 | 5 | public interface DaoParserProvider { 6 | DaoParserTypeEnum getDaoParserType(); 7 | 8 | String getDaoParseRootPath(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/evolution/factory/daoparser/DaoParserTypeEnum.java: -------------------------------------------------------------------------------- 1 | package evolution.factory.daoparser; 2 | 3 | public enum DaoParserTypeEnum { 4 | MyBatisParser, 5 | StringParser 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/evolution/factory/daoparser/JavaDaoParserFactory.java: -------------------------------------------------------------------------------- 1 | package evolution.factory.daoparser; 2 | 3 | import evolution.analysis.jv.calls.JavaDaoParser; 4 | import evolution.analysis.jv.calls.plugins.JavaDaoStringParser; 5 | import evolution.analysis.jv.calls.plugins.MyBatisParser; 6 | 7 | public class JavaDaoParserFactory { 8 | 9 | private final DaoParserProvider provider; 10 | 11 | public JavaDaoParserFactory(DaoParserProvider provider) { 12 | this.provider = provider; 13 | } 14 | 15 | public JavaDaoParser createDaoParser() { 16 | DaoParserTypeEnum daoParserType = this.provider.getDaoParserType(); 17 | if(daoParserType == DaoParserTypeEnum.StringParser) { 18 | return new JavaDaoStringParser(); 19 | } 20 | if(daoParserType == DaoParserTypeEnum.MyBatisParser) { 21 | return new MyBatisParser(this.provider.getDaoParseRootPath()); 22 | } 23 | throw new OutOfJavaDaoParserEnumError(daoParserType); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/evolution/factory/daoparser/OutOfJavaDaoParserEnumError.java: -------------------------------------------------------------------------------- 1 | package evolution.factory.daoparser; 2 | 3 | class OutOfJavaDaoParserEnumError extends Error { 4 | OutOfJavaDaoParserEnumError(DaoParserTypeEnum daoParserType) { 5 | super(String.format("the type %s is out of range", daoParserType.toString())); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/evolution/store/HelloWorldExample.java: -------------------------------------------------------------------------------- 1 | package evolution.store; 2 | 3 | import org.neo4j.driver.v1.*; 4 | 5 | import static org.neo4j.driver.v1.Values.parameters; 6 | 7 | public class HelloWorldExample implements AutoCloseable { 8 | private final Driver driver; 9 | 10 | public HelloWorldExample(String uri, String user, String password) { 11 | driver = GraphDatabase.driver(uri, AuthTokens.basic(user, password)); 12 | } 13 | 14 | @Override 15 | public void close() throws Exception { 16 | driver.close(); 17 | } 18 | 19 | public void printGreeting(final String message) { 20 | try (Session session = driver.session()) { 21 | System.out.println(isActorExist(session,"Tom Hanks")); 22 | 23 | String greeting = session.writeTransaction(new TransactionWork() { 24 | @Override 25 | public String execute(Transaction tx) { 26 | StatementResult result = tx.run("CREATE (a:Greeting) " + 27 | "SET a.message = $message " + 28 | "RETURN a.message + ', from node ' + id(a)", 29 | parameters("message", message)); 30 | 31 | return result.single().get(0).asString(); 32 | } 33 | }); 34 | System.out.println(greeting); 35 | } 36 | } 37 | 38 | public boolean isActorExist(Session session, String name) { 39 | return session.readTransaction(new TransactionWork() { 40 | @Override 41 | public Boolean execute(Transaction tx) { 42 | StatementResult result = tx.run("MATCH (a {name: $name}) RETURN a", parameters("name",name)); 43 | //Node node = result.single().get(0).asNode(); 44 | //System.out.println(node.asMap()); 45 | return result.hasNext(); 46 | } 47 | }); 48 | } 49 | 50 | public static void main(String... args) throws Exception { 51 | try (HelloWorldExample greeter = new HelloWorldExample("bolt://localhost:7687", "xuefeng", "xuefeng")) { 52 | greeter.printGreeting("hello, world"); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/evolution/store/Neo4JDriverFactory.java: -------------------------------------------------------------------------------- 1 | package evolution.store; 2 | 3 | import org.neo4j.driver.v1.AuthTokens; 4 | import org.neo4j.driver.v1.Driver; 5 | import org.neo4j.driver.v1.GraphDatabase; 6 | 7 | public class Neo4JDriverFactory { 8 | 9 | public static Driver create(String neo4jServer){ 10 | String uri = String.format("bolt://%s:7687",neo4jServer); 11 | String user = "neo4j"; 12 | String password = "admin"; 13 | 14 | return GraphDatabase.driver(uri, AuthTokens.basic(user, password)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/evolution/store/StoreManager.java: -------------------------------------------------------------------------------- 1 | package evolution.store; 2 | 3 | import org.neo4j.driver.v1.Driver; 4 | import org.neo4j.driver.v1.Session; 5 | import org.neo4j.driver.v1.Transaction; 6 | import org.neo4j.driver.v1.TransactionWork; 7 | 8 | public class StoreManager { 9 | private final Driver driver; 10 | 11 | public StoreManager(Driver driver) { 12 | this.driver = driver; 13 | } 14 | 15 | public void update(String state) { 16 | try (Session session = driver.session()) { 17 | session.writeTransaction(new TransactionWork() { 18 | @Override 19 | public Integer execute(Transaction tx) { 20 | tx.run(state); 21 | return 0; 22 | } 23 | }); 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | app: 18 | greeting: "Hello" 19 | root: "/workspace" 20 | keywords: 21 | - com 22 | neo4j-server: "neo4j" 23 | dao-parse-type: "MyBatisParser" 24 | 25 | server: 26 | port: 8080 27 | host: 0.0.0.0 28 | -------------------------------------------------------------------------------- /src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Example Logging Configuration File 18 | # For more information see $JAVA_HOME/jre/lib/logging.properties 19 | 20 | # Send messages to the console 21 | handlers=java.util.logging.ConsoleHandler 22 | 23 | # Global default logging level. Can be overriden by specific handlers and loggers 24 | .level=INFO 25 | 26 | # Helidon Web Server has a custom log formatter that extends SimpleFormatter. 27 | # It replaces "!thread!" with the current thread name 28 | java.util.logging.ConsoleHandler.level=INFO 29 | java.util.logging.ConsoleHandler.formatter=io.helidon.webserver.netty.WebServerLogFormatter 30 | java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n 31 | 32 | #Component specific log levels 33 | #io.helidon.webserver.level=INFO 34 | #io.helidon.config.level=INFO 35 | #io.helidon.security.level=INFO 36 | #io.helidon.common.level=INFO 37 | #io.netty.level=INFO 38 | -------------------------------------------------------------------------------- /src/test/java/evolution/ConfigReaderTest.java: -------------------------------------------------------------------------------- 1 | package evolution; 2 | 3 | import evolution.configuration.ConfigReader; 4 | import evolution.factory.daoparser.DaoParserTypeEnum; 5 | import evolution.factory.daoparser.DaoParserProvider; 6 | import org.junit.jupiter.api.Test; 7 | 8 | class ConfigReaderTest { 9 | 10 | @Test 11 | void should_get_correct_dao_parse_type_as_config_setting() { 12 | DaoParserProvider reader = new ConfigReader(); 13 | DaoParserTypeEnum daoParserType = reader.getDaoParserType(); 14 | assert(daoParserType).equals(DaoParserTypeEnum.MyBatisParser); 15 | } 16 | } -------------------------------------------------------------------------------- /src/test/java/evolution/MainTest.java: -------------------------------------------------------------------------------- 1 | package evolution; 2 | 3 | 4 | import io.helidon.webserver.WebServer; 5 | import org.junit.jupiter.api.AfterAll; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.BeforeAll; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import javax.json.Json; 11 | import javax.json.JsonObject; 12 | import javax.json.JsonReader; 13 | import java.net.HttpURLConnection; 14 | import java.net.URL; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | public class MainTest { 18 | 19 | private static WebServer webServer; 20 | 21 | @BeforeAll 22 | public static void startTheServer() throws Exception { 23 | webServer = Main.startServer(); 24 | while (! webServer.isRunning()) { 25 | Thread.sleep(1 * 1000); 26 | } 27 | } 28 | 29 | @AfterAll 30 | public static void stopServer() throws Exception { 31 | if (webServer != null) { 32 | webServer.shutdown() 33 | .toCompletableFuture() 34 | .get(10, TimeUnit.SECONDS); 35 | } 36 | } 37 | 38 | @Test 39 | public void testHelloWorld() throws Exception { 40 | HttpURLConnection conn; 41 | 42 | conn = getURLConnection("GET", "/greet/Joe"); 43 | Assertions.assertEquals(200, conn.getResponseCode(), "HTTP response2"); 44 | JsonReader jsonReader = Json.createReader(conn.getInputStream()); 45 | JsonObject jsonObject = jsonReader.readObject(); 46 | Assertions.assertEquals("Hello Joe!", jsonObject.getString("message"), 47 | "hello Joe message"); 48 | 49 | conn = getURLConnection("PUT", "/greet/greeting/Hola"); 50 | Assertions.assertEquals(200, conn.getResponseCode(), "HTTP response3"); 51 | conn = getURLConnection("GET", "/greet/Jose"); 52 | Assertions.assertEquals(200, conn.getResponseCode(), "HTTP response4"); 53 | jsonReader = Json.createReader(conn.getInputStream()); 54 | jsonObject = jsonReader.readObject(); 55 | Assertions.assertEquals("Hola Jose!", jsonObject.getString("message"), 56 | "hola Jose message"); 57 | } 58 | 59 | private HttpURLConnection getURLConnection(String method, String path) throws Exception { 60 | URL url = new URL("http://localhost:" + webServer.port() + path); 61 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 62 | conn.setRequestMethod(method); 63 | conn.setRequestProperty("Accept", "application/json"); 64 | return conn; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/evolution/analysis/jv/calls/plugins/JavaCallVisitorTest.java: -------------------------------------------------------------------------------- 1 | package evolution.analysis.jv.calls.plugins; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.List; 7 | import java.util.stream.Stream; 8 | 9 | public class JavaCallVisitorTest { 10 | 11 | private JavaDaoStringParser visitor = new JavaDaoStringParser(); 12 | @Test 13 | public void testParseProcedureCalls() { 14 | String body = "Stringsql=\"{call PKG_LS_CLM_CALC.P_GET_ANXIN_PRO_AMOUNT(?,?,?)} \";"; 15 | List res = visitor.parseProcedureCalls(body); 16 | Assertions.assertEquals(1,res.size()); 17 | Assertions.assertEquals("PKG_LS_CLM_CALC.P_GET_ANXIN_PRO_AMOUNT",res.get(0)); 18 | 19 | String body2 = "Stringsql=\" \"; " + 20 | "Stringsql=\"{call PKG_LS_CLM_CALC.P_GET_ANXIN_PRO_AMOUNT2(?,?,?)} \";"; 21 | List res2 = visitor.parseProcedureCalls(body2); 22 | Assertions.assertEquals(1,res2.size()); 23 | Assertions.assertEquals("PKG_LS_CLM_CALC.P_GET_ANXIN_PRO_AMOUNT2",res2.get(0)); 24 | 25 | String body3 = "Stringsql=\"{call PKG_LS_CLM_CALC.P_GET_ANXIN_PRO_AMOUNT(?,?,?)} \";" + 26 | "Stringsql=\"{call PKG_LS_CLM_CALC.P_GET_ANXIN_PRO_AMOUNT2(?,?,?)} \";"; 27 | List res3 = visitor.parseProcedureCalls(body3); 28 | Assertions.assertEquals(2,res3.size()); 29 | Assertions.assertEquals("PKG_LS_CLM_CALC.P_GET_ANXIN_PRO_AMOUNT",res3.get(0)); 30 | Assertions.assertEquals("PKG_LS_CLM_CALC.P_GET_ANXIN_PRO_AMOUNT2",res3.get(1)); 31 | } 32 | 33 | @Test 34 | public void testParseTables() { 35 | String body = "newStringBuffer(\"select distinct tclp.item_id,\").append(\" tpl.liab_id,\").append(\" tprl.product_abbr,\").append(\" tprl.product_name,\").append(\" tliab.liab_name\").append(\" from t_Liab_Pay_Relative tpl,\").append(\" t_claim_product tclp,\").append(\" t_product_life tprl,\").append(\" t_liability tliab,\").append(\" t_contract_master tcm\").append(\" where tclp.policy_id = ? and tclp.product_id = tpl.product_id and\").append(\" tliab.liab_id = tpl.liab_id and\").append(\" tclp.product_id = tprl.product_id and tclp.case_id = ? and\").append(\" tcm.policy_id = tclp.policy_id \")"; 36 | List res = visitor.parseTables(body); 37 | Stream.of(res).forEach(System.out::println); 38 | Assertions.assertEquals(10,res.size()); 39 | Assertions.assertEquals("SELECT",res.get(0)); 40 | } 41 | 42 | 43 | @Test 44 | public void cleanTableName() { 45 | Assertions.assertEquals("T_HEALTH_PRODUCT_SPECIAL", visitor.cleanTableName("T_HEALTH_PRODUCT_SPECIAL)\\N")); 46 | Assertions.assertEquals("T_HEALTH_PRODUCT_SPECIAL", visitor.cleanTableName("T_HEALTH_PRODUCT_SPECIAL)")); 47 | Assertions.assertEquals("T_HEALTH_PRODUCT_SPECIAL", visitor.cleanTableName("T_HEALTH_PRODUCT_SPECIAL")); 48 | Assertions.assertEquals("T_CONTRACT_MASTER_LIAB_HI", visitor.cleanTableName("T_CONTRACT_MASTER_LIAB_HI")); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/evolution/factory/daoparser/FakeConfigReader.java: -------------------------------------------------------------------------------- 1 | package evolution.factory.daoparser; 2 | 3 | public class FakeConfigReader implements DaoParserProvider { 4 | private final DaoParserTypeEnum daoParserTypeEnum; 5 | private final String parsRootPath; 6 | 7 | public FakeConfigReader(DaoParserTypeEnum daoParserTypeEnum, String parsRootPath) { 8 | this.daoParserTypeEnum = daoParserTypeEnum; 9 | this.parsRootPath = parsRootPath; 10 | } 11 | 12 | @Override 13 | public DaoParserTypeEnum getDaoParserType() { 14 | return this.daoParserTypeEnum; 15 | } 16 | 17 | @Override 18 | public String getDaoParseRootPath() { 19 | return this.parsRootPath; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/evolution/factory/daoparser/JavaDaoParserFactoryTest.java: -------------------------------------------------------------------------------- 1 | package evolution.factory.daoparser; 2 | 3 | import evolution.analysis.jv.calls.JavaDaoParser; 4 | import evolution.analysis.jv.calls.plugins.JavaDaoStringParser; 5 | import evolution.analysis.jv.calls.plugins.MyBatisParser; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.instanceOf; 10 | 11 | class JavaDaoParserFactoryTest { 12 | 13 | @Test 14 | void should_create_myBatis_parser_when_type_is_mybatis() { 15 | DaoParserProvider provider = new FakeConfigReader(DaoParserTypeEnum.MyBatisParser, ""); 16 | JavaDaoParserFactory factory = new JavaDaoParserFactory(provider); 17 | JavaDaoParser daoParser = factory.createDaoParser(); 18 | 19 | assertThat(daoParser, instanceOf(MyBatisParser.class)); 20 | } 21 | 22 | @Test 23 | void should_create_java_string_dao_parser_when_type_is_stringParser() { 24 | DaoParserProvider provider = new FakeConfigReader(DaoParserTypeEnum.StringParser, ""); 25 | JavaDaoParserFactory factory = new JavaDaoParserFactory(provider); 26 | JavaDaoParser daoParser = factory.createDaoParser(); 27 | 28 | assertThat(daoParser, instanceOf(JavaDaoStringParser.class)); 29 | } 30 | 31 | } --------------------------------------------------------------------------------