├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── jpaquery │ ├── builder │ ├── JPQL.java │ └── package-info.java │ ├── core │ ├── QueryHandler.java │ ├── Querys.java │ ├── SubQueryHandler.java │ ├── constant │ │ ├── LikeWay.java │ │ └── package-info.java │ ├── facade │ │ ├── And.java │ │ ├── BetweenPath.java │ │ ├── FunctionPath.java │ │ ├── Group.java │ │ ├── GroupPath.java │ │ ├── Having.java │ │ ├── HavingFunctionPath.java │ │ ├── HavingPath.java │ │ ├── Join.java │ │ ├── JoinHandler.java │ │ ├── JoinPath.java │ │ ├── JpaQuery.java │ │ ├── JpaQueryEach.java │ │ ├── Or.java │ │ ├── Order.java │ │ ├── OrderPath.java │ │ ├── QueryAppender.java │ │ ├── QueryRender.java │ │ ├── Select.java │ │ ├── SelectPath.java │ │ ├── SubJpaQuery.java │ │ ├── Where.java │ │ ├── WhereHandler.java │ │ ├── WherePath.java │ │ └── package-info.java │ ├── impl │ │ ├── BetweenPathImpl.java │ │ ├── GroupImpl.java │ │ ├── GroupPathImpl.java │ │ ├── HavingImpl.java │ │ ├── HavingPathImpl.java │ │ ├── JoinImpl.java │ │ ├── JoinPathImpl.java │ │ ├── JpaQueryHandler.java │ │ ├── JpaQueryImpl.java │ │ ├── OrderImpl.java │ │ ├── OrderPathImpl.java │ │ ├── QueryAppenderImpl.java │ │ ├── SelectImpl.java │ │ ├── SelectPathImpl.java │ │ ├── SubJpaQueryImpl.java │ │ ├── WhereImpl.java │ │ └── WherePathImpl.java │ ├── package-info.java │ ├── render │ │ ├── JpaQueryRender.java │ │ ├── impl │ │ │ ├── JpaQueryRenderImpl.java │ │ │ └── package-info.java │ │ └── package-info.java │ └── vo │ │ ├── EntityInfo.java │ │ ├── FromInfo.java │ │ ├── PathInfo.java │ │ ├── QueryContent.java │ │ └── package-info.java │ ├── example │ ├── Example.java │ ├── Examples.java │ └── package-info.java │ ├── support │ └── package-info.java │ └── util │ ├── _Helper.java │ ├── _MergeMap.java │ └── _Proxys.java └── test ├── java └── com │ └── jpaquery │ └── testcase │ ├── Gender.java │ ├── builder │ ├── JPQLTest.java │ └── package-info.java │ ├── package-info.java │ ├── querytest │ ├── ExampleTest.java │ ├── QueryTest.java │ └── package-info.java │ ├── schema │ ├── BaseEntity.java │ ├── Clazz.java │ ├── IdEntity.java │ ├── Student.java │ ├── Teacher.java │ └── package-info.java │ └── vo │ ├── VClazz.java │ ├── VStudent.java │ └── package-info.java └── resources └── log4j2.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | /.idea/ 14 | /target/ 15 | /.project 16 | /.classpath 17 | /.settings/ 18 | /logs/ 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 框架优势 2 | 3 | ## 类型安全 4 | 5 | 字符串只能和字符串比较,数字只能和数字比较。 6 | 7 | ## 防SQL注入 8 | 9 | 基本不存在将参数直接拼接进查询语句的可能,杜绝SQL注入风险。 10 | 11 | ## 重构支持 12 | 13 | 可以直接重构实体的getter方法,则所有位置都将一起重构,对于修改字段信息是非常友好的,而且能够及时发现字段修改不到位的错误。 14 | 15 | ## 提示友好 16 | 17 | 再也不必到处去查实体包含哪些字段,也不再担心写错字段名,IDE直接提示。同时,几乎不提供写不合法JPQL的方法。 18 | 19 | ## 简单易用 20 | 21 | 与其它类似框架,如QueryDSL,Hibernate Criteria等相比,无生成代码的坑,更像SQL,更容易理解和使用。 22 | 23 | # 使用手册 24 | 25 | 请参考[JpaQuery手册](https://github.com/ajiang-open/jpaquery/wiki/JpaQuery-Manual) -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.jpaquery 6 | jpaquery 7 | 1.1.3 8 | jar 9 | JPAQuery 10 | A tool for jpa 11 | https://github.com/ajiang-open/jpaquery 12 | 13 | jpaquery.com 14 | https://github.com/ajiang-open/jpaquery 15 | 16 | 17 | 18 | The Apache Software License, Version 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.txt 20 | repo 21 | 22 | 23 | 24 | 25 | pittlu 26 | pittlu 27 | jpaquery@gmail.com 28 | 29 | 30 | 31 | scm:git:git://github.com/ajiang-open/jpaquery 32 | scm:git:git://github.com/ajiang-open/jpaquery 33 | https://github.com/ajiang-open/jpaquery 34 | 35 | 36 | Github 37 | https://github.com/ajiang-open/jpaquery/issues 38 | 39 | 40 | 41 | 42 | Central 43 | https://repo1.maven.org/maven2/ 44 | 45 | true 46 | 47 | 48 | true 49 | 50 | 51 | 52 | Sonatype Public 53 | https://oss.sonatype.org/content/groups/public 54 | 55 | true 56 | 57 | 58 | true 59 | 60 | 61 | 62 | Sonatype Staging 63 | https://oss.sonatype.org/content/groups/staging 64 | 65 | true 66 | 67 | 68 | true 69 | 70 | 71 | 72 | Apache Snapshots 73 | https://repository.apache.org/snapshots/ 74 | 75 | true 76 | 77 | 78 | 79 | Codehaus Snapshots 80 | https://nexus.codehaus.org/snapshots/ 81 | 82 | true 83 | 84 | 85 | 86 | debop-releases-bintray 87 | http://dl.bintray.com/debop/maven 88 | 89 | 90 | 91 | 92 | 93 | Central 94 | https://repo1.maven.org/maven2/ 95 | 96 | true 97 | 98 | 99 | true 100 | 101 | 102 | 103 | Apache Snapshots 104 | https://repository.apache.org/snapshots/ 105 | 106 | true 107 | 108 | 109 | 110 | Codehaus Snapshots 111 | https://nexus.codehaus.org/snapshots/ 112 | 113 | true 114 | 115 | 116 | 117 | 118 | 119 | 1.8 120 | 1.8 121 | 1.7.24 122 | 3.2.5 123 | 3.5 124 | 1.9.3 125 | 2.1.9.RELEASE 126 | 5.1.8.RELEASE 127 | 1.0.0.Final 128 | 4.12 129 | 2.6.1 130 | 131 | 132 | 133 | 134 | org.slf4j 135 | slf4j-api 136 | ${slf4j.version} 137 | 138 | 139 | cglib 140 | cglib 141 | ${cglib.version} 142 | 143 | 144 | org.apache.commons 145 | commons-lang3 146 | ${commons-lang3.version} 147 | 148 | 149 | commons-beanutils 150 | commons-beanutils 151 | ${commons-beanutils.version} 152 | 153 | 154 | org.springframework.data 155 | spring-data-commons 156 | ${spring-data-commons.version} 157 | 158 | 159 | org.springframework 160 | spring-core 161 | 162 | 163 | org.springframework 164 | spring-beans 165 | 166 | 167 | 168 | 169 | org.springframework 170 | spring-tx 171 | ${spring.version} 172 | provided 173 | 174 | 175 | org.hibernate.javax.persistence 176 | hibernate-jpa-2.1-api 177 | ${hibernate-jpa-2.1-api.version} 178 | provided 179 | 180 | 181 | org.hibernate 182 | hibernate-core 183 | 5.2.10.Final 184 | provided 185 | 186 | 187 | junit 188 | junit 189 | ${junit.version} 190 | test 191 | 192 | 193 | org.apache.logging.log4j 194 | log4j-slf4j-impl 195 | ${log4j.version} 196 | test 197 | 198 | 199 | org.apache.logging.log4j 200 | log4j-api 201 | ${log4j.version} 202 | test 203 | 204 | 205 | org.apache.logging.log4j 206 | log4j-core 207 | ${log4j.version} 208 | test 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | org.apache.maven.plugins 217 | maven-javadoc-plugin 218 | 2.10.4 219 | 220 | UTF-8 221 | true 222 | UTF-8 223 | UTF-8 224 | 225 | 226 | 227 | attach-javadocs 228 | 229 | jar 230 | 231 | 232 | -Xdoclint:none 233 | 234 | 235 | 236 | 237 | 238 | 239 | org.apache.maven.plugins 240 | maven-source-plugin 241 | 3.0.1 242 | 243 | 244 | attach-sources 245 | 246 | jar 247 | 248 | 249 | 250 | 251 | 252 | 253 | org.apache.maven.plugins 254 | maven-gpg-plugin 255 | 1.5 256 | 257 | 258 | sign-artifacts 259 | verify 260 | 261 | sign 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | jpaquery-snapshots 272 | 273 | 274 | jpaquery-snapshots 275 | JpaQuery Snapshot Repository 276 | https://oss.sonatype.org/content/repositories/snapshots 277 | 278 | 279 | 280 | 281 | jpaquery-releases 282 | 283 | 284 | jpaquery-releases 285 | JpaQuery Release Repository 286 | https://oss.sonatype.org/service/local/staging/deploy/maven2 287 | 288 | 289 | 290 | 291 | 292 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/builder/JPQL.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.builder; 2 | 3 | import java.sql.Timestamp; 4 | import java.text.DateFormat; 5 | import java.text.SimpleDateFormat; 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.Date; 9 | import java.util.HashSet; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | import java.util.Set; 13 | import java.util.StringTokenizer; 14 | import java.util.regex.Pattern; 15 | 16 | import javax.persistence.EntityManager; 17 | import javax.persistence.NoResultException; 18 | import javax.persistence.Query; 19 | 20 | import org.apache.commons.lang3.StringUtils; 21 | import org.hibernate.SQLQuery; 22 | import org.hibernate.Session; 23 | import org.hibernate.SessionFactory; 24 | import org.hibernate.engine.spi.SessionFactoryImplementor; 25 | import org.hibernate.hql.internal.ast.QueryTranslatorImpl; 26 | import org.hibernate.query.NativeQuery; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | import org.springframework.data.domain.Page; 30 | import org.springframework.data.domain.PageImpl; 31 | import org.springframework.data.domain.Pageable; 32 | 33 | import com.jpaquery.util._Helper; 34 | 35 | /** 36 | * JPQL通用组装器 37 | * 38 | * @author lujijiang 39 | * 40 | */ 41 | public class JPQL { 42 | 43 | /** 44 | * 用于格式化SQL和注入参数 45 | * 46 | * @author lujijiang 47 | */ 48 | public static class SqlFormatter { 49 | private static final String WHITESPACE = " \n\r\f\t"; 50 | 51 | private static final Set BEGIN_CLAUSES = new HashSet(); 52 | private static final Set END_CLAUSES = new HashSet(); 53 | private static final Set LOGICAL = new HashSet(); 54 | private static final Set QUANTIFIERS = new HashSet(); 55 | private static final Set DML = new HashSet(); 56 | private static final Set MISC = new HashSet(); 57 | 58 | static { 59 | BEGIN_CLAUSES.add("left"); 60 | BEGIN_CLAUSES.add("right"); 61 | BEGIN_CLAUSES.add("inner"); 62 | BEGIN_CLAUSES.add("outer"); 63 | BEGIN_CLAUSES.add("group"); 64 | BEGIN_CLAUSES.add("order"); 65 | BEGIN_CLAUSES.add("limit");// 适应MYSQL 66 | 67 | END_CLAUSES.add("where"); 68 | END_CLAUSES.add("set"); 69 | END_CLAUSES.add("having"); 70 | END_CLAUSES.add("join"); 71 | END_CLAUSES.add("from"); 72 | END_CLAUSES.add("by"); 73 | END_CLAUSES.add("join"); 74 | END_CLAUSES.add("into"); 75 | END_CLAUSES.add("union"); 76 | 77 | LOGICAL.add("and"); 78 | LOGICAL.add("or"); 79 | LOGICAL.add("when"); 80 | LOGICAL.add("else"); 81 | LOGICAL.add("end"); 82 | 83 | QUANTIFIERS.add("in"); 84 | QUANTIFIERS.add("all"); 85 | QUANTIFIERS.add("exists"); 86 | QUANTIFIERS.add("some"); 87 | QUANTIFIERS.add("any"); 88 | 89 | DML.add("insert"); 90 | DML.add("update"); 91 | DML.add("delete"); 92 | 93 | MISC.add("select"); 94 | MISC.add("on"); 95 | MISC.add("with"); 96 | } 97 | 98 | static final String indentString = " "; 99 | static final String initial = "\n "; 100 | 101 | public static String format(String source, String databaseType, List args) { 102 | return new FormatProcess(source, databaseType, args).perform(); 103 | } 104 | 105 | private static class FormatProcess { 106 | String databaseType; 107 | List args; 108 | boolean beginLine = true; 109 | boolean afterBeginBeforeEnd = false; 110 | boolean afterByOrSetOrFromOrSelect = false; 111 | boolean afterValues = false; 112 | boolean afterOn = false; 113 | boolean afterBetween = false; 114 | boolean afterInsert = false; 115 | int inFunction = 0; 116 | int parensSinceSelect = 0; 117 | private LinkedList parenCounts = new LinkedList(); 118 | private LinkedList afterByOrFromOrSelects = new LinkedList(); 119 | 120 | int indent = 1; 121 | 122 | StringBuilder result = new StringBuilder(); 123 | StringTokenizer tokens; 124 | String lastToken; 125 | String token; 126 | String lcToken; 127 | private int i; 128 | 129 | public FormatProcess(String sql, String databaseType, List args) { 130 | this.databaseType = databaseType; 131 | this.args = args; 132 | tokens = new StringTokenizer(sql, "()+*/-=<>'`\"[],?" + WHITESPACE, true); 133 | } 134 | 135 | private String formatArg(Object arg) { 136 | if (arg == null) { 137 | return "null"; 138 | } 139 | if (_Helper.isNumber(arg.getClass())) { 140 | return arg.toString(); 141 | } 142 | if (arg instanceof Date) { 143 | if ("oracle".equalsIgnoreCase(databaseType)) { 144 | DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 145 | return "to_date('" + dateFormat.format((Date) arg) + "','yyyy-mm-dd hh24:mi:ss')"; 146 | } 147 | if ("mysql".equalsIgnoreCase(databaseType)) { 148 | DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 149 | return "str_to_date('" + dateFormat.format((Date) arg) + "','%Y-%m-%d %T')"; 150 | } 151 | if ("informix".equalsIgnoreCase(databaseType)) { 152 | DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 153 | return "to_date('" + dateFormat.format((Date) arg) + "','%Y-%m-%d %H:%M:%S')"; 154 | } 155 | DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 156 | return "'" + dateFormat.format((Date) arg) + "'"; 157 | } 158 | return "'" + StringUtils.replace(StringUtils.replace(arg.toString(), "'", "''"), "\\", "\\\\") + "'"; 159 | } 160 | 161 | public String perform() { 162 | i = 0; 163 | 164 | result.append(initial); 165 | 166 | while (tokens.hasMoreTokens()) { 167 | token = tokens.nextToken(); 168 | lcToken = token.toLowerCase(); 169 | 170 | if ("'".equals(token)) { 171 | String t; 172 | do { 173 | t = tokens.nextToken(); 174 | token += t; 175 | } while (!"'".equals(t) && tokens.hasMoreTokens()); // cannot 176 | // handle 177 | // single 178 | // quotes 179 | } else if ("\"".equals(token)) { 180 | String t; 181 | do { 182 | t = tokens.nextToken(); 183 | token += t; 184 | } while (!"\"".equals(t)); 185 | } 186 | if ("?".equals(token)) {// 注入参数 187 | if (args.size() > i) { 188 | Object arg = args.get(i); 189 | result.append(formatArg(arg)); 190 | } else { 191 | result.append("?"); 192 | } 193 | i++; 194 | } else if (afterByOrSetOrFromOrSelect && ",".equals(token)) { 195 | commaAfterByOrFromOrSelect(); 196 | } else if (afterOn && ",".equals(token)) { 197 | commaAfterOn(); 198 | } 199 | 200 | else if ("(".equals(token)) { 201 | openParen(); 202 | } else if (")".equals(token)) { 203 | closeParen(); 204 | } 205 | 206 | else if (BEGIN_CLAUSES.contains(lcToken)) { 207 | beginNewClause(); 208 | } 209 | 210 | else if (END_CLAUSES.contains(lcToken)) { 211 | endNewClause(); 212 | } 213 | 214 | else if ("select".equals(lcToken)) { 215 | select(); 216 | } 217 | 218 | else if (DML.contains(lcToken)) { 219 | updateOrInsertOrDelete(); 220 | } 221 | 222 | else if ("values".equals(lcToken)) { 223 | values(); 224 | } 225 | 226 | else if ("on".equals(lcToken)) { 227 | on(); 228 | } 229 | 230 | else if (afterBetween && lcToken.equals("and")) { 231 | misc(); 232 | afterBetween = false; 233 | } 234 | 235 | else if (LOGICAL.contains(lcToken)) { 236 | logical(); 237 | } 238 | 239 | else if (isWhitespace(token)) { 240 | white(); 241 | } 242 | 243 | else { 244 | misc(); 245 | } 246 | 247 | if (!isWhitespace(token)) { 248 | lastToken = lcToken; 249 | } 250 | 251 | } 252 | return result.toString(); 253 | } 254 | 255 | private void commaAfterOn() { 256 | out(); 257 | indent--; 258 | newline(); 259 | afterOn = false; 260 | afterByOrSetOrFromOrSelect = true; 261 | } 262 | 263 | private void commaAfterByOrFromOrSelect() { 264 | out(); 265 | newline(); 266 | } 267 | 268 | private void logical() { 269 | if ("end".equals(lcToken)) { 270 | indent--; 271 | } 272 | newline(); 273 | out(); 274 | beginLine = false; 275 | } 276 | 277 | private void on() { 278 | indent++; 279 | afterOn = true; 280 | newline(); 281 | out(); 282 | beginLine = false; 283 | } 284 | 285 | private void misc() { 286 | out(); 287 | if ("between".equals(lcToken)) { 288 | afterBetween = true; 289 | } 290 | if (afterInsert) { 291 | newline(); 292 | afterInsert = false; 293 | } else { 294 | beginLine = false; 295 | if ("case".equals(lcToken)) { 296 | indent++; 297 | } 298 | } 299 | } 300 | 301 | private void white() { 302 | if (!beginLine) { 303 | result.append(" "); 304 | } 305 | } 306 | 307 | private void updateOrInsertOrDelete() { 308 | out(); 309 | indent++; 310 | beginLine = false; 311 | if ("update".equals(lcToken)) { 312 | newline(); 313 | } 314 | if ("insert".equals(lcToken)) { 315 | afterInsert = true; 316 | } 317 | } 318 | 319 | private void select() { 320 | out(); 321 | indent++; 322 | newline(); 323 | parenCounts.addLast(Integer.valueOf(parensSinceSelect)); 324 | afterByOrFromOrSelects.addLast(Boolean.valueOf(afterByOrSetOrFromOrSelect)); 325 | parensSinceSelect = 0; 326 | afterByOrSetOrFromOrSelect = true; 327 | } 328 | 329 | private void out() { 330 | result.append(token); 331 | } 332 | 333 | private void endNewClause() { 334 | if (!afterBeginBeforeEnd) { 335 | indent--; 336 | if (afterOn) { 337 | indent--; 338 | afterOn = false; 339 | } 340 | newline(); 341 | } 342 | out(); 343 | if (!"union".equals(lcToken)) { 344 | indent++; 345 | } 346 | newline(); 347 | afterBeginBeforeEnd = false; 348 | afterByOrSetOrFromOrSelect = "by".equals(lcToken) || "set".equals(lcToken) || "from".equals(lcToken); 349 | } 350 | 351 | private void beginNewClause() { 352 | if (!afterBeginBeforeEnd) { 353 | if (afterOn) { 354 | indent--; 355 | afterOn = false; 356 | } 357 | indent--; 358 | newline(); 359 | } 360 | out(); 361 | beginLine = false; 362 | afterBeginBeforeEnd = true; 363 | } 364 | 365 | private void values() { 366 | indent--; 367 | newline(); 368 | out(); 369 | indent++; 370 | newline(); 371 | afterValues = true; 372 | } 373 | 374 | private void closeParen() { 375 | parensSinceSelect--; 376 | if (parensSinceSelect < 0) { 377 | indent--; 378 | parensSinceSelect = parenCounts.removeLast().intValue(); 379 | afterByOrSetOrFromOrSelect = afterByOrFromOrSelects.removeLast().booleanValue(); 380 | } 381 | if (inFunction > 0) { 382 | inFunction--; 383 | out(); 384 | } else { 385 | if (!afterByOrSetOrFromOrSelect) { 386 | indent--; 387 | newline(); 388 | } 389 | out(); 390 | } 391 | beginLine = false; 392 | } 393 | 394 | private void openParen() { 395 | if (isFunctionName(lastToken) || inFunction > 0) { 396 | inFunction++; 397 | } 398 | beginLine = false; 399 | if (inFunction > 0) { 400 | out(); 401 | } else { 402 | out(); 403 | if (!afterByOrSetOrFromOrSelect) { 404 | indent++; 405 | newline(); 406 | beginLine = true; 407 | } 408 | } 409 | parensSinceSelect++; 410 | } 411 | 412 | private static boolean isFunctionName(String tok) { 413 | final char begin = tok.charAt(0); 414 | final boolean isIdentifier = Character.isJavaIdentifierStart(begin) || '"' == begin; 415 | return isIdentifier && !LOGICAL.contains(tok) && !END_CLAUSES.contains(tok) 416 | && !QUANTIFIERS.contains(tok) && !DML.contains(tok) && !MISC.contains(tok); 417 | } 418 | 419 | private static boolean isWhitespace(String token) { 420 | return WHITESPACE.indexOf(token) >= 0; 421 | } 422 | 423 | private void newline() { 424 | result.append("\n"); 425 | for (int i = 0; i < indent; i++) { 426 | result.append(indentString); 427 | } 428 | beginLine = true; 429 | } 430 | } 431 | 432 | } 433 | 434 | private static final Logger logger = LoggerFactory.getLogger(JPQL.class); 435 | 436 | static final Pattern QUERY_ARG_PATTERN = Pattern.compile("\\?"); 437 | 438 | private JPQL() { 439 | } 440 | 441 | private StringBuilder jpqlBuilder = new StringBuilder(); 442 | 443 | private List argList = new ArrayList<>(); 444 | 445 | public static JPQL create() { 446 | return new JPQL(); 447 | } 448 | 449 | public JPQL append(String jpqlFragment, Object... args) { 450 | if (jpqlFragment == null) { 451 | throw new IllegalArgumentException(String.format("The append jpql fragment should not be null")); 452 | } 453 | if (jpqlFragment.contains("'")) { 454 | throw new IllegalArgumentException(String.format("The append jpql fragment should not contains \"'\"")); 455 | } 456 | if (args != null) { 457 | int count = StringUtils.countMatches(jpqlFragment, "?"); 458 | if (count != args.length) { 459 | throw new IllegalArgumentException( 460 | String.format("The number of question marks:%d and the number of arguments:%d is not equal", 461 | count, args.length)); 462 | } 463 | for (Object arg : args) { 464 | this.argList.add(arg); 465 | } 466 | } 467 | if (this.jpqlBuilder.length() > 1 468 | && !this.jpqlBuilder.substring(this.jpqlBuilder.length() - 1, this.jpqlBuilder.length()).equals(" ")) { 469 | this.jpqlBuilder.append(" "); 470 | } 471 | this.jpqlBuilder.append(jpqlFragment); 472 | return this; 473 | } 474 | 475 | private Query createQuery(EntityManager em, String jpql, List argList, boolean cacheable) { 476 | if (logger.isDebugEnabled()) { 477 | logger.debug("JPQL:{}", this); 478 | } 479 | Query query = em.createQuery(jpql); 480 | for (int i = 0; i < argList.size(); i++) { 481 | Object arg = argList.get(i); 482 | if (arg != null && arg instanceof Date) { 483 | arg = new Timestamp(((Date) arg).getTime()); 484 | } 485 | query.setParameter(i + 1, arg); 486 | } 487 | query.setHint("org.hibernate.cacheable", cacheable); 488 | return query; 489 | } 490 | 491 | private Query createQuery(EntityManager em, boolean cacheable) { 492 | return createQuery(em, this.jpqlBuilder.toString(), argList, cacheable); 493 | } 494 | 495 | /** 496 | * 获取结果列表 497 | * 498 | * @param em 499 | * 实体管理器 500 | * @param cacheable 501 | * 查询缓存开关 502 | * @return 503 | */ 504 | @SuppressWarnings("unchecked") 505 | public List list(EntityManager em, boolean cacheable) { 506 | Query query = createQuery(em, cacheable); 507 | return query.getResultList(); 508 | } 509 | 510 | /** 511 | * 获取结果列表 512 | * 513 | * @param em 514 | * 实体管理器 515 | * @return 516 | */ 517 | public List list(EntityManager em) { 518 | return list(em, false); 519 | } 520 | 521 | public Object one(EntityManager em) { 522 | return one(em, false); 523 | } 524 | 525 | public Object one(EntityManager em, boolean cacheable) { 526 | Query query = createQuery(em, cacheable); 527 | try { 528 | return query.getSingleResult(); 529 | } catch (NoResultException e) { 530 | return null; 531 | } 532 | } 533 | 534 | public List list(EntityManager em, int start, int max, boolean cacheable) { 535 | Query query = createQuery(em, cacheable); 536 | query.setFirstResult(start); 537 | query.setMaxResults(max); 538 | return query.getResultList(); 539 | } 540 | 541 | public List list(EntityManager em, int start, int max) { 542 | return list(em, start, max, false); 543 | } 544 | 545 | public List top(EntityManager em, int top, boolean cacheable) { 546 | return list(em, 0, top, cacheable); 547 | } 548 | 549 | public List top(EntityManager em, int top) { 550 | return top(em, top, false); 551 | } 552 | 553 | public Long count(EntityManager em) { 554 | Session session = em.unwrap(Session.class); 555 | SessionFactory sessionFactory = session.getSessionFactory(); 556 | String originalHql = this.jpqlBuilder.toString(); 557 | QueryTranslatorImpl queryTranslator = new QueryTranslatorImpl(originalHql, originalHql, Collections.EMPTY_MAP, 558 | (SessionFactoryImplementor) sessionFactory); 559 | queryTranslator.compile(Collections.EMPTY_MAP, false); 560 | String sql = "select count(*) from (" + queryTranslator.getSQLString() + ") tmp"; 561 | NativeQuery query = session.createNativeQuery(sql); 562 | for (int i = 0; i < argList.size(); i++) { 563 | query.setParameter(i, argList.get(i)); 564 | } 565 | return ((Number) query.uniqueResult()).longValue(); 566 | } 567 | 568 | @SuppressWarnings({ "unchecked", "rawtypes" }) 569 | public Page page(EntityManager em, Pageable pageable, boolean cacheable) { 570 | Long total = count(em); 571 | List content = total > pageable.getOffset() 572 | ? list(em, (int)pageable.getOffset(), pageable.getPageSize(), cacheable) : Collections.emptyList(); 573 | return new PageImpl(content, pageable, total); 574 | } 575 | 576 | public Page page(EntityManager em, Pageable pageable) { 577 | return page(em, pageable, false); 578 | } 579 | 580 | public String toString() { 581 | return SqlFormatter.format(jpqlBuilder.toString(), "mysql", argList); 582 | } 583 | 584 | } 585 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/builder/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.builder; -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/QueryHandler.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core; 2 | 3 | import com.jpaquery.core.facade.JpaQuery; 4 | 5 | public interface QueryHandler { 6 | T handle(JpaQuery query); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/Querys.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.util.LinkedList; 6 | 7 | import org.springframework.transaction.TransactionDefinition; 8 | import org.springframework.transaction.support.AbstractPlatformTransactionManager; 9 | 10 | import com.jpaquery.core.facade.JpaQuery; 11 | import com.jpaquery.core.impl.JpaQueryHandler; 12 | import com.jpaquery.core.impl.JpaQueryImpl; 13 | import com.jpaquery.core.render.impl.JpaQueryRenderImpl; 14 | import com.jpaquery.util._Proxys; 15 | 16 | /** 17 | * Querys工具类 18 | * 19 | * @author lujijiang 20 | * 21 | */ 22 | public class Querys { 23 | /** 24 | * 新建一个查询器 25 | * 26 | * @return 27 | */ 28 | private static JpaQuery newJpaQuery() { 29 | return new JpaQueryImpl(new JpaQueryHandler(), new JpaQueryRenderImpl()); 30 | } 31 | 32 | /** 33 | * 匿名查询器 34 | * @param queryHandler 35 | * @param 36 | * @return 37 | */ 38 | public static T query(QueryHandler queryHandler){ 39 | return queryHandler.handle(newJpaQuery()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/SubQueryHandler.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core; 2 | 3 | import com.jpaquery.core.facade.JpaQuery; 4 | 5 | public interface SubQueryHandler { 6 | void handle(JpaQuery subQuery); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/constant/LikeWay.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.constant; 2 | 3 | public enum LikeWay { 4 | leftLike, rightLike, allLike 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/constant/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.core.constant; -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/And.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | /** 4 | * and子句 5 | * 6 | * @author lujijiang 7 | * 8 | */ 9 | public interface And extends Where { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/BetweenPath.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | /** 4 | * between类型路径 5 | * 6 | * @author lujijiang 7 | * 8 | * @param 9 | */ 10 | public interface BetweenPath { 11 | 12 | Where and(T obj); 13 | 14 | Where and(JpaQuery subFinder); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/FunctionPath.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | /** 4 | * 函数路径 5 | * 6 | * @author lujijiang 7 | * 8 | * @param 9 | */ 10 | public interface FunctionPath extends SelectPath { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/Group.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | /** 4 | * 分组对象 5 | * 6 | * @author lujijiang 7 | * 8 | */ 9 | public interface Group extends QueryRender { 10 | /** 11 | * 获得分组路径 12 | * 13 | * @param obj 14 | * @return 15 | */ 16 | GroupPath get(Object obj); 17 | 18 | QueryAppender append(String queryString, Object... args); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/GroupPath.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | /** 4 | * 分组路径 5 | * 6 | * @author lujijiang 7 | * 8 | */ 9 | public interface GroupPath { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/Having.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface Having extends QueryRender { 4 | 5 | HavingPath get(T obj); 6 | 7 | QueryAppender append(String queryString, Object... args); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/HavingFunctionPath.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface HavingFunctionPath extends HavingPath { 4 | Having equal(T obj); 5 | 6 | Having notEqual(T obj); 7 | 8 | Having greatThan(T obj); 9 | 10 | Having greatEqual(T obj); 11 | 12 | Having lessThan(T obj); 13 | 14 | Having lessEqual(T obj); 15 | 16 | Having equal(JpaQuery subFinder); 17 | 18 | Having notEqual(JpaQuery subFinder); 19 | 20 | Having greatThan(JpaQuery subFinder); 21 | 22 | Having greatEqual(JpaQuery subFinder); 23 | 24 | Having lessThan(JpaQuery subFinder); 25 | 26 | Having lessEqual(JpaQuery subFinder); 27 | 28 | Having equalIfExist(T obj); 29 | 30 | Having notEqualIfExist(T obj); 31 | 32 | Having greatThanIfExist(T obj); 33 | 34 | Having greatEqualIfExist(T obj); 35 | 36 | Having lessThanIfExist(T obj); 37 | 38 | Having lessEqualIfExist(T obj); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/HavingPath.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface HavingPath { 4 | HavingPath distinct(); 5 | 6 | HavingFunctionPath count(); 7 | 8 | HavingFunctionPath avg(); 9 | 10 | HavingFunctionPath sum(); 11 | 12 | HavingFunctionPath min(); 13 | 14 | HavingFunctionPath max(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/Join.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | import java.util.Collection; 4 | 5 | public interface Join { 6 | 7 | public JoinPath get(T[] array); 8 | 9 | JoinPath get(Collection list); 10 | 11 | JoinPath get(T obj); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/JoinHandler.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface JoinHandler { 4 | void handle(T model); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/JoinPath.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface JoinPath { 4 | enum JoinPathType { 5 | inner, left, right, full 6 | } 7 | 8 | void inner(JoinHandler joinHandler); 9 | 10 | void left(JoinHandler joinHandler); 11 | 12 | void right(JoinHandler joinHandler); 13 | 14 | void full(JoinHandler joinHandler); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/JpaQuery.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | 6 | import javax.persistence.EntityManager; 7 | 8 | import com.jpaquery.core.QueryHandler; 9 | import com.jpaquery.core.SubQueryHandler; 10 | import org.springframework.data.domain.Page; 11 | import org.springframework.data.domain.Pageable; 12 | 13 | import com.jpaquery.core.vo.QueryContent; 14 | 15 | /** 16 | * Finder查询器接口 17 | * 18 | * @author lujijiang 19 | * 20 | */ 21 | public interface JpaQuery extends QueryRender { 22 | /** 23 | * 生成子查询 24 | * 25 | * @return 26 | */ 27 | public abstract void subQuery(SubQueryHandler subQueryHandler); 28 | 29 | /** 30 | * 指定from的表类型 31 | * 32 | * @param type 33 | * @return 34 | */ 35 | public abstract T from(Class type); 36 | 37 | /** 38 | * 获得where子句对象 39 | * 40 | * @return 41 | */ 42 | public abstract Where where(); 43 | 44 | /** 45 | * 直接产生查询字段路径对象 46 | * 47 | * @param obj 48 | * @return 49 | */ 50 | public WherePath where(T obj); 51 | 52 | /** 53 | * 获得select子句对象 54 | * 55 | * @return 56 | */ 57 | public abstract Select select(); 58 | 59 | /** 60 | * 直接指定select字段路径对象 61 | * 62 | * @param obj 63 | * @return 64 | */ 65 | public SelectPath select(T obj); 66 | 67 | /** 68 | * 获得order子句对象 69 | * 70 | * @return 71 | */ 72 | public abstract Order order(); 73 | 74 | /** 75 | * 直接指定相关字段的order路径对象 76 | * 77 | * @param objs 78 | * @return 79 | */ 80 | public OrderPath order(Object obj); 81 | 82 | /** 83 | * 获得goup子句对象 84 | * 85 | * @return 86 | */ 87 | public abstract Group group(); 88 | 89 | /** 90 | * 直接指定相关字段的group路径对象 91 | * 92 | * @param objs 93 | * @return 94 | */ 95 | public GroupPath group(Object obj); 96 | 97 | /** 98 | * 获得having子句对象 99 | * 100 | * @return 101 | */ 102 | public abstract Having having(); 103 | 104 | /** 105 | * 直接指定having字段路径对象 106 | * 107 | * @param obj 108 | * @return 109 | */ 110 | public HavingPath having(T obj); 111 | 112 | /** 113 | * 获得join子句对象 114 | * 115 | * @return 116 | */ 117 | public abstract Join join(); 118 | 119 | /** 120 | * 直接指定join字段路径对象 121 | * 122 | * @param obj 123 | * @return 124 | */ 125 | public JoinPath join(Collection list); 126 | 127 | /** 128 | * 直接指定join字段路径对象 129 | * 130 | * @param obj 131 | * @return 132 | */ 133 | public JoinPath join(T obj); 134 | 135 | /** 136 | * 获取查询语句 137 | * 138 | * @return 139 | */ 140 | public abstract QueryContent toQueryContent(); 141 | 142 | /** 143 | * 生成any谓词 144 | * 145 | * @return 146 | */ 147 | public SubJpaQuery any(); 148 | 149 | /** 150 | * 生成some谓词 151 | * 152 | * @return 153 | */ 154 | public SubJpaQuery some(); 155 | 156 | /** 157 | * 生成all谓词 158 | * 159 | * @return 160 | */ 161 | public SubJpaQuery all(); 162 | 163 | /** 164 | * 获取对象或者字段的别名 165 | * 166 | * @param proxyInstance 167 | * 模型对象或者模型对象属性 168 | * @return 169 | */ 170 | public abstract String alias(Object proxyInstance); 171 | 172 | /** 173 | * 获得统计类型的查询信息,和toQueryContent的区别是只有第一个select项有效并且order by子句消失 174 | * 175 | * @return 176 | */ 177 | public QueryContent toCountQueryContent(); 178 | 179 | /** 180 | * 查询单个结果 181 | * 182 | * @param em 183 | * @return 184 | */ 185 | public Object one(EntityManager em); 186 | 187 | /** 188 | * 查询单个结果 189 | * 190 | * @param em 191 | * @param cacheable 192 | * @return 193 | */ 194 | public Object one(EntityManager em, boolean cacheable); 195 | 196 | /** 197 | * 查询所有结果 198 | * 199 | * @param em 200 | * @return 201 | */ 202 | public List list(EntityManager em); 203 | 204 | /** 205 | * 查询所有结果 206 | * 207 | * @param em 208 | * @param cacheable 209 | * @return 210 | */ 211 | public List list(EntityManager em, boolean cacheable); 212 | 213 | /** 214 | * 查询指定范围的结果 215 | * 216 | * @param em 217 | * @param start 218 | * @param max 219 | * @param cacheable 220 | * @return 221 | */ 222 | public List list(EntityManager em, int start, int max); 223 | 224 | /** 225 | * 查询指定范围的结果 226 | * 227 | * @param em 228 | * @param start 229 | * @param max 230 | * @param cacheable 231 | * @return 232 | */ 233 | public List list(EntityManager em, int start, int max, boolean cacheable); 234 | 235 | /** 236 | * 查询前top条结果 237 | * 238 | * @param em 239 | * @param top 240 | * @param cacheable 241 | * @return 242 | */ 243 | public List top(EntityManager em, int top); 244 | 245 | /** 246 | * 查询前top条结果 247 | * 248 | * @param em 249 | * @param top 250 | * @param cacheable 251 | * @return 252 | */ 253 | public List top(EntityManager em, int top, boolean cacheable); 254 | 255 | /** 256 | * 遍历所有结果 257 | * 258 | * @param em 259 | * @param each 260 | * @return 261 | */ 262 | public void each(EntityManager em, JpaQueryEach each); 263 | 264 | /** 265 | * 遍历所有结果 266 | * 267 | * @param em 268 | * @param each 269 | * @param cacheable 270 | * @return 271 | */ 272 | public void each(EntityManager em, JpaQueryEach each, boolean cacheable); 273 | 274 | /** 275 | * 查询指定页面的结果 276 | * 277 | * @param em 278 | * @param pageable 279 | * @param cacheable 280 | * @return 281 | */ 282 | public Page page(EntityManager em, Pageable pageable); 283 | 284 | /** 285 | * 查询指定页面的结果 286 | * 287 | * @param em 288 | * @param pageable 289 | * @param cacheable 290 | * @return 291 | */ 292 | public Page page(EntityManager em, Pageable pageable, boolean cacheable); 293 | 294 | /** 295 | * 统计当前结果集 296 | * 297 | * @param em 298 | * @return 299 | */ 300 | public long count(EntityManager em); 301 | 302 | /** 303 | * 判断是否有数据 304 | * 305 | * @param em 306 | * @param cacheable 307 | * @return 308 | */ 309 | public boolean isEmpty(EntityManager em, boolean cacheable); 310 | 311 | /** 312 | * 判断是否有数据 313 | * 314 | * @param em 315 | * @return 316 | */ 317 | public boolean isEmpty(EntityManager em); 318 | 319 | /** 320 | * 克隆一个Finder,其中所有数据项都和原Finder一致,但两者后续操作不相互影响 321 | * 322 | * @return 323 | */ 324 | public JpaQuery copy(); 325 | 326 | } 327 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/JpaQueryEach.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface JpaQueryEach { 4 | /** 5 | * 处理各个实体 6 | * 7 | * @param entity 8 | */ 9 | public void handle(T entity); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/Or.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface Or extends Where { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/Order.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface Order extends QueryRender { 4 | 5 | OrderPath get(Object obj); 6 | 7 | QueryAppender append(String queryString, Object... args); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/OrderPath.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface OrderPath { 4 | 5 | enum OrderPathType { 6 | asc, desc 7 | } 8 | 9 | Order asc(); 10 | 11 | Order desc(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/QueryAppender.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | /** 4 | * 查询语句追加器 5 | * 6 | * @author lujijiang 7 | * 8 | */ 9 | public interface QueryAppender extends QueryRender { 10 | 11 | /** 12 | * 用于设置名字参数,如where name = :name and password = :password 13 | * 14 | * @param name 15 | * 参数名 16 | * @param value 17 | * 参数值 18 | * @return 19 | */ 20 | public QueryAppender arg(String name, Object value); 21 | 22 | /** 23 | * 序号参数,JPA风格,如where name = ?1 and password = ?2 24 | * 25 | * @param index 26 | * @param value 27 | * @return 28 | */ 29 | public QueryAppender arg(Integer index, Object value); 30 | 31 | /** 32 | * 设置别名,查询语句片段中的别名用英文大括号包起来,如{somefield}=? 33 | * 34 | * @param alias 35 | * 别名 36 | * @param proxy 37 | * 别名所代表的模型对象或者模型字段 38 | * @return 39 | */ 40 | public QueryAppender alias(String alias, Object proxy); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/QueryRender.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | import com.jpaquery.core.vo.QueryContent; 4 | 5 | /** 6 | * 查询信息渲染接口 7 | * 8 | * @author lujijiang 9 | * 10 | */ 11 | public interface QueryRender { 12 | /** 13 | * 获得查询信息 14 | * 15 | * @return 16 | */ 17 | public QueryContent toQueryContent(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/Select.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface Select extends QueryRender { 4 | 5 | SelectPath get(T obj); 6 | 7 | QueryAppender append(String queryString, Object... args); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/SelectPath.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface SelectPath { 4 | 5 | /** 6 | * 聚集函数类型 7 | * 8 | * @author lujijiang 9 | * 10 | */ 11 | public enum SelectPathType { 12 | distinct, count, avg, sum, min, max 13 | } 14 | 15 | SelectPath distinct(); 16 | 17 | FunctionPath count(); 18 | 19 | FunctionPath avg(); 20 | 21 | FunctionPath sum(); 22 | 23 | FunctionPath min(); 24 | 25 | FunctionPath max(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/SubJpaQuery.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface SubJpaQuery { 4 | public enum SubJpaQueryType { 5 | exists, notExists, all, any, some; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/Where.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | /** 4 | * where字句 5 | * 6 | * @author lujijiang 7 | * 8 | */ 9 | public interface Where extends QueryRender { 10 | /** 11 | * 逻辑类型 12 | * 13 | * @author lujijiang 14 | * 15 | */ 16 | public enum WhereType { 17 | and, or 18 | } 19 | 20 | /** 21 | * 获取属性 22 | * 23 | * @param obj 24 | * @return 25 | */ 26 | WherePath get(T obj); 27 | 28 | /** 29 | * 并查询 30 | * @param whereHandler 31 | */ 32 | void and(WhereHandler whereHandler); 33 | 34 | /** 35 | * 或查询 36 | * @param whereHandler 37 | */ 38 | void or(WhereHandler whereHandler); 39 | 40 | /** 41 | * 存在子查询 42 | * 43 | * @param subFinder 44 | */ 45 | Where exists(JpaQuery subFinder); 46 | 47 | /** 48 | * 不存在子查询 49 | * 50 | * @param subFinder 51 | */ 52 | Where notExists(JpaQuery subFinder); 53 | 54 | /** 55 | * 追加查询语句 56 | * 57 | * @param queryString 58 | * @param args 59 | * @return 60 | */ 61 | public QueryAppender append(String queryString, Object... args); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/WhereHandler.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface WhereHandler { 4 | void handle(Where where); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/WherePath.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.facade; 2 | 3 | public interface WherePath { 4 | public enum WherePathType { 5 | equal, notEqual, like, notLike, ilike, notIlike, greatThan, greatEqual, lessThan, lessEqual, between, notBetween, isNull, isNotNull, in, notIn 6 | } 7 | 8 | Where equal(T obj); 9 | 10 | Where notEqual(T obj); 11 | 12 | Where like(T obj); 13 | 14 | Where notLike(T obj); 15 | 16 | Where likeAll(T obj); 17 | 18 | Where notLikeAll(T obj); 19 | 20 | Where likeLeft(T obj); 21 | 22 | Where notLikeLeft(T obj); 23 | 24 | Where likeRight(T obj); 25 | 26 | Where notLikeRight(T obj); 27 | 28 | Where ilike(T obj); 29 | 30 | Where notIlike(T obj); 31 | 32 | Where ilikeAll(T obj); 33 | 34 | Where notIlikeAll(T obj); 35 | 36 | Where ilikeLeft(T obj); 37 | 38 | Where notILikeLeft(T obj); 39 | 40 | Where ilikeRight(T obj); 41 | 42 | Where notILikeRight(T obj); 43 | 44 | Where greatThan(T obj); 45 | 46 | Where greatEqual(T obj); 47 | 48 | Where lessThan(T obj); 49 | 50 | Where lessEqual(T obj); 51 | 52 | BetweenPath between(T obj); 53 | 54 | BetweenPath notBetween(T obj); 55 | 56 | Where in(T... objs); 57 | 58 | Where notIn(T... objs); 59 | 60 | Where equal(JpaQuery subFinder); 61 | 62 | Where notEqual(JpaQuery subFinder); 63 | 64 | Where like(JpaQuery subFinder); 65 | 66 | Where notLike(JpaQuery subFinder); 67 | 68 | Where ilike(JpaQuery subFinder); 69 | 70 | Where notIlike(JpaQuery subFinder); 71 | 72 | Where greatThan(JpaQuery subFinder); 73 | 74 | Where greatEqual(JpaQuery subFinder); 75 | 76 | Where lessThan(JpaQuery subFinder); 77 | 78 | Where lessEqual(JpaQuery subFinder); 79 | 80 | BetweenPath between(JpaQuery subFinder); 81 | 82 | BetweenPath notBetween(JpaQuery subFinder); 83 | 84 | Where in(JpaQuery subFinder); 85 | 86 | Where notIn(JpaQuery subFinder); 87 | 88 | Where equalIfExist(T obj); 89 | 90 | Where notEqualIfExist(T obj); 91 | 92 | Where likeIfExist(T obj); 93 | 94 | Where notLikeIfExist(T obj); 95 | 96 | Where likeLeftIfExist(T obj); 97 | 98 | Where notLikeLeftIfExist(T obj); 99 | 100 | Where likeRightIfExist(T obj); 101 | 102 | Where notLikeRightIfExist(T obj); 103 | 104 | Where likeAllIfExist(T obj); 105 | 106 | Where notLikeAllIfExist(T obj); 107 | 108 | Where ilikeIfExist(T obj); 109 | 110 | Where notIlikeIfExist(T obj); 111 | 112 | Where ilikeLeftIfExist(T obj); 113 | 114 | Where notILikeLeftIfExist(T obj); 115 | 116 | Where ilikeRightIfExist(T obj); 117 | 118 | Where notILikeRightIfExist(T obj); 119 | 120 | Where ilikeAllIfExist(T obj); 121 | 122 | Where notILikeAllIfExist(T obj); 123 | 124 | Where greatThanIfExist(T obj); 125 | 126 | Where greatEqualIfExist(T obj); 127 | 128 | Where lessThanIfExist(T obj); 129 | 130 | Where lessEqualIfExist(T obj); 131 | 132 | BetweenPath betweenIfExist(T obj); 133 | 134 | BetweenPath notBetweenIfExist(T obj); 135 | 136 | Where isNull(); 137 | 138 | Where isNotNull(); 139 | 140 | } -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/facade/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.core.facade; -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/BetweenPathImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import com.jpaquery.core.facade.BetweenPath; 4 | import com.jpaquery.core.facade.JpaQuery; 5 | import com.jpaquery.core.facade.Where; 6 | import com.jpaquery.core.facade.WherePath.WherePathType; 7 | 8 | public class BetweenPathImpl implements BetweenPath { 9 | 10 | JpaQueryHandler finderHandler; 11 | JpaQueryImpl finderImpl; 12 | WhereImpl whereImpl; 13 | WherePathImpl wherePathImpl; 14 | WherePathType wherePathType; 15 | boolean ifExist; 16 | Object arg; 17 | 18 | public BetweenPathImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl, 19 | WhereImpl whereImpl, WherePathImpl wherePathImpl, 20 | WherePathType wherePathType, boolean ifExist, Object arg) { 21 | this.finderHandler = finderHandler; 22 | this.finderImpl = finderImpl; 23 | this.whereImpl = whereImpl; 24 | this.wherePathImpl = wherePathImpl; 25 | this.wherePathType = wherePathType; 26 | this.ifExist = ifExist; 27 | this.arg = arg; 28 | } 29 | 30 | public Where and(T obj) { 31 | Object secondArg = finderHandler.getPathInfo(); 32 | secondArg = secondArg == null ? obj : secondArg; 33 | wherePathImpl.fillPath(wherePathType, ifExist, arg, secondArg); 34 | return whereImpl; 35 | } 36 | 37 | public Where and(JpaQuery subFinder) { 38 | wherePathImpl.fillPath(wherePathType, ifExist, arg, subFinder); 39 | return whereImpl; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/GroupImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.jpaquery.core.facade.Group; 10 | import com.jpaquery.core.facade.GroupPath; 11 | import com.jpaquery.core.facade.QueryAppender; 12 | import com.jpaquery.core.vo.QueryContent; 13 | 14 | public class GroupImpl implements Group { 15 | 16 | static Logger log = LoggerFactory.getLogger(GroupImpl.class); 17 | 18 | JpaQueryHandler finderHandler; 19 | JpaQueryImpl finderImpl; 20 | 21 | /** 22 | * 路径 23 | */ 24 | List paths = new ArrayList<>(); 25 | 26 | public JpaQueryHandler getFinderHandler() { 27 | return finderHandler; 28 | } 29 | 30 | public JpaQueryImpl getFinderImpl() { 31 | return finderImpl; 32 | } 33 | 34 | public List getPaths() { 35 | return paths; 36 | } 37 | 38 | public GroupImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl) { 39 | super(); 40 | this.finderHandler = finderHandler; 41 | this.finderImpl = finderImpl; 42 | } 43 | 44 | public QueryContent toQueryContent() { 45 | return finderImpl.finderRender.toGroup(finderImpl, this); 46 | } 47 | 48 | public GroupPath get(Object obj) { 49 | Object arg = finderHandler.getPathInfo(); 50 | arg = arg == null ? obj : arg; 51 | GroupPath path = new GroupPathImpl(finderHandler, finderImpl, this, arg); 52 | paths.add(path); 53 | return path; 54 | } 55 | 56 | public QueryAppender append(String queryString, Object... args) { 57 | QueryAppenderImpl queryAppenderImpl = new QueryAppenderImpl(finderImpl, queryString, args); 58 | paths.add(queryAppenderImpl); 59 | return queryAppenderImpl; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/GroupPathImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import com.jpaquery.core.facade.GroupPath; 4 | 5 | public class GroupPathImpl implements GroupPath { 6 | 7 | JpaQueryHandler finderHandler; 8 | JpaQueryImpl finderImpl; 9 | GroupImpl groupImpl; 10 | Object arg; 11 | 12 | public JpaQueryHandler getFinderHandler() { 13 | return finderHandler; 14 | } 15 | 16 | public JpaQueryImpl getFinderImpl() { 17 | return finderImpl; 18 | } 19 | 20 | public GroupImpl getGroupImpl() { 21 | return groupImpl; 22 | } 23 | 24 | public Object getArg() { 25 | return arg; 26 | } 27 | 28 | public GroupPathImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl, 29 | GroupImpl groupImpl, Object arg) { 30 | super(); 31 | this.finderHandler = finderHandler; 32 | this.finderImpl = finderImpl; 33 | this.groupImpl = groupImpl; 34 | this.arg = arg; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/HavingImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.jpaquery.core.facade.Having; 10 | import com.jpaquery.core.facade.HavingPath; 11 | import com.jpaquery.core.facade.QueryAppender; 12 | import com.jpaquery.core.vo.QueryContent; 13 | 14 | public class HavingImpl implements Having { 15 | 16 | static Logger log = LoggerFactory.getLogger(HavingImpl.class); 17 | 18 | JpaQueryHandler finderHandler; 19 | JpaQueryImpl finderImpl; 20 | 21 | /** 22 | * 路径 23 | */ 24 | List paths = new ArrayList<>(); 25 | 26 | public JpaQueryHandler getFinderHandler() { 27 | return finderHandler; 28 | } 29 | 30 | public JpaQueryImpl getFinderImpl() { 31 | return finderImpl; 32 | } 33 | 34 | public List getPaths() { 35 | return paths; 36 | } 37 | 38 | public HavingImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl) { 39 | super(); 40 | this.finderHandler = finderHandler; 41 | this.finderImpl = finderImpl; 42 | } 43 | 44 | public QueryContent toQueryContent() { 45 | return finderImpl.finderRender.toHaving(finderImpl, this); 46 | } 47 | 48 | public HavingPath get(T obj) { 49 | Object arg = finderHandler.getPathInfo(); 50 | arg = arg == null ? obj : arg; 51 | HavingPath havingPath = new HavingPathImpl(finderHandler, finderImpl, this, arg); 52 | paths.add(havingPath); 53 | return havingPath; 54 | } 55 | 56 | public QueryAppender append(String queryString, Object... args) { 57 | QueryAppenderImpl queryAppenderImpl = new QueryAppenderImpl(finderImpl, queryString, args); 58 | paths.add(queryAppenderImpl); 59 | return queryAppenderImpl; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/HavingPathImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import com.jpaquery.core.facade.JpaQuery; 4 | import com.jpaquery.core.facade.Having; 5 | import com.jpaquery.core.facade.HavingFunctionPath; 6 | import com.jpaquery.core.facade.HavingPath; 7 | import com.jpaquery.core.facade.SelectPath.SelectPathType; 8 | import com.jpaquery.core.facade.WherePath.WherePathType; 9 | 10 | public class HavingPathImpl implements HavingFunctionPath { 11 | 12 | JpaQueryHandler finderHandler; 13 | JpaQueryImpl finderImpl; 14 | HavingImpl havingImpl; 15 | /** 16 | * 左参数 17 | */ 18 | Object left; 19 | /** 20 | * select选择子句 21 | */ 22 | SelectPathType selectPathType; 23 | /** 24 | * 父select 25 | */ 26 | HavingPathImpl parentHavingPathImpl; 27 | 28 | /** 29 | * 是否允许空参数 30 | */ 31 | boolean ifExist; 32 | /** 33 | * 路径类型 34 | */ 35 | WherePathType wherePathType; 36 | 37 | /** 38 | * 路径参数 39 | */ 40 | Object[] args; 41 | 42 | public JpaQueryHandler getFinderHandler() { 43 | return finderHandler; 44 | } 45 | 46 | public JpaQueryImpl getFinderImpl() { 47 | return finderImpl; 48 | } 49 | 50 | public HavingImpl getHavingImpl() { 51 | return havingImpl; 52 | } 53 | 54 | public Object getLeft() { 55 | return left; 56 | } 57 | 58 | public SelectPathType getSelectPathType() { 59 | return selectPathType; 60 | } 61 | 62 | public HavingPathImpl getParentHavingPathImpl() { 63 | return parentHavingPathImpl; 64 | } 65 | 66 | public boolean isIfExist() { 67 | return ifExist; 68 | } 69 | 70 | public WherePathType getWherePathType() { 71 | return wherePathType; 72 | } 73 | 74 | public Object[] getArgs() { 75 | return args; 76 | } 77 | 78 | public HavingPathImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl, 79 | HavingImpl havingImpl, Object left) { 80 | super(); 81 | this.finderHandler = finderHandler; 82 | this.finderImpl = finderImpl; 83 | this.havingImpl = havingImpl; 84 | this.left = left; 85 | } 86 | 87 | public HavingPath distinct() { 88 | return toHavingPath(SelectPathType.distinct); 89 | } 90 | 91 | public HavingFunctionPath count() { 92 | HavingPathImpl parentHavingPathImpl = new HavingPathImpl( 93 | finderHandler, finderImpl, havingImpl, this); 94 | this.parentHavingPathImpl = parentHavingPathImpl; 95 | parentHavingPathImpl.selectPathType = SelectPathType.count; 96 | return parentHavingPathImpl; 97 | } 98 | 99 | public HavingFunctionPath avg() { 100 | return toHavingPath(SelectPathType.avg); 101 | } 102 | 103 | public HavingFunctionPath sum() { 104 | return toHavingPath(SelectPathType.sum); 105 | } 106 | 107 | public HavingFunctionPath min() { 108 | return toHavingPath(SelectPathType.min); 109 | } 110 | 111 | public HavingFunctionPath max() { 112 | return toHavingPath(SelectPathType.max); 113 | } 114 | 115 | private HavingFunctionPath toHavingPath(SelectPathType selectPathType) { 116 | HavingPathImpl parentHavingPathImpl = new HavingPathImpl( 117 | finderHandler, finderImpl, havingImpl, this); 118 | this.parentHavingPathImpl = parentHavingPathImpl; 119 | parentHavingPathImpl.selectPathType = selectPathType; 120 | return parentHavingPathImpl; 121 | } 122 | 123 | Having fillPath(WherePathType wherePathType, boolean ifExist, 124 | Object... args) { 125 | this.args = args; 126 | this.wherePathType = wherePathType; 127 | this.ifExist = ifExist; 128 | return havingImpl; 129 | } 130 | 131 | public Having equal(T obj) { 132 | Object arg = finderHandler.getPathInfo(); 133 | arg = arg == null ? obj : arg; 134 | return fillPath(WherePathType.equal, false, arg); 135 | } 136 | 137 | public Having notEqual(T obj) { 138 | Object arg = finderHandler.getPathInfo(); 139 | arg = arg == null ? obj : arg; 140 | return fillPath(WherePathType.notEqual, false, arg); 141 | } 142 | 143 | public Having greatThan(T obj) { 144 | Object arg = finderHandler.getPathInfo(); 145 | arg = arg == null ? obj : arg; 146 | return fillPath(WherePathType.greatThan, false, arg); 147 | } 148 | 149 | public Having greatEqual(T obj) { 150 | Object arg = finderHandler.getPathInfo(); 151 | arg = arg == null ? obj : arg; 152 | return fillPath(WherePathType.greatEqual, false, arg); 153 | } 154 | 155 | public Having lessThan(T obj) { 156 | Object arg = finderHandler.getPathInfo(); 157 | arg = arg == null ? obj : arg; 158 | return fillPath(WherePathType.lessThan, false, arg); 159 | } 160 | 161 | public Having lessEqual(T obj) { 162 | Object arg = finderHandler.getPathInfo(); 163 | arg = arg == null ? obj : arg; 164 | return fillPath(WherePathType.lessEqual, false, arg); 165 | } 166 | 167 | public Having equal(JpaQuery subFinder) { 168 | return fillPath(WherePathType.equal, false, subFinder); 169 | } 170 | 171 | public Having notEqual(JpaQuery subFinder) { 172 | return fillPath(WherePathType.notEqual, false, subFinder); 173 | } 174 | 175 | public Having greatThan(JpaQuery subFinder) { 176 | return fillPath(WherePathType.greatThan, false, subFinder); 177 | } 178 | 179 | public Having greatEqual(JpaQuery subFinder) { 180 | return fillPath(WherePathType.greatEqual, false, subFinder); 181 | } 182 | 183 | public Having lessThan(JpaQuery subFinder) { 184 | return fillPath(WherePathType.lessThan, false, subFinder); 185 | } 186 | 187 | public Having lessEqual(JpaQuery subFinder) { 188 | return fillPath(WherePathType.lessEqual, false, subFinder); 189 | } 190 | 191 | public Having equalIfExist(T obj) { 192 | return fillPath(WherePathType.equal, true, obj); 193 | } 194 | 195 | public Having notEqualIfExist(T obj) { 196 | return fillPath(WherePathType.notEqual, true, obj); 197 | } 198 | 199 | public Having greatThanIfExist(T obj) { 200 | return fillPath(WherePathType.greatThan, true, obj); 201 | } 202 | 203 | public Having greatEqualIfExist(T obj) { 204 | return fillPath(WherePathType.greatEqual, true, obj); 205 | } 206 | 207 | public Having lessThanIfExist(T obj) { 208 | return fillPath(WherePathType.lessThan, true, obj); 209 | } 210 | 211 | public Having lessEqualIfExist(T obj) { 212 | return fillPath(WherePathType.lessEqual, true, obj); 213 | } 214 | 215 | public boolean equals(Object obj) { 216 | throw new UnsupportedOperationException( 217 | "The equals method is not supported, maybe you should use equal method"); 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/JoinImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import java.lang.reflect.Array; 4 | import java.lang.reflect.Method; 5 | import java.util.Collection; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import com.jpaquery.core.facade.Join; 13 | import com.jpaquery.core.facade.JoinPath; 14 | import com.jpaquery.core.vo.EntityInfo; 15 | import com.jpaquery.core.vo.FromInfo; 16 | import com.jpaquery.core.vo.PathInfo; 17 | import com.jpaquery.util._Helper; 18 | 19 | public class JoinImpl implements Join { 20 | 21 | static Logger log = LoggerFactory.getLogger(JoinImpl.class); 22 | 23 | JpaQueryHandler finderHandler; 24 | JpaQueryImpl finderImpl; 25 | 26 | Map> joinPathMap = new HashMap<>(); 27 | 28 | public JpaQueryHandler getFinderHandler() { 29 | return finderHandler; 30 | } 31 | 32 | public JpaQueryImpl getFinderImpl() { 33 | return finderImpl; 34 | } 35 | 36 | public Map> getJoinPathMap() { 37 | return joinPathMap; 38 | } 39 | 40 | public JoinImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl) { 41 | super(); 42 | this.finderHandler = finderHandler; 43 | this.finderImpl = finderImpl; 44 | } 45 | 46 | @SuppressWarnings("unchecked") 47 | public JoinPath get(T[] array) { 48 | T proxy = (T) Array.get(array, 0); 49 | return getJoinPath(proxy); 50 | } 51 | 52 | public JoinPath get(Collection list) { 53 | T proxy = list.iterator().next(); 54 | return getJoinPath(proxy); 55 | } 56 | 57 | public JoinPath get(T obj) { 58 | return getJoinPath(obj); 59 | } 60 | 61 | private JoinPath getJoinPath(T proxy) { 62 | PathInfo pathInfo = finderHandler.getPathInfo(); 63 | Class componentType = getComponentTypeByGetter(pathInfo.getGetter()); 64 | if (!joinPathMap.containsKey(_Helper.identityHashCode(proxy))) { 65 | // 为了性能最大化,尽量使用原有的代理对象,如果原代理对象已经被使用,则重新生成代理对象 66 | proxy = finderHandler.proxy(null, componentType); 67 | } 68 | 69 | EntityInfo entityInfo = new EntityInfo(finderHandler, componentType, proxy); 70 | JoinPathImpl joinPath = new JoinPathImpl(finderHandler, finderImpl, this, entityInfo, pathInfo); 71 | FromInfo fromInfo = finderImpl.getCurrentFromInfos().get(pathInfo.getRootKey()); 72 | if (fromInfo != null) { 73 | fromInfo.getJoinPaths().add(joinPath); 74 | joinPath.setFromInfo(fromInfo); 75 | joinPath.getWhereImpl().getEntityInfoMap().put(entityInfo.getKey(), entityInfo); 76 | } else { 77 | JoinPathImpl preJoinPath = joinPathMap.get(pathInfo.getRootKey()); 78 | if (preJoinPath != null) { 79 | preJoinPath.getFromInfo().getJoinPaths().add(joinPath); 80 | joinPath.getWhereImpl().getEntityInfoMap().putAll(preJoinPath.getWhereImpl().getEntityInfoMap()); 81 | joinPath.setFromInfo(preJoinPath.getFromInfo()); 82 | } 83 | } 84 | joinPath.getWhereImpl().getEntityInfoMap().put(entityInfo.getKey(), entityInfo); 85 | joinPathMap.put(entityInfo.getKey(), joinPath); 86 | finderImpl.getSelectImpl().getEntityInfoMap().put(entityInfo.getKey(), entityInfo); 87 | return joinPath; 88 | } 89 | 90 | @SuppressWarnings("unchecked") 91 | private Class getComponentTypeByGetter(Method getter) { 92 | if (getter.getReturnType().isArray()) { 93 | return (Class) getter.getReturnType().getComponentType(); 94 | } 95 | if (Collection.class.isAssignableFrom(getter.getReturnType())) { 96 | return (Class) _Helper.getGenricReturnType(getter, 0); 97 | } 98 | return (Class) getter.getReturnType(); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/JoinPathImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import com.jpaquery.core.facade.JoinHandler; 4 | import com.jpaquery.core.facade.JoinPath; 5 | import com.jpaquery.core.facade.Where; 6 | import com.jpaquery.core.facade.Where.WhereType; 7 | import com.jpaquery.core.vo.EntityInfo; 8 | import com.jpaquery.core.vo.FromInfo; 9 | import com.jpaquery.core.vo.PathInfo; 10 | import com.jpaquery.util._Helper; 11 | import com.jpaquery.util._MergeMap; 12 | 13 | import java.util.LinkedList; 14 | 15 | public class JoinPathImpl implements JoinPath { 16 | 17 | JpaQueryHandler finderHandler; 18 | JpaQueryImpl finderImpl; 19 | FromInfo fromInfo; 20 | JoinImpl joinImpl; 21 | EntityInfo entityInfo; 22 | PathInfo pathInfo; 23 | JoinPathType joinPathType = JoinPathType.inner; 24 | WhereImpl whereImpl; 25 | 26 | public JpaQueryHandler getFinderHandler() { 27 | return finderHandler; 28 | } 29 | 30 | public JpaQueryImpl getFinderImpl() { 31 | return finderImpl; 32 | } 33 | 34 | public FromInfo getFromInfo() { 35 | return fromInfo; 36 | } 37 | 38 | public void setFromInfo(FromInfo fromInfo) { 39 | this.fromInfo = fromInfo; 40 | } 41 | 42 | public JoinImpl getJoinImpl() { 43 | return joinImpl; 44 | } 45 | 46 | public EntityInfo getEntityInfo() { 47 | return entityInfo; 48 | } 49 | 50 | public PathInfo getPathInfo() { 51 | return pathInfo; 52 | } 53 | 54 | public JoinPathType getJoinPathType() { 55 | return joinPathType; 56 | } 57 | 58 | public WhereImpl getWhereImpl() { 59 | return whereImpl; 60 | } 61 | 62 | public JoinPathImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl, JoinImpl joinImpl, 63 | EntityInfo entityInfo, PathInfo pathInfo) { 64 | super(); 65 | this.finderHandler = finderHandler; 66 | this.finderImpl = finderImpl; 67 | this.joinImpl = joinImpl; 68 | this.entityInfo = entityInfo; 69 | this.pathInfo = pathInfo; 70 | this.whereImpl = new WhereImpl(finderHandler, finderImpl, WhereType.and, new _MergeMap>()); 71 | } 72 | 73 | private void handleJoin(JoinHandler joinHandler) { 74 | T model = entityInfo.getProxy(); 75 | JoinPathImpl joinPathImpl = joinImpl.getJoinPathMap().get(_Helper.identityHashCode(model)); 76 | LinkedList ons = finderImpl.joinOnHolder.get(); 77 | if (ons == null) { 78 | ons = new LinkedList(); 79 | finderImpl.joinOnHolder.set(ons); 80 | } 81 | try { 82 | ons.addFirst(joinPathImpl.getWhereImpl()); 83 | joinHandler.handle(model); 84 | } finally { 85 | ons.removeFirst(); 86 | } 87 | } 88 | 89 | public void inner(JoinHandler joinHandler) { 90 | this.joinPathType = JoinPathType.inner; 91 | handleJoin((JoinHandler) joinHandler); 92 | } 93 | 94 | public void left(JoinHandler joinHandler) { 95 | this.joinPathType = JoinPathType.left; 96 | handleJoin(joinHandler); 97 | } 98 | 99 | public void right(JoinHandler joinHandler) { 100 | this.joinPathType = JoinPathType.right; 101 | handleJoin(joinHandler); 102 | } 103 | 104 | public void full(JoinHandler joinHandler) { 105 | this.joinPathType = JoinPathType.full; 106 | handleJoin(joinHandler); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/JpaQueryHandler.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import java.lang.reflect.Array; 4 | import java.lang.reflect.InvocationHandler; 5 | import java.lang.reflect.Method; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | import org.apache.commons.lang3.StringUtils; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import com.jpaquery.core.vo.PathInfo; 17 | import com.jpaquery.util._Helper; 18 | import com.jpaquery.util._Proxys; 19 | 20 | /** 21 | * finder处理和工具类 22 | * 23 | * @author lujijiang 24 | * 25 | */ 26 | public class JpaQueryHandler { 27 | 28 | /** 29 | * 日志器 30 | */ 31 | private static Logger log = LoggerFactory.getLogger(JpaQueryHandler.class); 32 | 33 | /** 34 | * 路径构建线程保持对象 35 | */ 36 | private ThreadLocal pathInfoLocal = new ThreadLocal(); 37 | 38 | /** 39 | * 实习序号池 40 | */ 41 | private Map, Integer> entityIndexPool = new ConcurrentHashMap, Integer>(); 42 | 43 | /** 44 | * 代理类型 45 | * 46 | * @param rootProxy 47 | * 根代理对象 48 | * @param type 49 | * 代理类型 50 | * @return 51 | */ 52 | T proxy(final Object rootProxy, final Class type) { 53 | if (_Helper.isBaseType(type)) { 54 | return null; 55 | } 56 | 57 | return _Proxys.newProxyInstance(new InvocationHandler() { 58 | /** 59 | * 缓存代理对象 60 | */ 61 | Map cacheProxyMap = new ConcurrentHashMap(); 62 | 63 | public Object invoke(Object proxy, Method method, Object[] args) throws Exception { 64 | String propertyName = getterMethodPropertyName(method); 65 | 66 | if (propertyName == null) { 67 | return new UnsupportedOperationException( 68 | String.format("The method %s of object %s@%d is unsupported", method.getName(), 69 | proxy.getClass().getCanonicalName(), System.identityHashCode(proxy))); 70 | } 71 | 72 | setPathInfo(rootProxy, proxy, propertyName, method); 73 | 74 | Class returnType = method.getReturnType(); 75 | // Map类型不做代理 76 | if (Map.class.isAssignableFrom(returnType)) { 77 | return null; 78 | } 79 | 80 | // 是数组,则初始化一个长度为1的数组 81 | if (returnType.isArray()) { 82 | Class componentType = returnType.getComponentType(); 83 | Object array = Array.newInstance(componentType, 1); 84 | Object subProxy = subProxy(rootProxy, proxy, propertyName, componentType); 85 | Array.set(array, 0, subProxy); 86 | return array; 87 | } 88 | // 是List集合,则初始化指定类型的集合,并且调用集合的get方法返回的都将是固定的对象 89 | if (List.class.isAssignableFrom(returnType)) { 90 | Class componentType = _Helper.getGenricReturnType(method, 0); 91 | final Object subProxy = subProxy(rootProxy, proxy, propertyName, componentType); 92 | return _Proxys.newProxyInstance(new InvocationHandler() { 93 | public Object invoke(Object proxy, Method method, Object[] args) throws Exception { 94 | if ("get".equals(method.getName())) { 95 | if (method.getParameterTypes().length == 1 96 | && int.class.equals(method.getParameterTypes()[0])) { 97 | return subProxy; 98 | } 99 | } 100 | if ("iterator".equals(method.getName())) { 101 | if (method.getParameterTypes().length == 0) { 102 | return new Iterator() { 103 | 104 | int size = 1; 105 | 106 | public boolean hasNext() { 107 | return size-- > 0; 108 | } 109 | 110 | public Object next() { 111 | return subProxy; 112 | } 113 | 114 | public void remove() { 115 | throw new UnsupportedOperationException(); 116 | } 117 | }; 118 | } 119 | } 120 | return new UnsupportedOperationException( 121 | String.format("The method %s of object %s@%d is unsupported", method.getName(), 122 | proxy.getClass().getCanonicalName(), System.identityHashCode(proxy))); 123 | } 124 | }, returnType); 125 | } 126 | 127 | // Set类型 128 | if (Set.class.isAssignableFrom(returnType)) { 129 | Class componentType = _Helper.getGenricReturnType(method, 0); 130 | final Object subProxy = subProxy(rootProxy, proxy, propertyName, componentType); 131 | return _Proxys.newProxyInstance(new InvocationHandler() { 132 | public Object invoke(Object proxy, Method method, Object[] args) throws Exception { 133 | if ("iterator".equals(method.getName())) { 134 | if (method.getParameterTypes().length == 0) { 135 | return new Iterator() { 136 | 137 | int size = 1; 138 | 139 | public boolean hasNext() { 140 | return size-- > 0; 141 | } 142 | 143 | public Object next() { 144 | return subProxy; 145 | } 146 | 147 | public void remove() { 148 | throw new UnsupportedOperationException(); 149 | } 150 | }; 151 | } 152 | } 153 | return new UnsupportedOperationException( 154 | String.format("The method %s of object %s@%d is unsupported", method.getName(), 155 | proxy.getClass().getCanonicalName(), System.identityHashCode(proxy))); 156 | } 157 | }, returnType); 158 | } 159 | 160 | return subProxy(rootProxy, proxy, propertyName, returnType); 161 | } 162 | 163 | private Object subProxy(final Object rootProxy, Object proxy, String propertyName, Class componentType) { 164 | if (_Helper.isBaseType(componentType)) { 165 | return null; 166 | } 167 | Object subProxy = cacheProxyMap.get(propertyName); 168 | if (subProxy == null) { 169 | subProxy = proxy(rootProxy == null ? proxy : rootProxy, componentType); 170 | cacheProxyMap.put(propertyName, subProxy); 171 | } 172 | return subProxy; 173 | } 174 | }, type); 175 | } 176 | 177 | /** 178 | * 注册路径信息 179 | * 180 | * @param rootProxy 181 | * @param proxy 182 | * @param propertyName 183 | */ 184 | private void setPathInfo(Object rootProxy, Object proxy, String propertyName, Method getter) { 185 | 186 | PathInfo pathInfo = pathInfoLocal.get(); 187 | if (pathInfo != null) { 188 | if (rootProxy == null) { 189 | // 如果没有根对象,说明调用了某个代理对象的第一层getter方法,重置pathInfo 190 | pathInfo = null; 191 | } else if (proxy == pathInfo.getRootProxy()) { 192 | // 如果根代理对象和当前代理对象一致,说明根对象的getter调用未被清除,重置pathInfo 193 | pathInfo = null; 194 | } else if (System.identityHashCode(rootProxy) != System.identityHashCode(pathInfo.getRootProxy())) { 195 | // 如果当前pathInfo中的根对象和传入的根对象不一致,说明调用了不同的代理对象的getter方法,重置pathInfo 196 | pathInfo = null; 197 | } 198 | } 199 | 200 | if (pathInfo == null) { 201 | pathInfo = new PathInfo(proxy, proxy, new StringBuilder().append(propertyName), getter); 202 | } else { 203 | pathInfo.setCurrentProxy(proxy); 204 | pathInfo.setGetter(getter); 205 | pathInfo.getPathBuilder().append('.'); 206 | pathInfo.getPathBuilder().append(propertyName); 207 | } 208 | pathInfoLocal.set(pathInfo); 209 | } 210 | 211 | /** 212 | * 根据getter方法获取属性名,如果这是一个属性,则返回属性名,否则返回false 213 | * 214 | * @param method 215 | * @return 216 | */ 217 | private String getterMethodPropertyName(Method method) { 218 | 219 | Class returnType = method.getReturnType(); 220 | 221 | if (returnType == null || Void.TYPE.equals(returnType) || Void.class.equals(returnType)) { 222 | return null; 223 | } 224 | 225 | if (method.getParameterTypes().length != 0) { 226 | return null; 227 | } 228 | 229 | String methodName = method.getName(); 230 | 231 | if (Boolean.TYPE.equals(returnType) || Boolean.class.equals(returnType)) { 232 | if (methodName.startsWith("is") && methodName.length() > 2 && Character.isUpperCase(methodName.charAt(2))) { 233 | return StringUtils.uncapitalize(methodName.substring(2)); 234 | } 235 | } 236 | 237 | if (methodName.startsWith("get") && methodName.length() > 3 && Character.isUpperCase(methodName.charAt(3))) { 238 | return StringUtils.uncapitalize(methodName.substring(3)); 239 | } 240 | 241 | return null; 242 | } 243 | 244 | /** 245 | * 获取路径信息 246 | * 247 | * @return 248 | */ 249 | PathInfo getPathInfo() { 250 | PathInfo pathInfo = pathInfoLocal.get(); 251 | if (pathInfo == null) { 252 | return null; 253 | } 254 | pathInfoLocal.remove(); 255 | return pathInfo; 256 | } 257 | 258 | /** 259 | * 获取实体序号,注意每生成一次序号自增 260 | * 261 | * @param type 262 | * @return 263 | */ 264 | public int generateEntityIndex(Class type) { 265 | Integer index = entityIndexPool.get(type); 266 | if (index == null) { 267 | index = 0; 268 | } 269 | entityIndexPool.put(type, index + 1); 270 | return index; 271 | } 272 | 273 | private int paramIndex = 0; 274 | 275 | public void resetParamIndex() { 276 | paramIndex = 0; 277 | } 278 | 279 | public String generateParamName() { 280 | return "p_".concat(String.valueOf(++paramIndex)); 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/JpaQueryImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.sql.Timestamp; 6 | import java.util.*; 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | import javax.persistence.EntityManager; 11 | import javax.persistence.FlushModeType; 12 | import javax.persistence.NoResultException; 13 | import javax.persistence.Query; 14 | 15 | import com.jpaquery.core.QueryHandler; 16 | import com.jpaquery.core.SubQueryHandler; 17 | import org.hibernate.Session; 18 | import org.hibernate.engine.spi.SessionFactoryImplementor; 19 | import org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory; 20 | import org.hibernate.hql.spi.QueryTranslator; 21 | import org.hibernate.hql.spi.QueryTranslatorFactory; 22 | import org.hibernate.query.NativeQuery; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | import org.springframework.data.domain.Page; 26 | import org.springframework.data.domain.PageImpl; 27 | import org.springframework.data.domain.Pageable; 28 | import org.springframework.data.domain.Sort; 29 | 30 | import com.jpaquery.core.Querys; 31 | import com.jpaquery.core.facade.Group; 32 | import com.jpaquery.core.facade.GroupPath; 33 | import com.jpaquery.core.facade.Having; 34 | import com.jpaquery.core.facade.HavingPath; 35 | import com.jpaquery.core.facade.Join; 36 | import com.jpaquery.core.facade.JoinPath; 37 | import com.jpaquery.core.facade.JpaQuery; 38 | import com.jpaquery.core.facade.JpaQueryEach; 39 | import com.jpaquery.core.facade.Order; 40 | import com.jpaquery.core.facade.OrderPath; 41 | import com.jpaquery.core.facade.Select; 42 | import com.jpaquery.core.facade.SelectPath; 43 | import com.jpaquery.core.facade.SubJpaQuery; 44 | import com.jpaquery.core.facade.SubJpaQuery.SubJpaQueryType; 45 | import com.jpaquery.core.facade.Where; 46 | import com.jpaquery.core.facade.WherePath; 47 | import com.jpaquery.core.render.JpaQueryRender; 48 | import com.jpaquery.core.vo.EntityInfo; 49 | import com.jpaquery.core.vo.FromInfo; 50 | import com.jpaquery.core.vo.PathInfo; 51 | import com.jpaquery.core.vo.QueryContent; 52 | import com.jpaquery.util._Helper; 53 | import com.jpaquery.util._MergeMap; 54 | import com.jpaquery.util._Proxys; 55 | import org.springframework.transaction.support.TransactionSynchronizationManager; 56 | 57 | /** 58 | * Finder实现类 59 | * 60 | * @author lujijiang 61 | * 62 | */ 63 | public class JpaQueryImpl implements JpaQuery { 64 | 65 | private static final Logger logger = LoggerFactory.getLogger(JpaQueryImpl.class); 66 | /** 67 | * each遍历时每次查询的数量 68 | */ 69 | private static final int EACH_SIZE = 1024; 70 | /** 71 | * 子查询 72 | */ 73 | List subFinderImpls = new ArrayList<>(); 74 | /** 75 | * finder处理器 76 | */ 77 | JpaQueryHandler finderHandler; 78 | /** 79 | * 父finder实体信息 80 | */ 81 | Map parentFromInfos = new _MergeMap<>(); 82 | /** 83 | * finder实体信息 84 | */ 85 | Map currentFromInfos = new _MergeMap<>(); 86 | /** 87 | * 默认finder渲染器 88 | */ 89 | JpaQueryRender finderRender; 90 | 91 | /** 92 | * select子句 93 | */ 94 | SelectImpl selectImpl; 95 | 96 | /** 97 | * finder主where字句 98 | */ 99 | WhereImpl whereImpl; 100 | 101 | /** 102 | * order子句 103 | */ 104 | OrderImpl orderImpl; 105 | /** 106 | * group子句 107 | */ 108 | GroupImpl groupImpl; 109 | /** 110 | * having子句 111 | */ 112 | HavingImpl havingImpl; 113 | /** 114 | * join子句 115 | */ 116 | JoinImpl joinImpl; 117 | /** 118 | * 父finder对象 119 | */ 120 | private JpaQueryImpl parentFinder; 121 | 122 | public List getSubFinderImpls() { 123 | return subFinderImpls; 124 | } 125 | 126 | public JpaQueryHandler getFinderHandler() { 127 | return finderHandler; 128 | } 129 | 130 | public Map getParentFromInfos() { 131 | return parentFromInfos; 132 | } 133 | 134 | public Map getCurrentFromInfos() { 135 | return currentFromInfos; 136 | } 137 | 138 | public JpaQueryRender getFinderRender() { 139 | return finderRender; 140 | } 141 | 142 | public SelectImpl getSelectImpl() { 143 | return selectImpl; 144 | } 145 | 146 | public WhereImpl getWhereImpl() { 147 | return whereImpl; 148 | } 149 | 150 | public OrderImpl getOrderImpl() { 151 | return orderImpl; 152 | } 153 | 154 | public GroupImpl getGroupImpl() { 155 | return groupImpl; 156 | } 157 | 158 | public HavingImpl getHavingImpl() { 159 | return havingImpl; 160 | } 161 | 162 | public JoinImpl getJoinImpl() { 163 | return joinImpl; 164 | } 165 | 166 | public JpaQueryImpl(JpaQueryHandler finderHandler, JpaQueryRender finderRender) { 167 | this.finderHandler = finderHandler; 168 | this.finderRender = finderRender; 169 | // 初始化子句 170 | selectImpl = new SelectImpl(finderHandler, this, new _MergeMap>()); 171 | whereImpl = new WhereImpl(finderHandler, this, Where.WhereType.and, new _MergeMap>()); 172 | orderImpl = new OrderImpl(finderHandler, this); 173 | groupImpl = new GroupImpl(finderHandler, this); 174 | havingImpl = new HavingImpl(finderHandler, this); 175 | joinImpl = new JoinImpl(finderHandler, this); 176 | } 177 | 178 | @Override 179 | public void subQuery(SubQueryHandler subQueryHandler) { 180 | JpaQueryImpl subFinderImpl = new JpaQueryImpl(finderHandler, finderRender); 181 | subFinderImpl.parentFinder = this; 182 | subFinderImpl.getParentFromInfos().putAll(getCurrentFromInfos()); 183 | subFinderImpl.getParentFromInfos().putAll(getParentFromInfos()); 184 | subFinderImpls.add(subFinderImpl); 185 | subQueryHandler.handle(subFinderImpl); 186 | } 187 | 188 | public T from(Class type) { 189 | T proxy = finderHandler.proxy(null, type); 190 | EntityInfo entityInfo = new EntityInfo(finderHandler, type, proxy); 191 | FromInfo fromInfo = new FromInfo(entityInfo); 192 | getCurrentFromInfos().put(entityInfo.getKey(), fromInfo); 193 | return proxy; 194 | } 195 | 196 | protected ThreadLocal> joinOnHolder = new ThreadLocal>(); 197 | 198 | public Where where() { 199 | LinkedList ons = joinOnHolder.get(); 200 | if(ons!=null && !ons.isEmpty()){ 201 | return ons.getFirst(); 202 | } 203 | return whereImpl; 204 | } 205 | 206 | public WherePath where(T obj) { 207 | return where().get(obj); 208 | } 209 | 210 | public Select select() { 211 | return selectImpl; 212 | } 213 | 214 | public SelectPath select(T obj) { 215 | return select().get(obj); 216 | } 217 | 218 | public Order order() { 219 | return orderImpl; 220 | } 221 | 222 | public OrderPath order(Object obj) { 223 | return order().get(obj); 224 | } 225 | 226 | public Group group() { 227 | return groupImpl; 228 | } 229 | 230 | public GroupPath group(Object obj) { 231 | return group().get(obj); 232 | } 233 | 234 | public Having having() { 235 | return havingImpl; 236 | } 237 | 238 | public HavingPath having(T obj) { 239 | return having().get(obj); 240 | } 241 | 242 | public Join join() { 243 | return joinImpl; 244 | } 245 | 246 | public JoinPath join(Collection list) { 247 | return join().get(list); 248 | } 249 | 250 | public JoinPath join(T obj) { 251 | return join().get(obj); 252 | } 253 | 254 | /** 255 | * 生成QueryContent 256 | * 257 | * @param countSwich 258 | * 是否是统计查询 259 | * @return 260 | */ 261 | private QueryContent toQueryContent(boolean countSwich) { 262 | // 重置参数序号 263 | if (parentFinder == null) { 264 | finderHandler.resetParamIndex(); 265 | } 266 | QueryContent queryContent = new QueryContent(); 267 | // select 268 | QueryContent selectQueryContent = selectImpl.toQueryContent(); 269 | if (selectQueryContent != null) { 270 | queryContent.append("select "); 271 | queryContent.append(selectQueryContent); 272 | } 273 | 274 | // from 275 | QueryContent fromQueryContent = finderRender.toFrom(this); 276 | if (fromQueryContent != null) { 277 | if (queryContent.length() > 0) { 278 | queryContent.append(" "); 279 | } 280 | queryContent.append("from "); 281 | queryContent.append(fromQueryContent); 282 | } else { 283 | throw new IllegalStateException("Must be exist from statement query"); 284 | } 285 | 286 | // where 287 | QueryContent whereQueryContent = whereImpl.toQueryContent(); 288 | if (whereQueryContent != null) { 289 | queryContent.append(" where "); 290 | queryContent.append(whereQueryContent); 291 | } 292 | 293 | // group 294 | QueryContent groupQueryContent = groupImpl.toQueryContent(); 295 | if (groupQueryContent != null) { 296 | queryContent.append(" group by "); 297 | queryContent.append(groupQueryContent); 298 | } 299 | 300 | // having 301 | QueryContent havingQueryContent = havingImpl.toQueryContent(); 302 | if (havingQueryContent != null) { 303 | queryContent.append(" having "); 304 | queryContent.append(havingQueryContent); 305 | } 306 | 307 | // order 308 | if (!countSwich) { 309 | QueryContent orderQueryContent = orderImpl.toQueryContent(); 310 | if (orderQueryContent != null) { 311 | queryContent.append(" order by "); 312 | queryContent.append(orderQueryContent); 313 | } 314 | } 315 | 316 | return queryContent; 317 | } 318 | 319 | public QueryContent toQueryContent() { 320 | return toQueryContent(false); 321 | } 322 | 323 | public QueryContent toCountQueryContent() { 324 | return toQueryContent(true); 325 | } 326 | 327 | public SubJpaQuery any() { 328 | return new SubJpaQueryImpl(this, SubJpaQueryType.any); 329 | } 330 | 331 | public SubJpaQuery some() { 332 | return new SubJpaQueryImpl(this, SubJpaQueryType.some); 333 | } 334 | 335 | public SubJpaQuery all() { 336 | return new SubJpaQueryImpl(this, SubJpaQueryType.all); 337 | } 338 | 339 | public String alias(Object proxyInstance) { 340 | PathInfo pathInfo = finderHandler.getPathInfo(); 341 | if (pathInfo != null) { 342 | FromInfo fromInfo = getCurrentFromInfos().get(pathInfo.getRootKey()); 343 | if (fromInfo == null) { 344 | fromInfo = getParentFromInfos().get(pathInfo.getRootKey()); 345 | } 346 | if (fromInfo == null) { 347 | throw new IllegalArgumentException( 348 | String.format("The info path %s root proxy instance is not valid", pathInfo)); 349 | } 350 | return fromInfo.getEntityInfo().getAlias().concat(".").concat(pathInfo.getPathBuilder().toString()); 351 | } 352 | if (proxyInstance == null) { 353 | throw new IllegalArgumentException(String.format("The proxy instance should't be null")); 354 | } 355 | if (proxyInstance instanceof JpaQuery) { 356 | return ((JpaQuery) proxyInstance).toQueryContent().getQueryString(); 357 | } 358 | 359 | long key = _Helper.identityHashCode(proxyInstance); 360 | 361 | FromInfo fromInfo = getCurrentFromInfos().get(key); 362 | if (fromInfo == null) { 363 | fromInfo = getParentFromInfos().get(key); 364 | } 365 | 366 | if (fromInfo != null) { 367 | return fromInfo.getEntityInfo().getAlias(); 368 | } 369 | 370 | JoinPathImpl joinPath = this.joinImpl.getJoinPathMap().get(key); 371 | if(joinPath!=null){ 372 | return joinPath.getEntityInfo().getAlias(); 373 | } 374 | 375 | throw new IllegalStateException(String.format( 376 | "Should be call a model getter method or argument is model object in this finder or sub finder object")); 377 | } 378 | 379 | // 特设附加方法 380 | /** 381 | * 获取所有From对象 382 | * 383 | * @return 384 | */ 385 | public Collection froms() { 386 | return getCurrentFromInfos().values(); 387 | } 388 | 389 | /** 390 | * 根据查询内容创建查询对象 391 | * 392 | * @param em 393 | * @param queryContent 394 | * @return 395 | */ 396 | private Query createQuery(EntityManager em, QueryContent queryContent) { 397 | if (logger.isDebugEnabled()) { 398 | String caller = _Helper.findCaller(); 399 | logger.debug("JPQL({}):{}", caller, queryContent); 400 | } 401 | Query query = em.createQuery(queryContent.getQueryString()); 402 | if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { 403 | query.setFlushMode(FlushModeType.COMMIT); 404 | } 405 | for (String name : queryContent.getArguments().keySet()) { 406 | Object arg = queryContent.getArguments().get(name); 407 | if (arg != null && arg instanceof Date) { 408 | Timestamp value = new Timestamp(((Date) arg).getTime()); 409 | query.setParameter(name, value); 410 | continue; 411 | } 412 | query.setParameter(name, arg); 413 | } 414 | return query; 415 | } 416 | 417 | private Query createQuery(EntityManager em, JpaQuery finder, boolean cacheable) { 418 | QueryContent queryContent = finder.toQueryContent(); 419 | Query query = createQuery(em, queryContent); 420 | cacheable(query, cacheable); 421 | return query; 422 | } 423 | 424 | private Query createQuery(EntityManager em, boolean cacheable) { 425 | return createQuery(em, this, cacheable); 426 | } 427 | 428 | /** 429 | * 生成统计专用的查询对象 430 | * 431 | * @param em 432 | * @return 433 | */ 434 | private Query createCountQuery(EntityManager em) { 435 | QueryContent queryContent = toCountQueryContent(); 436 | String hql = queryContent.getQueryString(); 437 | List argList = new ArrayList<>(); 438 | Pattern pattern = Pattern.compile(":[a-zA-Z0-9_]+"); 439 | Matcher matcher = pattern.matcher(hql); 440 | while (matcher.find()) { 441 | String group = matcher.group(); 442 | String name = group.substring(1); 443 | argList.add(queryContent.getArguments().get(name)); 444 | } 445 | Session session = em.unwrap(Session.class); 446 | QueryTranslatorFactory translatorFactory = new ASTQueryTranslatorFactory(); 447 | SessionFactoryImplementor factory = (SessionFactoryImplementor) session.getSessionFactory(); 448 | QueryTranslator translator = translatorFactory.createQueryTranslator(hql, hql, Collections.EMPTY_MAP, factory, 449 | null); 450 | translator.compile(Collections.EMPTY_MAP, false); 451 | String sql = translator.getSQLString(); 452 | sql = "SELECT COUNT(1) FROM (" + sql + ") TMP"; 453 | { 454 | Pattern questionMaskPattern = Pattern.compile("\\?"); 455 | StringBuffer stringBuffer = new StringBuffer(); 456 | Matcher questionMaskMatcher = questionMaskPattern.matcher(sql); 457 | int i = 0; 458 | while (questionMaskMatcher.find()) { 459 | questionMaskMatcher.appendReplacement(stringBuffer, ":p" + i); 460 | i++; 461 | } 462 | questionMaskMatcher.appendTail(stringBuffer); 463 | sql = stringBuffer.toString(); 464 | } 465 | NativeQuery query = session.createNativeQuery(sql); 466 | for (int i = 0; i < argList.size(); i++) { 467 | Object arg = argList.get(i); 468 | if (arg != null) { 469 | if (arg.getClass().isEnum()) { 470 | arg = ((Enum) arg).name(); 471 | } 472 | } 473 | if (arg != null && arg instanceof Collection) { 474 | Collection argCollection = (Collection) arg; 475 | List list = new ArrayList<>(); 476 | for (Object obj : argCollection) { 477 | if (obj != null && obj.getClass().isEnum()) { 478 | obj = ((Enum) obj).name(); 479 | } 480 | list.add(obj); 481 | } 482 | query.setParameterList("p" + i, list); 483 | } else { 484 | query.setParameter("p" + i, arg); 485 | } 486 | 487 | } 488 | return query; 489 | } 490 | 491 | @Override 492 | public Object one(EntityManager em) { 493 | return one(em, false); 494 | } 495 | 496 | @Override 497 | public Object one(EntityManager em, boolean cacheable) { 498 | Query query = createQuery(em, cacheable); 499 | try { 500 | return query.getSingleResult(); 501 | } catch (NoResultException e) { 502 | return null; 503 | } 504 | } 505 | 506 | @Override 507 | public List list(EntityManager em) { 508 | return list(em, false); 509 | } 510 | 511 | @Override 512 | public List list(EntityManager em, boolean cacheable) { 513 | Query query = createQuery(em, cacheable); 514 | return query.getResultList(); 515 | } 516 | 517 | private void cacheable(Query query, boolean cacheable) { 518 | query.setHint("org.hibernate.cacheable", cacheable); 519 | } 520 | 521 | @Override 522 | public List list(EntityManager em, int start, int max) { 523 | return list(em, start, max, false); 524 | } 525 | 526 | @Override 527 | public List list(EntityManager em, int start, int max, boolean cacheable) { 528 | Query query = createQuery(em, cacheable); 529 | query.setFirstResult(start); 530 | query.setMaxResults(max); 531 | return query.getResultList(); 532 | } 533 | 534 | @Override 535 | public List top(EntityManager em, int top) { 536 | return top(em, top, false); 537 | } 538 | 539 | @Override 540 | public List top(EntityManager em, int top, boolean cacheable) { 541 | return list(em, 0, top, cacheable); 542 | } 543 | 544 | @Override 545 | public Page page(EntityManager em, Pageable pageable) { 546 | return page(em, pageable, false); 547 | } 548 | 549 | @SuppressWarnings({ "rawtypes", "unchecked" }) 550 | @Override 551 | public Page page(EntityManager em, Pageable pageable, boolean cacheable) { 552 | JpaQuery finder = this.copy(); 553 | List content = createQuery(em, appendSortToFinder(finder, pageable.getSort()), cacheable) 554 | .setFirstResult((int)pageable.getOffset()).setMaxResults(pageable.getPageSize()).getResultList(); 555 | final long total = content.size() == pageable.getPageSize() ? -1 : pageable.getOffset() + content.size(); 556 | final PageImpl page = new PageImpl(content, pageable, total); 557 | return _Proxys.newProxyInstance(new InvocationHandler() { 558 | private long totalElements = total; 559 | 560 | @Override 561 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 562 | Page _this = (Page) proxy; 563 | if ("getTotalElements".equals(method.getName())) { 564 | fixTotal(em); 565 | return totalElements; 566 | } 567 | if ("getTotalPages".equals(method.getName())) { 568 | return _this.getSize() == 0 ? 1 569 | : (int) Math.ceil((double) _this.getTotalElements() / (double) _this.getSize()); 570 | } 571 | if ("hasNext".equals(method.getName())) { 572 | return _this.getNumber() + 1 < _this.getTotalPages(); 573 | } 574 | if ("isLast".equals(method.getName())) { 575 | return !_this.hasNext(); 576 | } 577 | if ("nextPageable".equals(method.getName())) { 578 | return _this.hasNext() ? pageable.next() : null; 579 | } 580 | return method.invoke(page, args); 581 | } 582 | 583 | public void fixTotal(EntityManager em) { 584 | if (totalElements == -1) { 585 | totalElements = count(em); 586 | } 587 | } 588 | }, Page.class); 589 | } 590 | 591 | /** 592 | * 将排序信息追加到Finder中,注意Finder将会被改变 593 | * 594 | * @param finder 595 | * @param sort 596 | */ 597 | private JpaQuery appendSortToFinder(JpaQuery finder, Sort sort) { 598 | if (sort == null) { 599 | return finder; 600 | } 601 | JpaQueryImpl finderImpl = (JpaQueryImpl) finder; 602 | if (finderImpl.getSelectImpl().getSelectPaths().size() == 1) { 603 | Object selectPath = finderImpl.getSelectImpl().getSelectPaths().get(0); 604 | if (selectPath != null && selectPath instanceof SelectPathImpl) { 605 | SelectPathImpl selectPathImpl = (SelectPathImpl) selectPath; 606 | Object arg = selectPathImpl.getArg(); 607 | if (arg != null && !(arg instanceof JpaQuery)) { 608 | try { 609 | String alias = finderImpl.alias(arg); 610 | for (Sort.Order order : sort) { 611 | finder.order().append(alias.concat(".").concat(order.getProperty()).concat(" ") 612 | .concat(order.getDirection().name().toLowerCase())); 613 | } 614 | return finder; 615 | } catch (IllegalStateException e) { 616 | 617 | } 618 | } 619 | } 620 | } 621 | for (Sort.Order order : sort) { 622 | finder.order().append(order.getProperty().concat(" ").concat(order.getDirection().name().toLowerCase())); 623 | } 624 | return finder; 625 | } 626 | 627 | public long count(EntityManager em) { 628 | Query query = createCountQuery(em); 629 | return ((Number) query.getSingleResult()).longValue(); 630 | } 631 | 632 | public JpaQuery copy() { 633 | JpaQueryImpl finder = new JpaQueryImpl(this.finderHandler, this.finderRender); 634 | 635 | finder.parentFinder = parentFinder; 636 | finder.parentFromInfos = parentFromInfos; 637 | 638 | finder.currentFromInfos = new HashMap(currentFromInfos); 639 | finder.subFinderImpls = new ArrayList(subFinderImpls); 640 | 641 | finder.groupImpl = new GroupImpl(finderHandler, finder); 642 | finder.groupImpl.paths = new ArrayList(groupImpl.paths); 643 | 644 | finder.havingImpl = new HavingImpl(finderHandler, finder); 645 | finder.havingImpl.paths = new ArrayList(havingImpl.paths); 646 | 647 | finder.joinImpl = new JoinImpl(finderHandler, finder); 648 | finder.joinImpl.joinPathMap = new HashMap>(joinImpl.joinPathMap); 649 | 650 | finder.orderImpl = new OrderImpl(finderHandler, finder); 651 | finder.orderImpl.paths = new ArrayList(orderImpl.paths); 652 | 653 | finder.selectImpl = new SelectImpl(finderHandler, finder, selectImpl.entityInfoMap); 654 | finder.selectImpl.selectPaths = new ArrayList(selectImpl.selectPaths); 655 | 656 | finder.whereImpl = new WhereImpl(finderHandler, finder, whereImpl.type, whereImpl.entityInfoMap); 657 | finder.whereImpl.wherePaths = new ArrayList(whereImpl.wherePaths); 658 | 659 | return finder; 660 | } 661 | 662 | public String toString() { 663 | return "JpaQuery[" + hashCode() + "]"; 664 | } 665 | 666 | @Override 667 | public void each(EntityManager em, JpaQueryEach each) { 668 | each(em, each, false); 669 | } 670 | 671 | @SuppressWarnings({ "unchecked" }) 672 | @Override 673 | public void each(EntityManager em, JpaQueryEach each, boolean cacheable) { 674 | for (int i = 0;; i += EACH_SIZE) { 675 | List list = (List) list(em, i, EACH_SIZE, cacheable); 676 | if (list.isEmpty()) { 677 | break; 678 | } 679 | for (T entity : list) { 680 | each.handle(entity); 681 | } 682 | } 683 | } 684 | 685 | @Override 686 | public boolean isEmpty(EntityManager em, boolean cacheable) { 687 | return top(em, 1, cacheable).size() == 0; 688 | } 689 | 690 | @Override 691 | public boolean isEmpty(EntityManager em) { 692 | return isEmpty(em, false); 693 | } 694 | 695 | } 696 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/OrderImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.jpaquery.core.facade.Order; 10 | import com.jpaquery.core.facade.OrderPath; 11 | import com.jpaquery.core.facade.QueryAppender; 12 | import com.jpaquery.core.vo.QueryContent; 13 | 14 | public class OrderImpl implements Order { 15 | 16 | static Logger log = LoggerFactory.getLogger(OrderImpl.class); 17 | 18 | JpaQueryHandler finderHandler; 19 | JpaQueryImpl finderImpl; 20 | 21 | /** 22 | * 路径 23 | */ 24 | List paths = new ArrayList<>(); 25 | 26 | public JpaQueryHandler getFinderHandler() { 27 | return finderHandler; 28 | } 29 | 30 | public JpaQueryImpl getFinderImpl() { 31 | return finderImpl; 32 | } 33 | 34 | public List getPaths() { 35 | return paths; 36 | } 37 | 38 | public OrderImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl) { 39 | super(); 40 | this.finderHandler = finderHandler; 41 | this.finderImpl = finderImpl; 42 | } 43 | 44 | public QueryContent toQueryContent() { 45 | return finderImpl.finderRender.toOrder(finderImpl, this); 46 | } 47 | 48 | public OrderPath get(Object obj) { 49 | Object arg = finderHandler.getPathInfo(); 50 | arg = arg == null ? obj : arg; 51 | OrderPath path = new OrderPathImpl(finderHandler, finderImpl, this, arg); 52 | paths.add(path); 53 | return path; 54 | } 55 | 56 | public QueryAppender append(String queryString, Object... args) { 57 | QueryAppenderImpl queryAppenderImpl = new QueryAppenderImpl(finderImpl, queryString, args); 58 | paths.add(queryAppenderImpl); 59 | return queryAppenderImpl; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/OrderPathImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import com.jpaquery.core.facade.Order; 4 | import com.jpaquery.core.facade.OrderPath; 5 | 6 | public class OrderPathImpl implements OrderPath { 7 | 8 | JpaQueryHandler finderHandler; 9 | JpaQueryImpl finderImpl; 10 | OrderImpl orderImpl; 11 | Object arg; 12 | OrderPathType orderPathType = OrderPathType.asc; 13 | 14 | public JpaQueryHandler getFinderHandler() { 15 | return finderHandler; 16 | } 17 | 18 | public JpaQueryImpl getFinderImpl() { 19 | return finderImpl; 20 | } 21 | 22 | public OrderImpl getOrderImpl() { 23 | return orderImpl; 24 | } 25 | 26 | public Object getArg() { 27 | return arg; 28 | } 29 | 30 | public OrderPathType getOrderPathType() { 31 | return orderPathType; 32 | } 33 | 34 | public OrderPathImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl, 35 | OrderImpl orderImpl, Object arg) { 36 | super(); 37 | this.finderHandler = finderHandler; 38 | this.finderImpl = finderImpl; 39 | this.orderImpl = orderImpl; 40 | this.arg = arg; 41 | } 42 | 43 | public Order asc() { 44 | orderPathType = OrderPathType.asc; 45 | return orderImpl; 46 | } 47 | 48 | public Order desc() { 49 | orderPathType = OrderPathType.desc; 50 | return orderImpl; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/QueryAppenderImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | import com.jpaquery.core.facade.QueryAppender; 10 | import com.jpaquery.core.vo.QueryContent; 11 | import com.jpaquery.util._Helper; 12 | 13 | /** 14 | * SQL追加工具类 15 | * 16 | * @author lujijiang 17 | * 18 | */ 19 | public class QueryAppenderImpl implements QueryAppender { 20 | 21 | static final Pattern QUERY_PATTERN = Pattern 22 | .compile( 23 | "(')" + "|((^\\s*and\\s+)" + "|(\\s+and\\s*$))" + "|((^\\s*or\\s+)" + "|(\\s+or\\s*$))" 24 | + "|((^\\s*,)|(,\\s*$))" + "|(^\\s*where\\s+)" + "|(^\\s*select\\s+)" + "|(^\\s*having\\s+)" 25 | + "|(^\\s*order\\s+by\\s+)" + "|(^\\s*group\\s+by\\s+)" + "|(\\?(\\d)*)", 26 | Pattern.CASE_INSENSITIVE); 27 | static final Pattern QUERY_ARG_PATTERN = Pattern.compile("(:\\s*\\w+)" + "|(\\{\\s*\\w+\\s*\\})" + "|(\\?\\d*)", 28 | Pattern.CASE_INSENSITIVE); 29 | 30 | JpaQueryImpl finderImpl; 31 | /** 32 | * 查询语句 33 | */ 34 | String queryString; 35 | 36 | /** 37 | * 占位参数 38 | */ 39 | Object[] args; 40 | 41 | /** 42 | * 序号参数,JPA风格 43 | */ 44 | Map argIndexMap = new ConcurrentHashMap(); 45 | 46 | /** 47 | * 名字参数 48 | */ 49 | Map argNameMap = new ConcurrentHashMap(); 50 | /** 51 | * 别名参数 52 | */ 53 | Map aliasNameMap = new ConcurrentHashMap(); 54 | 55 | public QueryAppenderImpl(JpaQueryImpl finderImpl, String queryString, Object[] args) { 56 | args = args == null ? _Helper.EMPTY_ARRAY : args; 57 | this.finderImpl = finderImpl; 58 | this.args = args; 59 | this.queryString = queryString; 60 | checkAndFix(); 61 | } 62 | 63 | /** 64 | * 检查查询语句是否合法以及提出非必要的关键字 65 | * 66 | * @param queryString 67 | * @param argCount 68 | * @return 69 | */ 70 | private void checkAndFix() { 71 | if (queryString == null) { 72 | throw new IllegalArgumentException(String.format("The append query string should not be null")); 73 | } 74 | int argCount = args.length; 75 | StringBuffer sb = new StringBuffer(); 76 | Matcher matcher = QUERY_PATTERN.matcher(queryString); 77 | int count = 0; 78 | while (matcher.find()) { 79 | String group = matcher.group(); 80 | if (group.contains("'")) { 81 | throw new IllegalArgumentException(String.format("The append query string should not contains \"'\"")); 82 | } else if (group.equals("?")) { 83 | if (count >= argCount) { 84 | throw new IllegalArgumentException(String.format( 85 | "The append query string and argument's count is not equal,query string contains %d and argument's count is %d", 86 | count + 1, argCount)); 87 | } 88 | // String id = "arg" 89 | // + UUID.randomUUID().toString().replace("-", ""); 90 | // matcher.appendReplacement(sb, ":".concat(id)); 91 | // argNameMap.put(id, args[count]); 92 | count++; 93 | } else if (group.matches("\\?\\d+")) { 94 | 95 | } else { 96 | matcher.appendReplacement(sb, ""); 97 | } 98 | } 99 | if (count != argCount) { 100 | throw new IllegalArgumentException(String.format( 101 | "The append query string and argument's count is not equal,query string contains %d and argument's count is %d", 102 | count, argCount)); 103 | } 104 | matcher.appendTail(sb); 105 | this.queryString = sb.toString(); 106 | } 107 | 108 | public QueryContent toQueryContent() { 109 | Map argMap = new HashMap(); 110 | StringBuffer sb = new StringBuffer(); 111 | Matcher matcher = QUERY_ARG_PATTERN.matcher(queryString); 112 | int count = 0; 113 | while (matcher.find()) { 114 | String group = matcher.group(); 115 | if (group.startsWith("{")) { 116 | String alias = aliasNameMap.get(group.subSequence(1, group.length() - 1).toString().trim()); 117 | if (alias == null) { 118 | throw new IllegalStateException(String.format("The alias which mapped %s is not exists", group)); 119 | } 120 | matcher.appendReplacement(sb, alias); 121 | } else { 122 | Object arg; 123 | if (group.startsWith(":")) { 124 | String name = group.substring(1).trim(); 125 | arg = argNameMap.get(name); 126 | argMap.put(name, arg); 127 | } else if (group.equals("?")) { 128 | String name = finderImpl.finderHandler.generateParamName(); 129 | arg = args[count]; 130 | argMap.put(name, arg); 131 | matcher.appendReplacement(sb, ":".concat(name)); 132 | count++; 133 | } else { 134 | String name = finderImpl.finderHandler.generateParamName(); 135 | arg = argIndexMap.get(Integer.valueOf(group.substring(1).trim())); 136 | argMap.put(name, arg); 137 | matcher.appendReplacement(sb, ":".concat(name)); 138 | } 139 | if (arg == null) { 140 | throw new IllegalStateException(String.format("The arg which mapped %s is not exists", group)); 141 | } 142 | } 143 | } 144 | matcher.appendTail(sb); 145 | QueryContent queryContent = new QueryContent(sb, argMap); 146 | return queryContent; 147 | } 148 | 149 | public QueryAppender arg(String name, Object value) { 150 | this.argNameMap.put(name.trim(), value); 151 | return this; 152 | } 153 | 154 | public QueryAppender arg(Integer index, Object value) { 155 | this.argIndexMap.put(index, value); 156 | return this; 157 | } 158 | 159 | public QueryAppender alias(String alias, Object proxy) { 160 | this.aliasNameMap.put(alias.trim(), finderImpl.alias(proxy)); 161 | return this; 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/SelectImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import com.jpaquery.core.facade.QueryAppender; 11 | import com.jpaquery.core.facade.Select; 12 | import com.jpaquery.core.facade.SelectPath; 13 | import com.jpaquery.core.vo.EntityInfo; 14 | import com.jpaquery.core.vo.QueryContent; 15 | 16 | /** 17 | * Select实现 18 | * 19 | * @author lujijiang 20 | * 21 | */ 22 | public class SelectImpl implements Select { 23 | 24 | static Logger log = LoggerFactory.getLogger(SelectImpl.class); 25 | 26 | /** 27 | * finder实现类 28 | */ 29 | JpaQueryImpl finderImpl; 30 | 31 | /** 32 | * finder处理器 33 | */ 34 | JpaQueryHandler finderHandler; 35 | 36 | /** 37 | * select路径 38 | */ 39 | List selectPaths = new ArrayList<>(); 40 | /** 41 | * 个性化映射 42 | */ 43 | Map> entityInfoMap; 44 | 45 | public JpaQueryImpl getFinderImpl() { 46 | return finderImpl; 47 | } 48 | 49 | public JpaQueryHandler getFinderHandler() { 50 | return finderHandler; 51 | } 52 | 53 | public List getSelectPaths() { 54 | return selectPaths; 55 | } 56 | 57 | public Map> getEntityInfoMap() { 58 | return entityInfoMap; 59 | } 60 | 61 | public SelectImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl, Map> entityInfoMap) { 62 | super(); 63 | this.finderImpl = finderImpl; 64 | this.finderHandler = finderHandler; 65 | this.entityInfoMap = entityInfoMap; 66 | } 67 | 68 | public QueryContent toQueryContent() { 69 | return finderImpl.finderRender.toSelect(finderImpl, this); 70 | } 71 | 72 | public SelectPath get(T obj) { 73 | Object arg = finderHandler.getPathInfo(); 74 | arg = arg == null ? obj : arg; 75 | SelectPath selectPath = new SelectPathImpl(finderHandler, finderImpl, this, arg); 76 | selectPaths.add(selectPath); 77 | return selectPath; 78 | } 79 | 80 | public QueryAppender append(String queryString, Object... args) { 81 | QueryAppenderImpl queryAppenderImpl = new QueryAppenderImpl(finderImpl, queryString, args); 82 | selectPaths.add(queryAppenderImpl); 83 | return queryAppenderImpl; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/SelectPathImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import com.jpaquery.core.facade.FunctionPath; 4 | import com.jpaquery.core.facade.SelectPath; 5 | 6 | /** 7 | * select路径实现 8 | * 9 | * @author lujijiang 10 | * 11 | * @param 12 | */ 13 | public class SelectPathImpl implements FunctionPath { 14 | 15 | /** 16 | * 17 | */ 18 | SelectPathType selectPathType; 19 | 20 | /** 21 | * 22 | */ 23 | JpaQueryHandler finderHandler; 24 | /** 25 | * 26 | */ 27 | JpaQueryImpl finderImpl; 28 | /** 29 | * 30 | */ 31 | SelectImpl selectImpl; 32 | /** 33 | * 34 | */ 35 | Object arg; 36 | 37 | /** 38 | * 父select 39 | */ 40 | SelectPathImpl parentSelectPathImpl; 41 | 42 | public SelectPathType getSelectPathType() { 43 | return selectPathType; 44 | } 45 | 46 | public JpaQueryHandler getFinderHandler() { 47 | return finderHandler; 48 | } 49 | 50 | public JpaQueryImpl getFinderImpl() { 51 | return finderImpl; 52 | } 53 | 54 | public SelectImpl getSelectImpl() { 55 | return selectImpl; 56 | } 57 | 58 | public Object getArg() { 59 | return arg; 60 | } 61 | 62 | public SelectPathImpl getParentSelectPathImpl() { 63 | return parentSelectPathImpl; 64 | } 65 | 66 | public SelectPathImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl, 67 | SelectImpl selectImpl, Object arg) { 68 | this.finderHandler = finderHandler; 69 | this.finderImpl = finderImpl; 70 | this.selectImpl = selectImpl; 71 | this.arg = arg; 72 | } 73 | 74 | public SelectPath distinct() { 75 | return toSelectPath(SelectPathType.distinct); 76 | } 77 | 78 | public FunctionPath count() { 79 | SelectPathImpl parentSelectPathImpl = new SelectPathImpl( 80 | finderHandler, finderImpl, selectImpl, this); 81 | this.parentSelectPathImpl = parentSelectPathImpl; 82 | parentSelectPathImpl.selectPathType = SelectPathType.count; 83 | return parentSelectPathImpl; 84 | } 85 | 86 | public FunctionPath avg() { 87 | return toSelectPath(SelectPathType.avg); 88 | } 89 | 90 | public FunctionPath sum() { 91 | return toSelectPath(SelectPathType.sum); 92 | } 93 | 94 | public FunctionPath min() { 95 | return toSelectPath(SelectPathType.min); 96 | } 97 | 98 | public FunctionPath max() { 99 | return toSelectPath(SelectPathType.max); 100 | } 101 | 102 | private FunctionPath toSelectPath(SelectPathType selectPathType) { 103 | SelectPathImpl parentSelectPathImpl = new SelectPathImpl( 104 | finderHandler, finderImpl, selectImpl, this); 105 | this.parentSelectPathImpl = parentSelectPathImpl; 106 | parentSelectPathImpl.selectPathType = selectPathType; 107 | return parentSelectPathImpl; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/SubJpaQueryImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import com.jpaquery.core.facade.SubJpaQuery; 4 | 5 | public class SubJpaQueryImpl implements SubJpaQuery { 6 | 7 | JpaQueryImpl jpaQueryImpl; 8 | 9 | SubJpaQueryType subJpaQueryType; 10 | 11 | public SubJpaQueryImpl(JpaQueryImpl jpaQueryImpl, SubJpaQueryType subJpaQueryType) { 12 | this.jpaQueryImpl = jpaQueryImpl; 13 | this.subJpaQueryType = subJpaQueryType; 14 | } 15 | 16 | public JpaQueryImpl getJpaQueryImpl() { 17 | return jpaQueryImpl; 18 | } 19 | 20 | public SubJpaQueryType getSubJpaQueryType() { 21 | return subJpaQueryType; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/WhereImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import com.jpaquery.core.facade.*; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import com.jpaquery.core.facade.SubJpaQuery.SubJpaQueryType; 12 | import com.jpaquery.core.vo.EntityInfo; 13 | import com.jpaquery.core.vo.QueryContent; 14 | 15 | /** 16 | * Where实现 17 | * 18 | * @author lujijiang 19 | * 20 | */ 21 | public class WhereImpl implements Where, Or, And { 22 | 23 | static Logger log = LoggerFactory.getLogger(WhereImpl.class); 24 | 25 | /** 26 | * 连接类型 27 | */ 28 | WhereType type; 29 | 30 | /** 31 | * finder实现类 32 | */ 33 | JpaQueryImpl finderImpl; 34 | 35 | /** 36 | * finder处理器 37 | */ 38 | JpaQueryHandler finderHandler; 39 | 40 | /** 41 | * where路径 42 | */ 43 | List wherePaths = new ArrayList<>(); 44 | 45 | /** 46 | * 个性化映射 47 | */ 48 | Map> entityInfoMap; 49 | 50 | public WhereType getType() { 51 | return type; 52 | } 53 | 54 | public JpaQueryImpl getFinderImpl() { 55 | return finderImpl; 56 | } 57 | 58 | public List getWherePaths() { 59 | return wherePaths; 60 | } 61 | 62 | public JpaQueryHandler getFinderHandler() { 63 | return finderHandler; 64 | } 65 | 66 | public Map> getEntityInfoMap() { 67 | return entityInfoMap; 68 | } 69 | 70 | public WhereImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl, WhereType type, 71 | Map> entityInfoMap) { 72 | this.finderImpl = finderImpl; 73 | this.finderHandler = finderHandler; 74 | this.type = type; 75 | this.entityInfoMap = entityInfoMap; 76 | } 77 | 78 | public QueryContent toQueryContent() { 79 | return finderImpl.finderRender.toWhere(finderImpl, this); 80 | } 81 | 82 | public WherePath get(T obj) { 83 | Object arg = finderHandler.getPathInfo(); 84 | arg = arg == null ? obj : arg; 85 | WherePathImpl wherePath = new WherePathImpl(finderHandler, finderImpl, this, arg); 86 | wherePaths.add(wherePath); 87 | return wherePath; 88 | } 89 | 90 | @Override 91 | public void and(WhereHandler whereHandler) { 92 | WhereImpl subWhereImpl = new WhereImpl(finderHandler, finderImpl, Where.WhereType.and, entityInfoMap); 93 | wherePaths.add(subWhereImpl); 94 | whereHandler.handle(subWhereImpl); 95 | } 96 | 97 | @Override 98 | public void or(WhereHandler whereHandler) { 99 | WhereImpl subWhereImpl = new WhereImpl(finderHandler, finderImpl, Where.WhereType.or, entityInfoMap); 100 | wherePaths.add(subWhereImpl); 101 | whereHandler.handle(subWhereImpl); 102 | } 103 | 104 | public Where exists(JpaQuery subFinder) { 105 | SubJpaQueryImpl subFinderImpl = new SubJpaQueryImpl((JpaQueryImpl) subFinder, SubJpaQueryType.exists); 106 | wherePaths.add(subFinderImpl); 107 | return this; 108 | } 109 | 110 | public Where notExists(JpaQuery subFinder) { 111 | SubJpaQueryImpl subFinderImpl = new SubJpaQueryImpl((JpaQueryImpl) subFinder, SubJpaQueryType.notExists); 112 | wherePaths.add(subFinderImpl); 113 | return this; 114 | } 115 | 116 | public QueryAppender append(String queryString, Object... args) { 117 | QueryAppenderImpl queryAppenderImpl = new QueryAppenderImpl(finderImpl, queryString, args); 118 | wherePaths.add(queryAppenderImpl); 119 | return queryAppenderImpl; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/impl/WherePathImpl.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.impl; 2 | 3 | import com.jpaquery.core.constant.LikeWay; 4 | import com.jpaquery.core.facade.BetweenPath; 5 | import com.jpaquery.core.facade.JpaQuery; 6 | import com.jpaquery.core.facade.Where; 7 | import com.jpaquery.core.facade.WherePath; 8 | import com.jpaquery.core.vo.PathInfo; 9 | import com.jpaquery.util._Helper; 10 | 11 | /** 12 | * Where路径实现类 13 | * 14 | * @author lujijiang 15 | * 16 | * @param 17 | */ 18 | public class WherePathImpl implements WherePath { 19 | /** 20 | * finder处理器 21 | */ 22 | JpaQueryHandler finderHandler; 23 | /** 24 | * finder实现类 25 | */ 26 | JpaQueryImpl finderImpl; 27 | /** 28 | * 主where示例 29 | */ 30 | WhereImpl whereImpl; 31 | /** 32 | * 路径信息 33 | */ 34 | Object left; 35 | 36 | /** 37 | * 是否允许空参数 38 | */ 39 | boolean ifExist; 40 | /** 41 | * 路径类型 42 | */ 43 | WherePathType wherePathType; 44 | /** 45 | * 参数 46 | */ 47 | Object[] args; 48 | 49 | public JpaQueryHandler getFinderHandler() { 50 | return finderHandler; 51 | } 52 | 53 | public JpaQueryImpl getFinderImpl() { 54 | return finderImpl; 55 | } 56 | 57 | public WhereImpl getWhereImpl() { 58 | return whereImpl; 59 | } 60 | 61 | public Object getLeft() { 62 | return left; 63 | } 64 | 65 | public boolean isIfExist() { 66 | return ifExist; 67 | } 68 | 69 | public WherePathType getWherePathType() { 70 | return wherePathType; 71 | } 72 | 73 | public Object[] getArgs() { 74 | return args; 75 | } 76 | 77 | public WherePathImpl(JpaQueryHandler finderHandler, JpaQueryImpl finderImpl, WhereImpl whereImpl, Object left) { 78 | this.finderHandler = finderHandler; 79 | this.finderImpl = finderImpl; 80 | this.whereImpl = whereImpl; 81 | this.left = left; 82 | } 83 | 84 | /** 85 | * 填充路径信息 86 | * 87 | * @param obj 88 | * 参数对象 89 | * @param wherePathType 90 | * where类型 91 | * @param ifExist 92 | * 是否存在参数 93 | */ 94 | Where fillPath(WherePathType wherePathType, boolean ifExist, Object... args) { 95 | this.args = args; 96 | this.wherePathType = wherePathType; 97 | this.ifExist = ifExist; 98 | return whereImpl; 99 | } 100 | 101 | public Where equal(T obj) { 102 | Object arg = finderHandler.getPathInfo(); 103 | arg = arg == null ? obj : arg; 104 | return fillPath(WherePathType.equal, false, arg); 105 | } 106 | 107 | public Where notEqual(T obj) { 108 | Object arg = finderHandler.getPathInfo(); 109 | arg = arg == null ? obj : arg; 110 | return fillPath(WherePathType.notEqual, false, arg); 111 | } 112 | 113 | public Where like(T obj) { 114 | Object arg = finderHandler.getPathInfo(); 115 | arg = arg == null ? obj : arg; 116 | return fillPath(WherePathType.like, false, arg); 117 | } 118 | 119 | public Where notLike(T obj) { 120 | Object arg = finderHandler.getPathInfo(); 121 | arg = arg == null ? obj : arg; 122 | return fillPath(WherePathType.notLike, false, arg); 123 | } 124 | 125 | public Where ilike(T obj) { 126 | Object arg = finderHandler.getPathInfo(); 127 | arg = arg == null ? obj : arg; 128 | return fillPath(WherePathType.ilike, false, arg); 129 | } 130 | 131 | public Where notIlike(T obj) { 132 | Object arg = finderHandler.getPathInfo(); 133 | arg = arg == null ? obj : arg; 134 | return fillPath(WherePathType.notIlike, false, arg); 135 | } 136 | 137 | public Where greatThan(T obj) { 138 | Object arg = finderHandler.getPathInfo(); 139 | arg = arg == null ? obj : arg; 140 | return fillPath(WherePathType.greatThan, false, arg); 141 | } 142 | 143 | public Where greatEqual(T obj) { 144 | Object arg = finderHandler.getPathInfo(); 145 | arg = arg == null ? obj : arg; 146 | return fillPath(WherePathType.greatEqual, false, arg); 147 | } 148 | 149 | public Where lessThan(T obj) { 150 | Object arg = finderHandler.getPathInfo(); 151 | arg = arg == null ? obj : arg; 152 | return fillPath(WherePathType.lessThan, false, arg); 153 | } 154 | 155 | public Where lessEqual(T obj) { 156 | Object arg = finderHandler.getPathInfo(); 157 | arg = arg == null ? obj : arg; 158 | return fillPath(WherePathType.lessEqual, false, arg); 159 | } 160 | 161 | public BetweenPath between(T obj) { 162 | Object arg = finderHandler.getPathInfo(); 163 | arg = arg == null ? obj : arg; 164 | BetweenPath betweenPath = new BetweenPathImpl(finderHandler, finderImpl, whereImpl, this, 165 | WherePathType.between, false, arg); 166 | return betweenPath; 167 | } 168 | 169 | public BetweenPath notBetween(T obj) { 170 | Object arg = finderHandler.getPathInfo(); 171 | arg = arg == null ? obj : arg; 172 | BetweenPath betweenPath = new BetweenPathImpl(finderHandler, finderImpl, whereImpl, this, 173 | WherePathType.notBetween, false, arg); 174 | return betweenPath; 175 | } 176 | 177 | public Where in(T... objs) { 178 | Object arg = finderHandler.getPathInfo(); 179 | if (arg != null && objs != null && objs.length > 1) { 180 | throw new IllegalArgumentException( 181 | "In clause, only one path parameter is allowed and can not coexist with the value parameter"); 182 | } 183 | else if(arg==null && (objs==null||objs.length==0)) { 184 | throw new IllegalArgumentException( 185 | "In clause, the value parameters should not be null or empty"); 186 | } 187 | return fillPath(WherePathType.in, false, arg == null ? objs : arg); 188 | } 189 | 190 | public Where notIn(T... objs) { 191 | Object arg = finderHandler.getPathInfo(); 192 | if (arg != null && objs != null && objs.length > 1) { 193 | throw new IllegalArgumentException( 194 | "In clause, only one path parameter is allowed and can not coexist with the value parameter"); 195 | } 196 | else if(arg==null && (objs==null||objs.length==0)) { 197 | throw new IllegalArgumentException( 198 | "Not in clause, the value parameters should not be null or empty"); 199 | } 200 | return fillPath(WherePathType.notIn, false, arg == null ? objs : arg); 201 | } 202 | 203 | public Where equal(JpaQuery subFinder) { 204 | return fillPath(WherePathType.equal, false, subFinder); 205 | } 206 | 207 | public Where notEqual(JpaQuery subFinder) { 208 | return fillPath(WherePathType.notEqual, false, subFinder); 209 | } 210 | 211 | public Where like(JpaQuery subFinder) { 212 | return fillPath(WherePathType.like, false, subFinder); 213 | } 214 | 215 | public Where notLike(JpaQuery subFinder) { 216 | return fillPath(WherePathType.notIlike, false, subFinder); 217 | } 218 | 219 | public Where ilike(JpaQuery subFinder) { 220 | return fillPath(WherePathType.ilike, false, subFinder); 221 | } 222 | 223 | public Where notIlike(JpaQuery subFinder) { 224 | return fillPath(WherePathType.notIlike, false, subFinder); 225 | } 226 | 227 | public Where greatThan(JpaQuery subFinder) { 228 | return fillPath(WherePathType.greatThan, false, subFinder); 229 | } 230 | 231 | public Where greatEqual(JpaQuery subFinder) { 232 | return fillPath(WherePathType.greatEqual, false, subFinder); 233 | } 234 | 235 | public Where lessThan(JpaQuery subFinder) { 236 | return fillPath(WherePathType.lessThan, false, subFinder); 237 | } 238 | 239 | public Where lessEqual(JpaQuery subFinder) { 240 | return fillPath(WherePathType.lessEqual, false, subFinder); 241 | } 242 | 243 | public BetweenPath between(JpaQuery subFinder) { 244 | BetweenPath betweenPath = new BetweenPathImpl(finderHandler, finderImpl, whereImpl, this, 245 | WherePathType.between, false, subFinder); 246 | return betweenPath; 247 | } 248 | 249 | public BetweenPath notBetween(JpaQuery subFinder) { 250 | BetweenPath betweenPath = new BetweenPathImpl(finderHandler, finderImpl, whereImpl, this, 251 | WherePathType.notBetween, false, subFinder); 252 | return betweenPath; 253 | } 254 | 255 | public Where in(JpaQuery subFinder) { 256 | return fillPath(WherePathType.in, false, subFinder); 257 | } 258 | 259 | public Where notIn(JpaQuery subFinder) { 260 | return fillPath(WherePathType.notIn, false, subFinder); 261 | } 262 | 263 | public Where equalIfExist(T obj) { 264 | Object arg = finderHandler.getPathInfo(); 265 | arg = arg == null ? obj : arg; 266 | return fillPath(WherePathType.equal, true, arg); 267 | } 268 | 269 | public Where notEqualIfExist(T obj) { 270 | Object arg = finderHandler.getPathInfo(); 271 | arg = arg == null ? obj : arg; 272 | return fillPath(WherePathType.notEqual, true, arg); 273 | } 274 | 275 | public Where likeIfExist(T obj) { 276 | Object arg = finderHandler.getPathInfo(); 277 | arg = arg == null ? obj : arg; 278 | return fillPath(WherePathType.like, true, arg); 279 | } 280 | 281 | public Where notLikeIfExist(T obj) { 282 | Object arg = finderHandler.getPathInfo(); 283 | arg = arg == null ? obj : arg; 284 | return fillPath(WherePathType.notLike, true, arg); 285 | } 286 | 287 | public Where ilikeIfExist(T obj) { 288 | Object arg = finderHandler.getPathInfo(); 289 | arg = arg == null ? obj : arg; 290 | return fillPath(WherePathType.ilike, true, arg); 291 | } 292 | 293 | public Where notIlikeIfExist(T obj) { 294 | Object arg = finderHandler.getPathInfo(); 295 | arg = arg == null ? obj : arg; 296 | return fillPath(WherePathType.notIlike, true, arg); 297 | } 298 | 299 | public Where greatThanIfExist(T obj) { 300 | Object arg = finderHandler.getPathInfo(); 301 | arg = arg == null ? obj : arg; 302 | return fillPath(WherePathType.greatThan, true, arg); 303 | } 304 | 305 | public Where greatEqualIfExist(T obj) { 306 | Object arg = finderHandler.getPathInfo(); 307 | arg = arg == null ? obj : arg; 308 | return fillPath(WherePathType.greatEqual, true, arg); 309 | } 310 | 311 | public Where lessThanIfExist(T obj) { 312 | Object arg = finderHandler.getPathInfo(); 313 | arg = arg == null ? obj : arg; 314 | return fillPath(WherePathType.lessThan, true, arg); 315 | } 316 | 317 | public Where lessEqualIfExist(T obj) { 318 | Object arg = finderHandler.getPathInfo(); 319 | arg = arg == null ? obj : arg; 320 | return fillPath(WherePathType.lessEqual, true, arg); 321 | } 322 | 323 | public BetweenPath betweenIfExist(T obj) { 324 | Object arg = finderHandler.getPathInfo(); 325 | arg = arg == null ? obj : arg; 326 | BetweenPath betweenPath = new BetweenPathImpl(finderHandler, finderImpl, whereImpl, this, 327 | WherePathType.between, true, arg); 328 | return betweenPath; 329 | } 330 | 331 | public BetweenPath notBetweenIfExist(T obj) { 332 | Object arg = finderHandler.getPathInfo(); 333 | arg = arg == null ? obj : arg; 334 | BetweenPath betweenPath = new BetweenPathImpl(finderHandler, finderImpl, whereImpl, this, 335 | WherePathType.notBetween, true, arg); 336 | return betweenPath; 337 | } 338 | 339 | public Where isNull() { 340 | return fillPath(WherePathType.isNull, false); 341 | } 342 | 343 | public Where isNotNull() { 344 | return fillPath(WherePathType.isNotNull, false); 345 | } 346 | 347 | public boolean equals(Object obj) { 348 | throw new UnsupportedOperationException( 349 | "The equals method is not supported, maybe you should use equal method"); 350 | } 351 | 352 | @Override 353 | public Where likeLeft(T obj) { 354 | PathInfo pathInfo = finderHandler.getPathInfo(); 355 | if (pathInfo == null) { 356 | return fillPath(WherePathType.like, false, obj + "%"); 357 | } 358 | pathInfo.setLikeWay(LikeWay.leftLike); 359 | return fillPath(WherePathType.like, false, pathInfo); 360 | } 361 | 362 | @Override 363 | public Where notLikeLeft(T obj) { 364 | PathInfo pathInfo = finderHandler.getPathInfo(); 365 | if (pathInfo == null) { 366 | return fillPath(WherePathType.notLike, false, obj + "%"); 367 | } 368 | pathInfo.setLikeWay(LikeWay.leftLike); 369 | return fillPath(WherePathType.notLike, false, pathInfo); 370 | } 371 | 372 | @Override 373 | public Where likeRight(T obj) { 374 | PathInfo pathInfo = finderHandler.getPathInfo(); 375 | if (pathInfo == null) { 376 | return fillPath(WherePathType.like, false, obj + "%"); 377 | } 378 | pathInfo.setLikeWay(LikeWay.rightLike); 379 | return fillPath(WherePathType.like, false, pathInfo); 380 | } 381 | 382 | @Override 383 | public Where notLikeRight(T obj) { 384 | PathInfo pathInfo = finderHandler.getPathInfo(); 385 | if (pathInfo == null) { 386 | return fillPath(WherePathType.notLike, false, obj + "%"); 387 | } 388 | pathInfo.setLikeWay(LikeWay.rightLike); 389 | return fillPath(WherePathType.notLike, false, pathInfo); 390 | } 391 | 392 | @Override 393 | public Where ilikeLeft(T obj) { 394 | PathInfo pathInfo = finderHandler.getPathInfo(); 395 | if (pathInfo == null) { 396 | return fillPath(WherePathType.ilike, false, obj + "%"); 397 | } 398 | pathInfo.setLikeWay(LikeWay.leftLike); 399 | return fillPath(WherePathType.ilike, false, pathInfo); 400 | } 401 | 402 | @Override 403 | public Where notILikeLeft(T obj) { 404 | PathInfo pathInfo = finderHandler.getPathInfo(); 405 | if (pathInfo == null) { 406 | return fillPath(WherePathType.notIlike, false, obj + "%"); 407 | } 408 | pathInfo.setLikeWay(LikeWay.leftLike); 409 | return fillPath(WherePathType.notIlike, false, pathInfo); 410 | } 411 | 412 | @Override 413 | public Where ilikeRight(T obj) { 414 | PathInfo pathInfo = finderHandler.getPathInfo(); 415 | if (pathInfo == null) { 416 | return fillPath(WherePathType.ilike, false, obj + "%"); 417 | } 418 | pathInfo.setLikeWay(LikeWay.rightLike); 419 | return fillPath(WherePathType.ilike, false, pathInfo); 420 | } 421 | 422 | @Override 423 | public Where notILikeRight(T obj) { 424 | PathInfo pathInfo = finderHandler.getPathInfo(); 425 | if (pathInfo == null) { 426 | return fillPath(WherePathType.notIlike, false, obj + "%"); 427 | } 428 | pathInfo.setLikeWay(LikeWay.rightLike); 429 | return fillPath(WherePathType.notIlike, false, pathInfo); 430 | } 431 | 432 | @Override 433 | public Where likeLeftIfExist(T obj) { 434 | PathInfo pathInfo = finderHandler.getPathInfo(); 435 | if (pathInfo == null) { 436 | return fillPath(WherePathType.like, true, !_Helper.isEmpty(obj) ? obj + "%" : null); 437 | } 438 | pathInfo.setLikeWay(LikeWay.leftLike); 439 | return fillPath(WherePathType.like, true, pathInfo); 440 | } 441 | 442 | @Override 443 | public Where notLikeLeftIfExist(T obj) { 444 | PathInfo pathInfo = finderHandler.getPathInfo(); 445 | if (pathInfo == null) { 446 | return fillPath(WherePathType.notLike, true, !_Helper.isEmpty(obj) ? obj + "%" : null); 447 | } 448 | pathInfo.setLikeWay(LikeWay.leftLike); 449 | return fillPath(WherePathType.notLike, true, pathInfo); 450 | } 451 | 452 | @Override 453 | public Where likeRightIfExist(T obj) { 454 | PathInfo pathInfo = finderHandler.getPathInfo(); 455 | if (pathInfo == null) { 456 | return fillPath(WherePathType.like, true, !_Helper.isEmpty(obj) ? obj + "%" : null); 457 | } 458 | pathInfo.setLikeWay(LikeWay.rightLike); 459 | return fillPath(WherePathType.like, true, pathInfo); 460 | } 461 | 462 | @Override 463 | public Where notLikeRightIfExist(T obj) { 464 | PathInfo pathInfo = finderHandler.getPathInfo(); 465 | if (pathInfo == null) { 466 | return fillPath(WherePathType.notLike, true, !_Helper.isEmpty(obj) ? obj + "%" : null); 467 | } 468 | pathInfo.setLikeWay(LikeWay.rightLike); 469 | return fillPath(WherePathType.notLike, true, pathInfo); 470 | } 471 | 472 | @Override 473 | public Where ilikeLeftIfExist(T obj) { 474 | PathInfo pathInfo = finderHandler.getPathInfo(); 475 | if (pathInfo == null) { 476 | return fillPath(WherePathType.ilike, true, !_Helper.isEmpty(obj) ? obj + "%" : null); 477 | } 478 | pathInfo.setLikeWay(LikeWay.leftLike); 479 | return fillPath(WherePathType.ilike, true, pathInfo); 480 | } 481 | 482 | @Override 483 | public Where notILikeLeftIfExist(T obj) { 484 | PathInfo pathInfo = finderHandler.getPathInfo(); 485 | if (pathInfo == null) { 486 | return fillPath(WherePathType.notIlike, true, !_Helper.isEmpty(obj) ? obj + "%" : null); 487 | } 488 | pathInfo.setLikeWay(LikeWay.leftLike); 489 | return fillPath(WherePathType.notIlike, true, pathInfo); 490 | } 491 | 492 | @Override 493 | public Where ilikeRightIfExist(T obj) { 494 | PathInfo pathInfo = finderHandler.getPathInfo(); 495 | if (pathInfo == null) { 496 | return fillPath(WherePathType.ilike, true, !_Helper.isEmpty(obj) ? obj + "%" : null); 497 | } 498 | pathInfo.setLikeWay(LikeWay.rightLike); 499 | return fillPath(WherePathType.ilike, true, pathInfo); 500 | } 501 | 502 | @Override 503 | public Where notILikeRightIfExist(T obj) { 504 | PathInfo pathInfo = finderHandler.getPathInfo(); 505 | if (pathInfo == null) { 506 | return fillPath(WherePathType.notIlike, true, !_Helper.isEmpty(obj) ? obj + "%" : null); 507 | } 508 | pathInfo.setLikeWay(LikeWay.rightLike); 509 | return fillPath(WherePathType.notIlike, true, pathInfo); 510 | } 511 | 512 | @Override 513 | public Where likeAll(T obj) { 514 | PathInfo pathInfo = finderHandler.getPathInfo(); 515 | if (pathInfo == null) { 516 | return fillPath(WherePathType.like, false, !_Helper.isEmpty(obj) ? "%" + obj + "%" : null); 517 | } 518 | pathInfo.setLikeWay(LikeWay.allLike); 519 | return fillPath(WherePathType.like, false, pathInfo); 520 | } 521 | 522 | @Override 523 | public Where notLikeAll(T obj) { 524 | PathInfo pathInfo = finderHandler.getPathInfo(); 525 | if (pathInfo == null) { 526 | return fillPath(WherePathType.notLike, false, !_Helper.isEmpty(obj) ? "%" + obj + "%" : null); 527 | } 528 | pathInfo.setLikeWay(LikeWay.allLike); 529 | return fillPath(WherePathType.notLike, false, pathInfo); 530 | } 531 | 532 | @Override 533 | public Where ilikeAll(T obj) { 534 | PathInfo pathInfo = finderHandler.getPathInfo(); 535 | if (pathInfo == null) { 536 | return fillPath(WherePathType.ilike, false, !_Helper.isEmpty(obj) ? "%" + obj + "%" : null); 537 | } 538 | pathInfo.setLikeWay(LikeWay.allLike); 539 | return fillPath(WherePathType.ilike, false, pathInfo); 540 | } 541 | 542 | @Override 543 | public Where notIlikeAll(T obj) { 544 | PathInfo pathInfo = finderHandler.getPathInfo(); 545 | if (pathInfo == null) { 546 | return fillPath(WherePathType.notIlike, false, !_Helper.isEmpty(obj) ? "%" + obj + "%" : null); 547 | } 548 | pathInfo.setLikeWay(LikeWay.allLike); 549 | return fillPath(WherePathType.notIlike, false, pathInfo); 550 | } 551 | 552 | @Override 553 | public Where likeAllIfExist(T obj) { 554 | PathInfo pathInfo = finderHandler.getPathInfo(); 555 | if (pathInfo == null) { 556 | return fillPath(WherePathType.like, true, !_Helper.isEmpty(obj) ? "%" + obj + "%" : null); 557 | } 558 | pathInfo.setLikeWay(LikeWay.allLike); 559 | return fillPath(WherePathType.like, true, pathInfo); 560 | } 561 | 562 | @Override 563 | public Where notLikeAllIfExist(T obj) { 564 | PathInfo pathInfo = finderHandler.getPathInfo(); 565 | if (pathInfo == null) { 566 | return fillPath(WherePathType.notLike, true, !_Helper.isEmpty(obj) ? "%" + obj + "%" : null); 567 | } 568 | pathInfo.setLikeWay(LikeWay.allLike); 569 | return fillPath(WherePathType.notLike, true, pathInfo); 570 | } 571 | 572 | @Override 573 | public Where ilikeAllIfExist(T obj) { 574 | PathInfo pathInfo = finderHandler.getPathInfo(); 575 | if (pathInfo == null) { 576 | return fillPath(WherePathType.ilike, true, !_Helper.isEmpty(obj) ? "%" + obj + "%" : null); 577 | } 578 | pathInfo.setLikeWay(LikeWay.allLike); 579 | return fillPath(WherePathType.ilike, true, pathInfo); 580 | } 581 | 582 | @Override 583 | public Where notILikeAllIfExist(T obj) { 584 | PathInfo pathInfo = finderHandler.getPathInfo(); 585 | if (pathInfo == null) { 586 | return fillPath(WherePathType.notIlike, true, !_Helper.isEmpty(obj) ? "%" + obj + "%" : null); 587 | } 588 | pathInfo.setLikeWay(LikeWay.allLike); 589 | return fillPath(WherePathType.notIlike, true, pathInfo); 590 | } 591 | 592 | } 593 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.core; -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/render/JpaQueryRender.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.render; 2 | 3 | import com.jpaquery.core.impl.GroupImpl; 4 | import com.jpaquery.core.impl.HavingImpl; 5 | import com.jpaquery.core.impl.JpaQueryImpl; 6 | import com.jpaquery.core.impl.OrderImpl; 7 | import com.jpaquery.core.impl.SelectImpl; 8 | import com.jpaquery.core.impl.WhereImpl; 9 | import com.jpaquery.core.vo.QueryContent; 10 | 11 | public interface JpaQueryRender { 12 | 13 | QueryContent toFrom(JpaQueryImpl finderImpl); 14 | 15 | QueryContent toWhere(JpaQueryImpl finderImpl, WhereImpl whereImpl); 16 | 17 | QueryContent toSelect(JpaQueryImpl finderImpl, SelectImpl selectImpl); 18 | 19 | QueryContent toOrder(JpaQueryImpl finderImpl, OrderImpl orderImpl); 20 | 21 | QueryContent toGroup(JpaQueryImpl finderImpl, GroupImpl groupImpl); 22 | 23 | QueryContent toHaving(JpaQueryImpl finderImpl, HavingImpl havingImpl); 24 | 25 | QueryContent toSelectCount(JpaQueryImpl finderImpl, SelectImpl selectImpl); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/render/impl/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.core.render.impl; -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/render/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.core.render; -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/vo/EntityInfo.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.vo; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import com.jpaquery.core.impl.JpaQueryHandler; 6 | import com.jpaquery.util._Helper; 7 | 8 | /** 9 | * 实体信息 10 | * 11 | * @author lujijiang 12 | * 13 | */ 14 | public class EntityInfo { 15 | /** 16 | * 实体类型 17 | */ 18 | Class type; 19 | /** 20 | * 实体别名 21 | */ 22 | String alias; 23 | /** 24 | * 实体模型 25 | */ 26 | T proxy; 27 | /** 28 | * 实体key 29 | */ 30 | Long key; 31 | 32 | public EntityInfo(JpaQueryHandler finderHandler, Class type, T proxy) { 33 | this.type = type; 34 | this.proxy = proxy; 35 | key = _Helper.identityHashCode(proxy); 36 | alias = StringUtils.uncapitalize(type.getSimpleName()); 37 | int index = finderHandler.generateEntityIndex(type); 38 | if (index > 0) { 39 | alias = alias.concat("_").concat(String.valueOf(index)); 40 | } 41 | 42 | } 43 | 44 | public Class getType() { 45 | return type; 46 | } 47 | 48 | public String getAlias() { 49 | return alias; 50 | } 51 | 52 | public void setAlias(String alias) { 53 | this.alias = alias; 54 | } 55 | 56 | public T getProxy() { 57 | return proxy; 58 | } 59 | 60 | public Long getKey() { 61 | return key; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/vo/FromInfo.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.vo; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.jpaquery.core.impl.JoinPathImpl; 7 | 8 | /** 9 | * From信息 10 | * 11 | * @author lujijiang 12 | * 13 | */ 14 | public class FromInfo { 15 | /** 16 | * 实体信息 17 | */ 18 | EntityInfo entityInfo; 19 | 20 | /** 21 | * Join信息 22 | */ 23 | List> joinPaths = new ArrayList<>(); 24 | 25 | public EntityInfo getEntityInfo() { 26 | return entityInfo; 27 | } 28 | 29 | public List> getJoinPaths() { 30 | return joinPaths; 31 | } 32 | 33 | public FromInfo(EntityInfo entityInfo) { 34 | super(); 35 | this.entityInfo = entityInfo; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/vo/PathInfo.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.vo; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import com.jpaquery.core.constant.LikeWay; 6 | import com.jpaquery.util._Helper; 7 | 8 | /** 9 | * 路径消息 10 | * 11 | * @author lujijiang 12 | * 13 | */ 14 | public class PathInfo { 15 | /** 16 | * 根代理对象 17 | */ 18 | Object rootProxy; 19 | 20 | /** 21 | * 根代理对象的系统引用 22 | */ 23 | long rootKey; 24 | /** 25 | * 当前代理对象 26 | */ 27 | Object currentProxy; 28 | /** 29 | * 当前代理对象的系统引用 30 | */ 31 | long currentKey; 32 | /** 33 | * 路径构建 34 | */ 35 | StringBuilder pathBuilder; 36 | /** 37 | * getter方法 38 | */ 39 | Method getter; 40 | 41 | /** 42 | * 相似方式 43 | */ 44 | LikeWay likeWay; 45 | 46 | public PathInfo(Object rootProxy, Object currentProxy, StringBuilder pathBuilder, Method getter) { 47 | super(); 48 | this.rootProxy = rootProxy; 49 | this.rootKey = _Helper.identityHashCode(rootProxy); 50 | this.setCurrentProxy(currentProxy); 51 | this.pathBuilder = pathBuilder; 52 | this.getter = getter; 53 | } 54 | 55 | public Object getCurrentProxy() { 56 | return currentProxy; 57 | } 58 | 59 | public void setCurrentProxy(Object currentProxy) { 60 | this.currentProxy = currentProxy; 61 | this.currentKey = _Helper.identityHashCode(currentProxy); 62 | } 63 | 64 | public Object getRootProxy() { 65 | return rootProxy; 66 | } 67 | 68 | public long getRootKey() { 69 | return rootKey; 70 | } 71 | 72 | public long getCurrentKey() { 73 | return currentKey; 74 | } 75 | 76 | public StringBuilder getPathBuilder() { 77 | return pathBuilder; 78 | } 79 | 80 | public void setGetter(Method getter) { 81 | this.getter = getter; 82 | } 83 | 84 | public Method getGetter() { 85 | return getter; 86 | } 87 | 88 | public LikeWay getLikeWay() { 89 | return likeWay; 90 | } 91 | 92 | public void setLikeWay(LikeWay likeWay) { 93 | this.likeWay = likeWay; 94 | } 95 | 96 | public String toString() { 97 | return "PathInfo [path=" + pathBuilder + ",rootProxy=" + rootProxy.getClass().getCanonicalName().concat("@") 98 | + System.identityHashCode(rootProxy) + ", currentProxy=" 99 | + currentProxy.getClass().getCanonicalName().concat("@") + System.identityHashCode(currentProxy) + "]"; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/vo/QueryContent.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.core.vo; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | import com.jpaquery.builder.JPQL; 11 | 12 | /** 13 | * 查询信息对象 14 | * 15 | * @author lujijiang 16 | * 17 | */ 18 | public class QueryContent { 19 | 20 | /** 21 | * 查询语句 22 | */ 23 | StringBuilder queryBuilder; 24 | /** 25 | * 查询参数 26 | */ 27 | Map arguments; 28 | 29 | public QueryContent(StringBuilder queryBuilder, Map arguments) { 30 | this.queryBuilder = queryBuilder; 31 | this.arguments = arguments; 32 | } 33 | 34 | public QueryContent(Object object, Map arguments) { 35 | this(new StringBuilder().append(object), arguments); 36 | } 37 | 38 | public QueryContent() { 39 | this(new StringBuilder(), new ConcurrentHashMap()); 40 | } 41 | 42 | public StringBuilder getQueryBuilder() { 43 | return queryBuilder; 44 | } 45 | 46 | public String getQueryString() { 47 | return queryBuilder.toString(); 48 | } 49 | 50 | public Map getArguments() { 51 | return arguments; 52 | } 53 | 54 | public QueryContent append(QueryContent otherQueryContent) { 55 | if (otherQueryContent != null) { 56 | this.getQueryBuilder().append(otherQueryContent.getQueryBuilder()); 57 | this.getArguments().putAll(otherQueryContent.getArguments()); 58 | } 59 | return this; 60 | } 61 | 62 | public QueryContent append(String queryString) { 63 | append(queryString, null); 64 | return this; 65 | } 66 | 67 | public QueryContent append(String queryString, Map args) { 68 | this.getQueryBuilder().append(queryString); 69 | if (args != null) { 70 | this.getArguments().putAll(args); 71 | } 72 | return this; 73 | } 74 | 75 | final static Pattern NAME__ARG_PATTERN = Pattern.compile(":\\w+"); 76 | 77 | public String toString(String databaseType) { 78 | StringBuffer sb = new StringBuffer(); 79 | List argList = new ArrayList<>(); 80 | Matcher matcher = NAME__ARG_PATTERN.matcher(getQueryString()); 81 | while (matcher.find()) { 82 | String group = matcher.group(); 83 | Object arg = getArguments().get(group.substring(1)); 84 | argList.add(arg); 85 | matcher.appendReplacement(sb, "?"); 86 | } 87 | matcher.appendTail(sb); 88 | return JPQL.SqlFormatter.format(sb.toString(), databaseType, argList); 89 | } 90 | 91 | public String toString() { 92 | return toString(null); 93 | } 94 | 95 | public int length() { 96 | return getQueryBuilder().length(); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/core/vo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.core.vo; -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/example/Example.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.example; 2 | 3 | import java.beans.IntrospectionException; 4 | import java.beans.Introspector; 5 | import java.beans.PropertyDescriptor; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | import java.util.Collection; 9 | import java.util.Date; 10 | import java.util.HashMap; 11 | import java.util.HashSet; 12 | import java.util.Map; 13 | import java.util.Set; 14 | import java.util.concurrent.atomic.AtomicInteger; 15 | 16 | import com.jpaquery.core.facade.JpaQuery; 17 | import com.jpaquery.util._Helper; 18 | 19 | public class Example { 20 | 21 | Example() { 22 | 23 | } 24 | 25 | /** 26 | * 包含字段 27 | */ 28 | private Set includes = new HashSet(); 29 | /** 30 | * 排除字段 31 | */ 32 | private Set excludes = new HashSet(); 33 | 34 | /** 35 | * 是否包含null字段 36 | */ 37 | private boolean includeNull; 38 | 39 | /** 40 | * 是否包含0,仅针对基本数字类型字段有效 41 | */ 42 | private boolean includePrimitiveZero = false; 43 | 44 | /** 45 | * 是否包含false,仅针对基本boolean类型字段有效 46 | */ 47 | private boolean includePrimitiveFalse = false; 48 | 49 | /** 50 | * 是否包含空字段 51 | */ 52 | private boolean includeEmpty; 53 | 54 | /** 55 | * 需要包括的字段名列表 56 | * 57 | * @param names 58 | * @return 59 | */ 60 | public Example includes(String... names) { 61 | if (names == null) { 62 | throw new IllegalArgumentException("The names argument should not be null"); 63 | } 64 | for (String name : names) { 65 | if (name == null) { 66 | throw new IllegalArgumentException("The names argument should not contain null"); 67 | } 68 | name = name.trim(); 69 | includes.add(name); 70 | } 71 | return this; 72 | } 73 | 74 | /** 75 | * 需要排除的字段名列表 76 | * 77 | * @param names 78 | * @return 79 | */ 80 | public Example excludes(String... names) { 81 | if (names == null) { 82 | throw new IllegalArgumentException("The names argument should not be null"); 83 | } 84 | for (String name : names) { 85 | if (name == null) { 86 | throw new IllegalArgumentException("The names argument should not contain null"); 87 | } 88 | name = name.trim(); 89 | excludes.add(name); 90 | } 91 | return this; 92 | } 93 | 94 | /** 95 | * 是否包含null字段 96 | * 97 | * @return 98 | */ 99 | public Example includeNull() { 100 | includeNull = true; 101 | return this; 102 | } 103 | 104 | /** 105 | * 是否排除null字段 106 | * 107 | * @return 108 | */ 109 | public Example excludeNull() { 110 | includeNull = false; 111 | return this; 112 | } 113 | 114 | /** 115 | * 是否包含空字段 116 | * 117 | * @return 118 | */ 119 | public Example includeEmpty() { 120 | includeEmpty = true; 121 | return this; 122 | } 123 | 124 | /** 125 | * 是否排除空字段 126 | * 127 | * @return 128 | */ 129 | public Example excludeEmpty() { 130 | includeEmpty = false; 131 | return this; 132 | } 133 | 134 | /** 135 | * 是否包含值为0的基本类型字段 136 | * 137 | * @return 138 | */ 139 | public Example includePrimitiveZero() { 140 | includePrimitiveZero = true; 141 | return this; 142 | } 143 | 144 | /** 145 | * 是否排除值为0的基本类型字段 146 | * 147 | * @return 148 | */ 149 | public Example excludePrimitiveZero() { 150 | includePrimitiveZero = false; 151 | return this; 152 | } 153 | 154 | /** 155 | * 是否包含值为false的基本类型字段 156 | * 157 | * @return 158 | */ 159 | public Example includePrimitiveFalse() { 160 | includePrimitiveFalse = true; 161 | return this; 162 | } 163 | 164 | /** 165 | * 是否排除值为false的基本类型字段 166 | * 167 | * @return 168 | */ 169 | public Example excludePrimitiveFalse() { 170 | includePrimitiveFalse = false; 171 | return this; 172 | } 173 | 174 | private Class excludeProxy(Class type) { 175 | while (type.getSimpleName().contains("$")) { 176 | type = type.getSuperclass(); 177 | } 178 | return type; 179 | } 180 | 181 | /** 182 | * @param jpaQuery 183 | * 查找器 184 | * @param example 185 | * 样例对象 186 | * @return 187 | */ 188 | // @SuppressWarnings("unchecked") 189 | // public void toJpaQuery(JpaQuery jpaQuery, Object example) { 190 | // JpaQueryImpl jpaQueryImpl = (JpaQueryImpl) jpaQuery; 191 | // Iterator iterator = jpaQueryImpl.froms().iterator(); 192 | // if (!iterator.hasNext()) { 193 | // throw new IllegalStateException("The jpaQuery should from some entity 194 | // class first"); 195 | // } 196 | // T entityModel = (T) iterator.next().getEntityInfo().getProxy(); 197 | // toJpaQuery(jpaQuery, example, entityModel); 198 | // } 199 | 200 | /** 201 | * 以样例填充Finder,除了Exampe的规则之外,仅对字符串、数字和日期类型有效 202 | * 203 | * @param jpaQuery 204 | * 查找器 205 | * 206 | * @param example 207 | * 样例对象 208 | * 209 | * @param entityModel 210 | * 实体模型代理对象 211 | * @return 212 | */ 213 | public void toJpaQuery(JpaQuery jpaQuery, Object example, T entityModel) { 214 | if (jpaQuery == null) { 215 | throw new IllegalArgumentException("The jpaQuery should not be null"); 216 | } 217 | if (entityModel == null) { 218 | throw new IllegalArgumentException("The entityModel should not be null"); 219 | } 220 | if (example == null) { 221 | throw new IllegalArgumentException("The example should not be null"); 222 | } 223 | String alias = jpaQuery.alias(entityModel); 224 | AtomicInteger paramIndex = new AtomicInteger(0); 225 | try { 226 | toJpaQuery(new HashSet(), null, example, jpaQuery, alias, entityModel.getClass(), paramIndex); 227 | } catch (IllegalAccessException e) { 228 | throw new RuntimeException(e); 229 | } catch (IllegalArgumentException e) { 230 | throw new RuntimeException(e); 231 | } catch (InvocationTargetException e) { 232 | throw new RuntimeException(e); 233 | } catch (IntrospectionException e) { 234 | throw new RuntimeException(e); 235 | } 236 | } 237 | 238 | /** 239 | * 以样例填充Finder,除了Exampe的规则之外,仅对字符串、数字和日期类型有效 240 | * 241 | * @param hashs 242 | * 防止循环引用 243 | * @param prefixName 244 | * 路径前缀 245 | * @param example 246 | * 样例对象 247 | * @param jpaQuery 248 | * 查找器 249 | * @param alias 250 | * 模型别名 251 | * @throws InvocationTargetException 252 | * @throws IllegalArgumentException 253 | * @throws IllegalAccessException 254 | * @throws IntrospectionException 255 | */ 256 | private void toJpaQuery(Set hashs, String prefixPath, Object example, JpaQuery jpaQuery, String alias, 257 | Class entityClass, AtomicInteger paramIndex) 258 | throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException { 259 | Integer hash = System.identityHashCode(example); 260 | if (hashs.contains(hash)) { 261 | return; 262 | } 263 | hashs.add(hash); 264 | 265 | PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(excludeProxy(example.getClass())) 266 | .getPropertyDescriptors(); 267 | 268 | PropertyDescriptor[] entityPropertyDescriptors = Introspector.getBeanInfo(excludeProxy(entityClass)) 269 | .getPropertyDescriptors(); 270 | Map entityPropertyDescriptorMap = new HashMap<>(); 271 | for (PropertyDescriptor entityPropertyDescriptor : entityPropertyDescriptors) { 272 | entityPropertyDescriptorMap.put(entityPropertyDescriptor.getName(), entityPropertyDescriptor); 273 | } 274 | 275 | for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { 276 | 277 | Class propertyType = propertyDescriptor.getPropertyType(); 278 | 279 | String path = propertyDescriptor.getName(); 280 | 281 | PropertyDescriptor entityPropertyDescriptor = entityPropertyDescriptorMap.get(path); 282 | if (entityPropertyDescriptor == null) { 283 | continue; 284 | } 285 | 286 | if (prefixPath != null) { 287 | path = prefixPath.concat(".").concat(path); 288 | } 289 | 290 | if (excludes.contains(path)) { 291 | continue; 292 | } 293 | if (!includes.isEmpty() && !includes.contains(path)) { 294 | continue; 295 | } 296 | 297 | Method readMethod = propertyDescriptor.getReadMethod(); 298 | 299 | if (readMethod == null) { 300 | continue; 301 | } 302 | 303 | String name = "e_".concat(Integer.toString(paramIndex.getAndIncrement())); 304 | Object value = readMethod.invoke(example); 305 | 306 | if (value == null) { 307 | // 过滤null 308 | if (includeNull) { 309 | jpaQuery.where().append(alias.concat(".").concat(path).concat(" is null")); 310 | } 311 | continue; 312 | } else if (CharSequence.class.isAssignableFrom(propertyType)) { 313 | // 过滤字符串 314 | if (value.toString().trim().length() == 0) { 315 | if (!includeEmpty) { 316 | continue; 317 | } 318 | } 319 | jpaQuery.where().append(alias.concat(".").concat(path).concat(" like :").concat(name)).arg(name, 320 | String.valueOf(value)); 321 | } else if (propertyType.isPrimitive()) { 322 | // 过滤基本类型 323 | if (value != null && value.equals(0)) { 324 | if (!includePrimitiveZero) { 325 | continue; 326 | } 327 | } 328 | if (value != null && value.equals(false)) { 329 | if (!includePrimitiveFalse) { 330 | continue; 331 | } 332 | } 333 | if (value instanceof Boolean) { 334 | value = ((Boolean) value).booleanValue(); 335 | } 336 | jpaQuery.where().append(alias.concat(".").concat(path).concat(" = :").concat(name)).arg(name, value); 337 | } else { 338 | // 过滤数字和日期类型等其它类型 339 | if (propertyType.isEnum() || Number.class.isAssignableFrom(propertyType) 340 | || Boolean.class.equals(propertyType) || Character.class.equals(propertyType) 341 | || Date.class.isAssignableFrom(propertyType)) { 342 | jpaQuery.where().append(alias.concat(".").concat(path).concat(" = :").concat(name)).arg(name, 343 | value); 344 | } else { 345 | if (_Helper.isBaseType(propertyType)) { 346 | continue; 347 | } 348 | if (propertyType.isArray()) { 349 | continue; 350 | } 351 | if (Collection.class.isAssignableFrom(propertyType)) { 352 | continue; 353 | } 354 | if (Map.class.isAssignableFrom(propertyType)) { 355 | continue; 356 | } 357 | toJpaQuery(hashs, path, value, jpaQuery, alias, entityPropertyDescriptor.getPropertyType(), 358 | paramIndex); 359 | } 360 | } 361 | } 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/example/Examples.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.example; 2 | 3 | public class Examples { 4 | public static Example create() { 5 | return new Example(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/example/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author lujijiang 3 | * 4 | */ 5 | package com.jpaquery.example; -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/support/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.support; -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/util/_Helper.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.util; 2 | 3 | import java.lang.reflect.Array; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Modifier; 6 | import java.lang.reflect.ParameterizedType; 7 | import java.lang.reflect.Type; 8 | import java.util.Collection; 9 | import java.util.Date; 10 | import java.util.Map; 11 | 12 | public class _Helper { 13 | 14 | /** 15 | * 空类型数组 16 | */ 17 | public static final Class[] EMPTY_TYPES = new Class[] {}; 18 | /** 19 | * 空对象数组 20 | */ 21 | public static final Object[] EMPTY_ARRAY = new Object[0]; 22 | 23 | /** 24 | * 获取对象系统引用哈希值(不为负数) 25 | * 26 | * @param x 27 | * @return 28 | */ 29 | public static long identityHashCode(Object x) { 30 | return (long) System.identityHashCode(x) + (long) Integer.MAX_VALUE; 31 | } 32 | 33 | /** 34 | * 判断一个对象是否是空对象 35 | * 36 | * @param obj 37 | * @return 38 | */ 39 | @SuppressWarnings("rawtypes") 40 | public static boolean isEmpty(Object obj) { 41 | if (obj == null) { 42 | return true; 43 | } 44 | if (obj instanceof Map) { 45 | return ((Map) obj).isEmpty(); 46 | } 47 | if (obj instanceof Collection) { 48 | return ((Collection) obj).isEmpty(); 49 | } 50 | if (obj.getClass().isArray()) { 51 | return Array.getLength(obj) == 0; 52 | } 53 | if (obj instanceof CharSequence) { 54 | return obj.toString().trim().length() == 0; 55 | } 56 | return Object.class.equals(obj.getClass()); 57 | } 58 | 59 | /** 60 | * 判断一个类型是否是基本类型 61 | * 62 | * @param type 63 | * @return 64 | */ 65 | public static boolean isBaseType(Class type) { 66 | if (type.isPrimitive()) { 67 | return true; 68 | } 69 | if (type.isEnum()) { 70 | return true; 71 | } 72 | if (type.isArray()) { 73 | return true; 74 | } 75 | if (Modifier.isFinal(type.getModifiers())) { 76 | return true; 77 | } 78 | if (CharSequence.class.isAssignableFrom(type)) { 79 | return true; 80 | } 81 | if (Number.class.isAssignableFrom(type)) { 82 | return true; 83 | } 84 | if (Date.class.isAssignableFrom(type)) { 85 | return true; 86 | } 87 | if (Boolean.class.equals(type)) { 88 | return true; 89 | } 90 | if (Character.class.equals(type)) { 91 | return true; 92 | } 93 | if (Class.class.equals(type)) { 94 | return true; 95 | } 96 | if (StringBuilder.class.equals(type)) { 97 | return true; 98 | } 99 | if (StringBuffer.class.equals(type)) { 100 | return true; 101 | } 102 | if (Object.class.equals(type)) { 103 | return true; 104 | } 105 | if (Void.class.equals(type)) { 106 | return true; 107 | } 108 | return false; 109 | } 110 | 111 | /** 112 | * 判断是否是数字类型 113 | * 114 | * @param type 115 | * @return 116 | */ 117 | public static boolean isNumber(Class type) { 118 | if (Number.class.isAssignableFrom(type)) { 119 | return true; 120 | } 121 | if (type.equals(int.class)) { 122 | return true; 123 | } 124 | if (type.equals(short.class)) { 125 | return true; 126 | } 127 | if (type.equals(long.class)) { 128 | return true; 129 | } 130 | if (type.equals(float.class)) { 131 | return true; 132 | } 133 | if (type.equals(double.class)) { 134 | return true; 135 | } 136 | if (type.equals(byte.class)) { 137 | return true; 138 | } 139 | return false; 140 | } 141 | 142 | /** 143 | * 获得方法返回类型的参数泛型 144 | * 145 | * @param method 146 | * @param index 147 | * @return 148 | */ 149 | @SuppressWarnings("rawtypes") 150 | public static Class getGenricReturnType(final Method method, final int index) { 151 | Type genericReturnType = method.getGenericReturnType(); 152 | if (genericReturnType != null) { 153 | if (genericReturnType instanceof ParameterizedType) { 154 | ParameterizedType parameterizedType = (ParameterizedType) genericReturnType; 155 | Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); 156 | if (actualTypeArguments.length > index) { 157 | return (Class) actualTypeArguments[index]; 158 | } 159 | } 160 | } 161 | return Object.class; 162 | } 163 | 164 | /** 165 | * 查找调用者 166 | * 167 | * @param excludeBasePackage 168 | * 过滤基础包名 169 | * @return 返回基础包之外的首个调用者 170 | */ 171 | public static String findCaller(String excludeBasePackage) { 172 | String caller = ""; 173 | StackTraceElement[] stackTraceElements = new Exception().getStackTrace(); 174 | for (StackTraceElement stackTraceElement : stackTraceElements) { 175 | if (!stackTraceElement.getClassName().startsWith(excludeBasePackage)) { 176 | caller = stackTraceElement.getClassName().concat(".").concat(stackTraceElement.getMethodName()) 177 | .concat(":").concat(String.valueOf(stackTraceElement.getLineNumber())); 178 | break; 179 | } 180 | } 181 | return caller; 182 | } 183 | 184 | /** 185 | * 查找调用者 186 | * 187 | * @return 返回非JpaQuery本身的调用者 188 | */ 189 | public static String findCaller() { 190 | return findCaller("com.jpaquery"); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/util/_MergeMap.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.util; 2 | 3 | import java.util.*; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * 可合并的Map 8 | * 9 | * @author lujijiang 10 | * 11 | * @param 12 | * @param 13 | */ 14 | public class _MergeMap extends AbstractMap { 15 | 16 | /** 17 | * 其它引用的Map 18 | */ 19 | Set> others = Collections.synchronizedSet(new LinkedHashSet<>()); 20 | /** 21 | * 自身Map 22 | */ 23 | Map own = Collections.synchronizedMap(new LinkedHashMap<>()); 24 | 25 | @Override 26 | public Set keySet() { 27 | Set keys = new LinkedHashSet<>(); 28 | keys.addAll(own.keySet()); 29 | for (Map other : others) { 30 | keys.addAll(other.keySet()); 31 | } 32 | return keys; 33 | } 34 | 35 | @Override 36 | public Set> entrySet() { 37 | 38 | final Set keys = keySet(); 39 | 40 | return new AbstractSet>() { 41 | 42 | @Override 43 | public Iterator> iterator() { 44 | return new Iterator>() { 45 | 46 | Iterator iterator = keys.iterator(); 47 | 48 | @Override 49 | public boolean hasNext() { 50 | return iterator.hasNext(); 51 | } 52 | 53 | @Override 54 | public java.util.Map.Entry next() { 55 | return new java.util.Map.Entry() { 56 | 57 | K key = iterator.next(); 58 | 59 | @Override 60 | public K getKey() { 61 | return key; 62 | } 63 | 64 | @Override 65 | public V getValue() { 66 | return get(key); 67 | } 68 | 69 | @Override 70 | public V setValue(V value) { 71 | throw new UnsupportedOperationException(); 72 | } 73 | }; 74 | } 75 | }; 76 | } 77 | 78 | @Override 79 | public int size() { 80 | return keys.size(); 81 | } 82 | }; 83 | } 84 | 85 | @Override 86 | public V put(K key, V value) { 87 | V oldValue = null; 88 | for (Map other : others) { 89 | if (other.containsKey(key)) { 90 | oldValue = other.put(key, value); 91 | } 92 | } 93 | if (own.containsKey(key)) { 94 | oldValue = own.get(key); 95 | } 96 | own.put(key, value); 97 | return oldValue; 98 | } 99 | 100 | @SuppressWarnings("unchecked") 101 | @Override 102 | public void putAll(Map m) { 103 | others.add((Map) m); 104 | } 105 | 106 | @Override 107 | public boolean containsKey(Object key) { 108 | if (own.containsKey(key)) { 109 | return true; 110 | } 111 | for (Map other : others) { 112 | if (other.containsKey(key)) { 113 | return true; 114 | } 115 | } 116 | return false; 117 | } 118 | 119 | @Override 120 | public V get(Object key) { 121 | if (own.containsKey(key)) { 122 | return own.get(key); 123 | } 124 | for (Map other : others) { 125 | if (other.containsKey(key)) { 126 | return other.get(key); 127 | } 128 | } 129 | return null; 130 | } 131 | 132 | @Override 133 | public V remove(Object key) { 134 | V value = null; 135 | for (Map other : others) { 136 | if (other.containsKey(key)) { 137 | value = other.remove(key); 138 | } 139 | } 140 | if (own.containsKey(key)) { 141 | value = own.remove(key); 142 | } 143 | return value; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/com/jpaquery/util/_Proxys.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.util; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.lang.reflect.InvocationHandler; 5 | import java.lang.reflect.Method; 6 | import java.lang.reflect.Proxy; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.apache.commons.beanutils.ConstructorUtils; 11 | import org.apache.commons.beanutils.MethodUtils; 12 | 13 | import net.sf.cglib.proxy.Enhancer; 14 | import net.sf.cglib.proxy.MethodInterceptor; 15 | import net.sf.cglib.proxy.MethodProxy; 16 | 17 | /** 18 | * 代理工具类 19 | * 20 | * @author lujijiang 21 | * 22 | */ 23 | public class _Proxys { 24 | 25 | private _Proxys() { 26 | } 27 | 28 | /** 29 | * 创建代理对象(只能最多有一个非接口类型) 30 | * 31 | * @param invocationHandler 32 | * 代理处理器 33 | * @param mainType 34 | * 主类型 35 | * @param otherTypes 36 | * 其它类型 37 | * @param arguments 38 | * 父类需要的构造参数 39 | * @return 代理对象 40 | */ 41 | @SuppressWarnings("unchecked") 42 | public static T newProxyInstance(final InvocationHandler invocationHandler, Class mainType, 43 | Class[] otherTypes, Object... arguments) { 44 | List> interfaceTypes = new ArrayList>(); 45 | Class superClass = null; 46 | 47 | if (!mainType.isInterface()) { 48 | superClass = mainType; 49 | } else { 50 | interfaceTypes.add(mainType); 51 | } 52 | if (otherTypes != null) { 53 | for (Class otherType : otherTypes) { 54 | if (!otherType.isInterface()) { 55 | if (superClass != null) { 56 | throw new IllegalArgumentException(String 57 | .format("Should not be more than one super class:%s and %s", superClass, otherType)); 58 | } 59 | superClass = otherType; 60 | } else { 61 | interfaceTypes.add(otherType); 62 | } 63 | } 64 | } 65 | if (superClass == null) { 66 | // 当全部是接口类型时,使用JDK原生代理 67 | return (T) Proxy.newProxyInstance(getClassLoader(), interfaceTypes.toArray(new Class[0]), 68 | new InvocationHandler() { 69 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 70 | return invokeMethod(invocationHandler, proxy, method, args); 71 | } 72 | }); 73 | } 74 | Enhancer en = new Enhancer(); 75 | en.setUseCache(true); 76 | en.setUseFactory(false); 77 | en.setSuperclass(superClass); 78 | en.setInterfaces(interfaceTypes.toArray(_Helper.EMPTY_TYPES)); 79 | en.setCallback(new MethodInterceptor() { 80 | public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 81 | return invokeMethod(invocationHandler, obj, method, args); 82 | } 83 | }); 84 | if (arguments == null || arguments.length == 0) { 85 | return (T) en.create(); 86 | } else { 87 | int argumentLength = arguments.length; 88 | Class parameterTypes[] = new Class[argumentLength]; 89 | for (int i = 0; i < argumentLength; i++) { 90 | parameterTypes[i] = arguments[i] == null ? null : arguments[i].getClass(); 91 | } 92 | Constructor constructor = getMatchingAccessibleConstructor(superClass, parameterTypes); 93 | if (constructor == null) { 94 | throw new IllegalArgumentException( 95 | String.format("Could not found a constructor of type:%s for arguments types:%s", 96 | superClass.getCanonicalName(), argumentTypesToString(parameterTypes))); 97 | } 98 | return (T) en.create(constructor.getParameterTypes(), arguments); 99 | } 100 | } 101 | 102 | /** 103 | * 获得系统类加载器 104 | * 105 | * @return 106 | */ 107 | private static ClassLoader getClassLoader() { 108 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 109 | return classLoader == null ? _Proxys.class.getClassLoader() : classLoader; 110 | } 111 | 112 | /** 113 | * 尝试寻找匹配的构造器 114 | * 115 | * @param clazz 116 | * @param parameterTypes 117 | * @return 118 | */ 119 | private static Constructor getMatchingAccessibleConstructor(Class clazz, Class[] parameterTypes) { 120 | try { 121 | Constructor ctor = clazz.getConstructor(parameterTypes); 122 | try { 123 | ctor.setAccessible(true); 124 | } catch (SecurityException se) { 125 | } 126 | return ctor; 127 | 128 | } catch (NoSuchMethodException e) { 129 | } 130 | 131 | int paramSize = parameterTypes.length; 132 | Constructor[] ctors = clazz.getConstructors(); 133 | for (int i = 0, size = ctors.length; i < size; i++) { 134 | Class[] ctorParams = ctors[i].getParameterTypes(); 135 | int ctorParamSize = ctorParams.length; 136 | if (ctorParamSize == paramSize) { 137 | boolean match = true; 138 | for (int n = 0; n < ctorParamSize; n++) { 139 | if (!MethodUtils.isAssignmentCompatible(ctorParams[n], parameterTypes[n])) { 140 | match = false; 141 | break; 142 | } 143 | } 144 | 145 | if (match) { 146 | Constructor ctor = ConstructorUtils.getAccessibleConstructor(ctors[i]); 147 | if (ctor != null) { 148 | try { 149 | ctor.setAccessible(true); 150 | } catch (SecurityException se) { 151 | } 152 | @SuppressWarnings("unchecked") 153 | Constructor typedCtor = (Constructor) ctor; 154 | return typedCtor; 155 | } 156 | } 157 | } 158 | } 159 | 160 | return null; 161 | } 162 | 163 | /** 164 | * 输出类型信息 165 | * 166 | * @param argTypes 167 | * @return 168 | */ 169 | private static String argumentTypesToString(Class[] argTypes) { 170 | StringBuilder buf = new StringBuilder(); 171 | buf.append("("); 172 | if (argTypes != null) { 173 | for (int i = 0; i < argTypes.length; i++) { 174 | if (i > 0) { 175 | buf.append(", "); 176 | } 177 | Class c = argTypes[i]; 178 | buf.append((c == null) ? "null" : c.getName()); 179 | } 180 | } 181 | buf.append(")"); 182 | return buf.toString(); 183 | } 184 | 185 | /** 186 | * 创建代理对象(只能最多有一个非接口类型) 187 | * 188 | * @param invocationHandler 189 | * 代理处理器 190 | * @param mainType 191 | * 主类型 192 | * @param otherTypes 193 | * 其它类型 194 | * @return 代理对象 195 | */ 196 | public static T newProxyInstance(final InvocationHandler invocationHandler, Class mainType, 197 | Class... otherTypes) { 198 | return newProxyInstance(invocationHandler, mainType, otherTypes, _Helper.EMPTY_ARRAY); 199 | } 200 | 201 | /** 202 | * 创建代理对象(只能最多有一个非接口类型) 203 | * 204 | * @param invocationHandler 205 | * 代理处理器 206 | * @param mainType 207 | * 主类型 208 | * @param arguments 209 | * 构造参数 210 | * @return 代理对象 211 | */ 212 | public static T newProxyInstance(final InvocationHandler invocationHandler, Class mainType, 213 | Object... arguments) { 214 | return newProxyInstance(invocationHandler, mainType, _Helper.EMPTY_TYPES, arguments); 215 | } 216 | 217 | /** 218 | * 创建代理对象 219 | * 220 | * @param invocationHandler 221 | * 代理处理器 222 | * @param mainType 223 | * 主类型 224 | * @return 代理对象 225 | */ 226 | public static T newProxyInstance(final InvocationHandler invocationHandler, Class mainType) { 227 | return newProxyInstance(invocationHandler, mainType, _Helper.EMPTY_TYPES); 228 | } 229 | 230 | /** 231 | * 实际执行方法 232 | * 233 | * @param invocationHandler 234 | * @param proxy 235 | * @param method 236 | * @param args 237 | * @return 238 | * @throws Exception 239 | */ 240 | private static Object invokeMethod(final InvocationHandler invocationHandler, Object proxy, Method method, 241 | Object[] args) throws Throwable { 242 | return invocationHandler.invoke(proxy, method, args); 243 | } 244 | } -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/Gender.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase; 2 | 3 | public enum Gender { 4 | male, female 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/builder/JPQLTest.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.builder; 2 | 3 | import java.io.IOException; 4 | 5 | import org.junit.Test; 6 | 7 | import com.jpaquery.builder.JPQL; 8 | 9 | public class JPQLTest { 10 | @Test 11 | public void testJPQL() { 12 | JPQL jpql = JPQL.create(); 13 | jpql.append("select name,?", "aaaaa").append("from User where name=?", "tester"); 14 | System.out.println(jpql); 15 | } 16 | 17 | @Test 18 | public void testCommand() { 19 | try { 20 | Runtime.getRuntime().exec( 21 | "/bin/sh -c 'gpg' '--use-agent' '--batch' '--passphrase-fd' '0' '--armor' '--detach-sign' '--no-tty' '--output' '/Users/lujijiang/git/jpaquery/target/jpaquery-0.1.jar.asc' '/Users/lujijiang/git/jpaquery/target/jpaquery-0.1.jar'"); 22 | } catch (IOException e) { 23 | // TODO Auto-generated catch block 24 | e.printStackTrace(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/builder/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.testcase.builder; -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.testcase; -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/querytest/ExampleTest.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.querytest; 2 | 3 | import com.jpaquery.testcase.Gender; 4 | import com.jpaquery.testcase.schema.Student; 5 | import com.jpaquery.testcase.vo.VClazz; 6 | import com.jpaquery.testcase.vo.VStudent; 7 | import org.junit.Test; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import com.jpaquery.core.Querys; 12 | import com.jpaquery.core.facade.JpaQuery; 13 | import com.jpaquery.example.Examples; 14 | 15 | public class ExampleTest { 16 | 17 | Logger logger = LoggerFactory.getLogger(getClass()); 18 | 19 | @Test 20 | public void test1() { 21 | VStudent vStudent = new VStudent(); 22 | vStudent.setName("小明"); 23 | vStudent.setNickName("aaaaa"); 24 | vStudent.setGender(Gender.female); 25 | vStudent.setClazz(new VClazz()); 26 | vStudent.getClazz().setName("A班"); 27 | vStudent.getClazz().setOrder(1); 28 | Querys.query(jpaQuery -> { 29 | Student modelStudent = jpaQuery.from(Student.class); 30 | Examples.create().toJpaQuery(jpaQuery, vStudent, modelStudent); 31 | logger.info(jpaQuery.toQueryContent().toString()); 32 | return null; 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/querytest/QueryTest.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.querytest; 2 | 3 | import com.jpaquery.testcase.schema.Clazz; 4 | import com.jpaquery.testcase.schema.Student; 5 | import com.jpaquery.testcase.schema.Teacher; 6 | import org.junit.Test; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import com.jpaquery.core.Querys; 11 | 12 | public class QueryTest { 13 | 14 | Logger logger = LoggerFactory.getLogger(getClass()); 15 | 16 | // @Test 17 | public void test1() { 18 | Querys.query(query -> { 19 | Student modelStudent = query.from(Student.class); 20 | query.select(modelStudent.getClazz()); 21 | query.join(modelStudent.getTeachers().get(0).getClazzs()).left(modelClazz -> { 22 | query.where(modelClazz.getName()).equal("aaa"); 23 | }); 24 | query.where(modelStudent.getName()).equal("张三"); 25 | logger.info(query.toQueryContent().toString()); 26 | return null; 27 | }); 28 | } 29 | 30 | // @Test 31 | public void test2() { 32 | Querys.query(query -> { 33 | Clazz modelClazz = query.from(Clazz.class); 34 | query.subQuery(subQuery->{ 35 | Student modelStudent = subQuery.from(Student.class); 36 | subQuery.where(modelStudent.getClazz()).equal(modelClazz); 37 | subQuery.select(modelStudent.getId()); 38 | query.where().exists(subQuery); 39 | }); 40 | logger.info(query.toQueryContent().toString()); 41 | return null; 42 | }); 43 | } 44 | 45 | /** 46 | * 多级Join展示 47 | */ 48 | @Test 49 | public void test3() { 50 | Querys.query(query -> { 51 | Student modelStudent = query.from(Student.class); 52 | { 53 | query.join(modelStudent.getTeachers().get(0).getClazzs()).left(modelClazz -> { 54 | query.where(modelClazz.getName()).equal("aaa"); 55 | query.join(modelClazz.getTeachers()).left(modelTeacher -> { 56 | query.where(modelTeacher.getName()).equal(modelClazz.getName()); 57 | }); 58 | }); 59 | } 60 | query.where(modelStudent.getName()).equal("张三"); 61 | logger.info(query.toQueryContent().toString()); 62 | return null; 63 | }); 64 | } 65 | 66 | @Test 67 | public void test5() { 68 | Querys.query(query -> { 69 | Student modelStudent = query.from(Student.class); 70 | query.select(modelStudent.getClazz()); 71 | query.join(modelStudent.getTeachers().get(0).getClazzs()).left(modelClazz -> { 72 | query.where(modelClazz).equal(new Clazz()); 73 | query.where(modelClazz.getName()).equal("aaa"); 74 | }); 75 | query.where(modelStudent.getName()).likeAllIfExist("张三"); 76 | query.where(modelStudent.getName()).likeAll(modelStudent.getClazz().getName()); 77 | logger.info(query.toQueryContent().toString()); 78 | return null; 79 | }); 80 | } 81 | 82 | @Test 83 | public void test6() { 84 | Querys.query(query -> { 85 | Student modelStudent = query.from(Student.class); 86 | query.where().or(or->{ 87 | or.get(modelStudent.getName()).equal("111"); 88 | or.get(modelStudent.getName()).equal("222"); 89 | }); 90 | logger.info(query.toQueryContent().toString()); 91 | return null; 92 | }); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/querytest/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.testcase.querytest; -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/schema/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.schema; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import javax.persistence.Column; 7 | import javax.persistence.MappedSuperclass; 8 | import javax.persistence.PrePersist; 9 | import javax.persistence.PreUpdate; 10 | import javax.persistence.Temporal; 11 | import javax.persistence.TemporalType; 12 | import javax.persistence.Version; 13 | 14 | import org.apache.commons.lang3.builder.ToStringBuilder; 15 | 16 | /** 17 | * 抽象实体类型,用于联合主键表 18 | * 19 | * @author lujijiang 20 | * 21 | */ 22 | @MappedSuperclass 23 | public abstract class BaseEntity implements Serializable, Cloneable { 24 | 25 | /** 26 | * 27 | */ 28 | private static final long serialVersionUID = -8833080406291300295L; 29 | 30 | /** 31 | * 是否无效(默认是有效) 32 | */ 33 | @Column(name = "disabled_", columnDefinition = "decimal(1,0)") 34 | protected Boolean disabled; 35 | /** 36 | * 最后更新时间 37 | */ 38 | @Column(name = "last_updated_") 39 | @Temporal(TemporalType.TIMESTAMP) 40 | protected Date lastUpdated; 41 | /** 42 | * 创建时间 43 | */ 44 | @Column(name = "date_created_") 45 | @Temporal(TemporalType.TIMESTAMP) 46 | protected Date dateCreated; 47 | 48 | /** 49 | * 数据库版本号(用于乐观锁) 50 | */ 51 | @Column(name = "version_") 52 | @Version 53 | protected Integer version; 54 | 55 | public BaseEntity() { 56 | 57 | } 58 | 59 | public Boolean getDisabled() { 60 | return disabled; 61 | } 62 | 63 | public void setDisabled(Boolean disabled) { 64 | this.disabled = disabled; 65 | } 66 | 67 | public Date getLastUpdated() { 68 | return lastUpdated; 69 | } 70 | 71 | public void setLastUpdated(Date lastUpdated) { 72 | this.lastUpdated = lastUpdated; 73 | } 74 | 75 | public Date getDateCreated() { 76 | return dateCreated; 77 | } 78 | 79 | public void setDateCreated(Date dateCreated) { 80 | this.dateCreated = dateCreated; 81 | } 82 | 83 | public Integer getVersion() { 84 | return version; 85 | } 86 | 87 | public void setVersion(Integer version) { 88 | this.version = version; 89 | } 90 | 91 | public String toString() { 92 | return ToStringBuilder.reflectionToString(this); 93 | } 94 | 95 | @PrePersist 96 | public void prePersist() { 97 | if (dateCreated == null) 98 | this.dateCreated = new Date(); 99 | if (disabled == null) 100 | this.disabled = false; 101 | if (lastUpdated == null) 102 | this.lastUpdated = this.dateCreated; 103 | if (version == null) { 104 | version = 0; 105 | } 106 | } 107 | 108 | @PreUpdate 109 | public void preUpdate() { 110 | this.lastUpdated = new Date(); 111 | if (disabled == null) 112 | this.disabled = false; 113 | } 114 | 115 | public Object copy() throws CloneNotSupportedException { 116 | return super.clone(); 117 | } 118 | 119 | } -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/schema/Clazz.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.schema; 2 | 3 | import java.util.List; 4 | 5 | import javax.persistence.CascadeType; 6 | import javax.persistence.Column; 7 | import javax.persistence.Entity; 8 | import javax.persistence.FetchType; 9 | import javax.persistence.ManyToMany; 10 | import javax.persistence.OneToMany; 11 | import javax.persistence.Table; 12 | 13 | import org.hibernate.annotations.Cache; 14 | import org.hibernate.annotations.CacheConcurrencyStrategy; 15 | import org.hibernate.annotations.DynamicInsert; 16 | import org.hibernate.annotations.DynamicUpdate; 17 | import org.hibernate.annotations.SelectBeforeUpdate; 18 | 19 | @Entity 20 | @Table(indexes = {}) 21 | @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "non-lazy") 22 | @SelectBeforeUpdate(true) 23 | @DynamicUpdate 24 | @DynamicInsert 25 | public class Clazz extends IdEntity { 26 | 27 | /** 28 | * 29 | */ 30 | private static final long serialVersionUID = 1781509012412590566L; 31 | 32 | @Column(length = 64, unique = true) 33 | String name; 34 | 35 | @OneToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY, mappedBy = "clazz") 36 | @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "non-lazy") 37 | List students; 38 | 39 | @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "non-lazy") 40 | @ManyToMany(cascade = CascadeType.REFRESH, mappedBy = "clazzs", // 通过维护端的属性关联 41 | fetch = FetchType.LAZY) 42 | List teachers; 43 | 44 | public String getName() { 45 | return name; 46 | } 47 | 48 | public void setName(String name) { 49 | this.name = name; 50 | } 51 | 52 | public List getStudents() { 53 | return students; 54 | } 55 | 56 | public void setStudents(List students) { 57 | this.students = students; 58 | } 59 | 60 | public List getTeachers() { 61 | return teachers; 62 | } 63 | 64 | public void setTeachers(List teachers) { 65 | this.teachers = teachers; 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return "Clazz [name=" + name + "]"; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/schema/IdEntity.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.schema; 2 | 3 | import java.util.UUID; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Id; 7 | import javax.persistence.MappedSuperclass; 8 | import javax.persistence.PrePersist; 9 | 10 | import org.apache.commons.lang3.builder.ToStringBuilder; 11 | 12 | /** 13 | * 抽象主键实体 14 | * 15 | * @author lujijiang 16 | * 17 | */ 18 | @MappedSuperclass 19 | public abstract class IdEntity extends BaseEntity { 20 | 21 | /** 22 | * 23 | */ 24 | private static final long serialVersionUID = -8833080406291300295L; 25 | 26 | /** 27 | * 主键 28 | */ 29 | @Id 30 | @Column(name = "id_") 31 | protected String id; 32 | 33 | public IdEntity() { 34 | 35 | } 36 | 37 | public String getId() { 38 | return id; 39 | } 40 | 41 | public void setId(String id) { 42 | this.id = id; 43 | } 44 | 45 | public int hashCode() { 46 | int hash = 0; 47 | hash += (id != null ? id.hashCode() : 0); 48 | return hash; 49 | } 50 | 51 | public boolean equals(Object object) { 52 | if (object == null) { 53 | return false; 54 | } 55 | if (!(this.getClass().isAssignableFrom(object.getClass()))) { 56 | return false; 57 | } 58 | IdEntity other = (IdEntity) object; 59 | if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) { 60 | return false; 61 | } 62 | return true; 63 | } 64 | 65 | public String toString() { 66 | return ToStringBuilder.reflectionToString(this); 67 | } 68 | 69 | @PrePersist 70 | public void prePersist() { 71 | if (id == null) { 72 | this.id = UUID.randomUUID().toString(); 73 | } 74 | super.prePersist(); 75 | } 76 | 77 | public Object copy() throws CloneNotSupportedException { 78 | return super.copy(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/schema/Student.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.schema; 2 | 3 | import java.util.List; 4 | 5 | import javax.persistence.CascadeType; 6 | import javax.persistence.Column; 7 | import javax.persistence.Entity; 8 | import javax.persistence.FetchType; 9 | import javax.persistence.ManyToMany; 10 | import javax.persistence.ManyToOne; 11 | import javax.persistence.Table; 12 | 13 | import org.hibernate.annotations.Cache; 14 | import org.hibernate.annotations.CacheConcurrencyStrategy; 15 | import org.hibernate.annotations.DynamicInsert; 16 | import org.hibernate.annotations.DynamicUpdate; 17 | import org.hibernate.annotations.SelectBeforeUpdate; 18 | 19 | import com.jpaquery.testcase.Gender; 20 | 21 | @Entity 22 | @Table(indexes = {}) 23 | @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "non-lazy") 24 | @SelectBeforeUpdate(true) 25 | @DynamicUpdate 26 | @DynamicInsert 27 | public class Student extends IdEntity { 28 | 29 | /** 30 | * 31 | */ 32 | private static final long serialVersionUID = 7288342496235362292L; 33 | 34 | @Column(length = 64, unique = true) 35 | String name; 36 | 37 | @ManyToOne(cascade = { CascadeType.REFRESH }, optional = false, fetch = FetchType.LAZY) 38 | Clazz clazz; 39 | 40 | @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "non-lazy") 41 | @ManyToMany(cascade = CascadeType.REFRESH, mappedBy = "students", // 通过维护端的属性关联 42 | fetch = FetchType.LAZY) 43 | List teachers; 44 | 45 | Gender gender; 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public void setName(String name) { 52 | this.name = name; 53 | } 54 | 55 | public Clazz getClazz() { 56 | return clazz; 57 | } 58 | 59 | public void setClazz(Clazz clazz) { 60 | this.clazz = clazz; 61 | } 62 | 63 | public List getTeachers() { 64 | return teachers; 65 | } 66 | 67 | public void setTeachers(List teachers) { 68 | this.teachers = teachers; 69 | } 70 | 71 | public Gender getGender() { 72 | return gender; 73 | } 74 | 75 | public void setGender(Gender gender) { 76 | this.gender = gender; 77 | } 78 | 79 | @Override 80 | public String toString() { 81 | return "Student [name=" + name + "]"; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/schema/Teacher.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.schema; 2 | 3 | import java.util.List; 4 | 5 | import javax.persistence.CascadeType; 6 | import javax.persistence.Column; 7 | import javax.persistence.Entity; 8 | import javax.persistence.FetchType; 9 | import javax.persistence.JoinColumn; 10 | import javax.persistence.JoinTable; 11 | import javax.persistence.ManyToMany; 12 | import javax.persistence.Table; 13 | 14 | import org.hibernate.annotations.Cache; 15 | import org.hibernate.annotations.CacheConcurrencyStrategy; 16 | import org.hibernate.annotations.DynamicInsert; 17 | import org.hibernate.annotations.DynamicUpdate; 18 | import org.hibernate.annotations.SelectBeforeUpdate; 19 | 20 | @Entity 21 | @Table(indexes = {}) 22 | @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "non-lazy") 23 | @SelectBeforeUpdate(true) 24 | @DynamicUpdate 25 | @DynamicInsert 26 | public class Teacher extends IdEntity { 27 | /** 28 | * 29 | */ 30 | private static final long serialVersionUID = -2674345024644705051L; 31 | @Column(length = 64, unique = true) 32 | String name; 33 | 34 | @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "non-lazy") 35 | @ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY) 36 | @JoinTable(joinColumns = @JoinColumn(name = "teacher_id_"), inverseJoinColumns = @JoinColumn(name = "clazz_id_")) 37 | List clazzs; 38 | 39 | @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "non-lazy") 40 | @ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY) 41 | @JoinTable(joinColumns = @JoinColumn(name = "teacher_id_"), inverseJoinColumns = @JoinColumn(name = "student_id_")) 42 | List students; 43 | 44 | public String getName() { 45 | return name; 46 | } 47 | 48 | public void setName(String name) { 49 | this.name = name; 50 | } 51 | 52 | public List getClazzs() { 53 | return clazzs; 54 | } 55 | 56 | public void setClazzs(List clazzs) { 57 | this.clazzs = clazzs; 58 | } 59 | 60 | public List getStudents() { 61 | return students; 62 | } 63 | 64 | public void setStudents(List students) { 65 | this.students = students; 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return "Teacher [name=" + name + "]"; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/schema/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.testcase.schema; -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/vo/VClazz.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.vo; 2 | 3 | public class VClazz { 4 | String name; 5 | 6 | int order; 7 | 8 | public String getName() { 9 | return name; 10 | } 11 | 12 | public void setName(String name) { 13 | this.name = name; 14 | } 15 | 16 | public int getOrder() { 17 | return order; 18 | } 19 | 20 | public void setOrder(int order) { 21 | this.order = order; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/vo/VStudent.java: -------------------------------------------------------------------------------- 1 | package com.jpaquery.testcase.vo; 2 | 3 | import com.jpaquery.testcase.Gender; 4 | 5 | public class VStudent { 6 | 7 | String name; 8 | 9 | String nickName; 10 | 11 | VClazz clazz; 12 | 13 | Gender gender; 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | 23 | public String getNickName() { 24 | return nickName; 25 | } 26 | 27 | public void setNickName(String nickName) { 28 | this.nickName = nickName; 29 | } 30 | 31 | public VClazz getClazz() { 32 | return clazz; 33 | } 34 | 35 | public void setClazz(VClazz clazz) { 36 | this.clazz = clazz; 37 | } 38 | 39 | public Gender getGender() { 40 | return gender; 41 | } 42 | 43 | public void setGender(Gender gender) { 44 | this.gender = gender; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/jpaquery/testcase/vo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author lujijiang 6 | * 7 | */ 8 | package com.jpaquery.testcase.vo; -------------------------------------------------------------------------------- /src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 11 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | --------------------------------------------------------------------------------