├── LICENSE
├── README-EN.md
├── README.md
├── pom.xml
└── src
└── main
└── java
└── com
└── littlenb
└── mybatisjpa
├── annotation
├── CodeEnum.java
├── InsertDefinition.java
├── MappedJdbcType.java
└── UpdateDefinition.java
├── keygen
├── DefaultIdGenerator.java
├── IdGenerator.java
└── IdentityKeyGenerator.java
├── rs
├── ResultMapParser.java
└── ResultTypePlugin.java
├── statement
├── AbstractStatementFactory.java
├── AnnotationStatementRegistry.java
├── InsertStatementFactory.java
├── StatementFactory.java
└── UpdateStatementFactory.java
├── support
├── AnnotationStatementScanner.java
├── Certainty.java
├── Constant.java
├── MybatisJapConfiguration.java
└── template
│ ├── InsertBatchSqlTemplate.java
│ ├── InsertCertainSqlTemplate.java
│ ├── InsertIgnoreNullSqlTemplate.java
│ ├── InsertSqlTemplate.java
│ ├── SqlTemplate.java
│ ├── UpdateCertainSqlTemplate.java
│ ├── UpdateIgnoreNullSqlTemplate.java
│ └── UpdateSqlTemplate.java
├── type
├── CodeEnumAdapter.java
├── CodeType.java
├── ICodeEnum.java
├── IntCodeEnumTypeHandler.java
├── SelectorStrategy.java
└── StringCodeEnumTypeHandler.java
└── util
├── ColumnMetaResolver.java
├── FieldReflectUtil.java
├── NamingPolicy.java
├── NamingStrategy.java
└── PersistentUtil.java
/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 [2017] [svili]
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-EN.md:
--------------------------------------------------------------------------------
1 | # mybatis-jpa
2 |
3 | [](https://maven-badges.herokuapp.com/maven-central/org.mybatis/mybatis)
4 | []()
5 | [](http://search.maven.org/#artifactdetails%7Ccom.github.cnsvili%7Cmybatis-jpa%7C2.1.3%7C)
6 | [](LICENSE)
7 |
8 | :book: English Documentation | [:book: 中文文档](README.md)
9 |
10 | The plugins for mybatis, in order to provider the ability to handler jpa.
11 |
12 | ## maven
13 |
14 | ```xml
15 |
16 | com.littlenb
17 | mybatis-jpa
18 | 2.2.0
19 |
20 | ```
21 |
22 | ## Plugin boom
23 |
24 | + ResultTypePlugin [](https://github.com/svili365/mybatis-jpa/wiki/ResultTypePlugin)
25 |
26 | Introduce the JPA annotation to handle result set mappings(JavaBean/POJO).
27 |
28 | It means with ResultTypePlugin,no longer need to be build ResultMap.
29 |
30 | + AnnotationStatementScanner [](https://github.com/svili365/mybatis-jpa/wiki/DefinitionStatementScanner)
31 |
32 | register MappedStatement with annotation-based,only support for Insert and Update.
33 |
34 |
35 | Please view test project where has more examples[mybatis-jpa-test](https://github.com/svili365/mybatis-jpa-test)
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mybatis-jpa
2 |
3 | [](https://maven-badges.herokuapp.com/maven-central/org.mybatis/mybatis)
4 | []()
5 | [](http://search.maven.org/#artifactdetails%7Ccom.github.cnsvili%7Cmybatis-jpa%7C2.1.3%7C)
6 | [](LICENSE)
7 |
8 | [:book: English Documentation](README-EN.md) | :book: 中文文档
9 |
10 | Mybatis插件,提供Mybatis处理JPA的能力.
11 |
12 | ## maven
13 |
14 | ```xml
15 |
16 | com.littlenb
17 | mybatis-jpa
18 | 2.2.0
19 |
20 | ```
21 |
22 | ## 插件清单
23 |
24 | + ResultTypePlugin [](https://github.com/svili365/mybatis-jpa/wiki/ResultTypePlugin)
25 |
26 | 对于常规的结果映射, 不需要再构建ResultMap, ResultTypePlugin按照(JavaBean/POJO)中JPA注解, 解析生成相应的ResultMap.
27 |
28 | + AnnotationStatementScanner [](https://github.com/svili365/mybatis-jpa/wiki/DefinitionStatementScanner)
29 |
30 | 注册MappedStatement, 基于注解, 仅支持Insert和Update.
31 |
32 |
33 | 更多示例请查看[mybatis-jpa-test](https://github.com/svili365/mybatis-jpa-test)
34 |
35 | ## 联系方式
36 | QQ交流群:246912326
37 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 |
6 | com.littlenb
7 | mybatis-jpa
8 | jar
9 | 2.5.1
10 |
11 | mybatis-jpa
12 | The plugins for mybatis, in order to provider the ability to handler jpa.
13 |
14 | https://github.com/svili365/mybatis-jpa
15 |
16 |
17 | UTF-8
18 | UTF-8
19 | 1.7
20 |
21 | 3.4.0
22 |
23 |
24 |
25 |
26 |
27 | javax.persistence
28 | persistence-api
29 | 1.0.2
30 |
31 |
32 |
33 | org.mybatis
34 | mybatis
35 | ${mybatis.version}
36 | provided
37 |
38 |
39 |
40 | org.reflections
41 | reflections
42 | 0.9.11
43 |
44 |
45 |
46 | com.littlenb
47 | snowflake
48 | 1.0.5
49 |
50 |
51 |
52 | junit
53 | junit
54 | 4.12
55 | test
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | org.apache.maven.plugins
65 | maven-compiler-plugin
66 | 3.7.0
67 |
68 | ${java.version}
69 | ${java.version}
70 |
71 |
72 |
73 | org.apache.maven.plugins
74 | maven-surefire-plugin
75 |
76 | true
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | ${project.basedir}
85 | META-INF
86 |
87 | LICENSE
88 | NOTICE
89 |
90 |
91 |
92 | ${project.build.sourceDirectory}
93 |
94 | **/*.java
95 |
96 |
97 |
98 |
99 |
100 | ${project.build.testSourceDirectory}
101 |
102 | **/*.java
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | The Apache Software License, Version 2.0
111 | http://www.apache.org/licenses/LICENSE-2.0.txt
112 |
113 |
114 |
115 |
116 |
117 | svili365
118 | svili365@outlook.com
119 |
120 |
121 |
122 |
123 | scm:git@github.com:svili365/mybatis-jpa.git
124 | scm:git@github.com:svili365/mybatis-jpa.git
125 | git@github.com:svili365/mybatis-jpa.git
126 |
127 |
128 |
129 |
130 | release
131 |
132 |
133 |
134 |
135 | org.apache.maven.plugins
136 | maven-source-plugin
137 | 3.0.0
138 |
139 |
140 | package
141 |
142 | jar-no-fork
143 |
144 |
145 |
146 |
147 |
148 |
149 | org.apache.maven.plugins
150 | maven-javadoc-plugin
151 | 2.10.4
152 |
153 |
154 | package
155 |
156 | jar
157 |
158 |
159 |
160 |
161 |
162 |
163 | org.apache.maven.plugins
164 | maven-gpg-plugin
165 | 1.5
166 |
167 |
168 | verify
169 |
170 | sign
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 | sonatype
180 | https://oss.sonatype.org/content/repositories/snapshots/
181 | false
182 |
183 |
184 | sonatype
185 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
186 |
187 |
188 |
189 |
190 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/annotation/CodeEnum.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.annotation;
2 |
3 | import com.littlenb.mybatisjpa.type.CodeType;
4 | import java.lang.annotation.Documented;
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * The priority is higher than Enumerated
12 | *
13 | * @author sway.li
14 | **/
15 | @Documented
16 | @Retention(RetentionPolicy.RUNTIME)
17 | @Target(ElementType.FIELD)
18 | public @interface CodeEnum {
19 |
20 | CodeType value() default CodeType.INT;
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/annotation/InsertDefinition.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.annotation;
2 |
3 | import com.littlenb.mybatisjpa.type.SelectorStrategy;
4 | import java.lang.annotation.Documented;
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * @author sway.li
12 | **/
13 | @Documented
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Target(ElementType.METHOD)
16 | public @interface InsertDefinition {
17 |
18 | SelectorStrategy strategy() default SelectorStrategy.NONE;
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/annotation/MappedJdbcType.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 | import org.apache.ibatis.type.JdbcType;
9 |
10 | /**
11 | * @author sway.li
12 | **/
13 | @Documented
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Target(ElementType.FIELD)
16 | public @interface MappedJdbcType {
17 |
18 | JdbcType value();
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/annotation/UpdateDefinition.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.annotation;
2 |
3 | import com.littlenb.mybatisjpa.type.SelectorStrategy;
4 | import java.lang.annotation.Documented;
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * @author sway.li
12 | **/
13 | @Documented
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Target(ElementType.METHOD)
16 | public @interface UpdateDefinition {
17 |
18 | SelectorStrategy strategy() default SelectorStrategy.NONE;
19 |
20 | /**
21 | * default id = #{id}
22 | */
23 | String where() default "id = #{id}";
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/keygen/DefaultIdGenerator.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.keygen;
2 |
3 |
4 | import com.littlenb.snowflake.support.SecondsIdGeneratorFactory;
5 |
6 | /**
7 | * @author sway.li
8 | * @since 2.5.1
9 | */
10 | public class DefaultIdGenerator implements IdGenerator {
11 |
12 | private com.littlenb.snowflake.sequence.IdGenerator idGenerator;
13 |
14 | private DefaultIdGenerator() {
15 | }
16 |
17 | public static DefaultIdGenerator newInstance() {
18 | // 2017-01-01 00:00:00
19 | return newInstance(1483200000L, 1L);
20 | }
21 |
22 | public static DefaultIdGenerator newInstance(long seconds, long workerId) {
23 | DefaultIdGenerator instance = new DefaultIdGenerator();
24 | SecondsIdGeneratorFactory idGeneratorFactory = new SecondsIdGeneratorFactory(seconds);
25 | instance.idGenerator = idGeneratorFactory.create(workerId);
26 | return instance;
27 | }
28 |
29 | @Override
30 | public synchronized Object nextId() {
31 | return idGenerator.nextId();
32 | }
33 |
34 | @Override
35 | public synchronized Object[] nextSegment(int size) {
36 | long[] segment = idGenerator.nextSegment(size);
37 | Object[] array = new Object[size];
38 | for (int i = 0; i < size; i++) {
39 | array[i] = segment[i];
40 | }
41 | return array;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/keygen/IdGenerator.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.keygen;
2 |
3 | /**
4 | * @author sway.li
5 | */
6 | public interface IdGenerator {
7 |
8 | Object nextId();
9 |
10 | Object[] nextSegment(int size);
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/keygen/IdentityKeyGenerator.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.keygen;
2 |
3 | import java.sql.Statement;
4 | import java.util.Arrays;
5 | import java.util.Collection;
6 | import java.util.Iterator;
7 | import java.util.List;
8 | import java.util.Map;
9 | import org.apache.ibatis.executor.Executor;
10 | import org.apache.ibatis.executor.ExecutorException;
11 | import org.apache.ibatis.executor.keygen.KeyGenerator;
12 | import org.apache.ibatis.mapping.MappedStatement;
13 | import org.apache.ibatis.reflection.MetaObject;
14 | import org.apache.ibatis.session.Configuration;
15 |
16 | /**
17 | * @author sway.li
18 | */
19 | public class IdentityKeyGenerator implements KeyGenerator {
20 |
21 | private IdGenerator idGenerator;
22 |
23 | public IdentityKeyGenerator(IdGenerator idGenerator) {
24 | this.idGenerator = idGenerator;
25 | }
26 |
27 | @Override
28 | public void processBefore(Executor executor, MappedStatement ms, Statement stmt,
29 | Object parameter) {
30 | processGeneratedKeys(ms, stmt, parameter);
31 | }
32 |
33 | @Override
34 | public void processAfter(Executor executor, MappedStatement ms, Statement stmt,
35 | Object parameter) {
36 | // do nothing
37 | }
38 |
39 | public void processGeneratedKeys(MappedStatement ms, Statement stmt, Object parameter) {
40 | final String[] keyProperties = ms.getKeyProperties();
41 | if (keyProperties == null || keyProperties.length == 0) {
42 | return;
43 | }
44 | if (keyProperties.length > 1) {
45 | throw new ExecutorException(
46 | "There are more than one keyProperty in MappedStatement : " + ms.getId() + ".");
47 | }
48 |
49 | if (parameter instanceof Collection) {
50 | handleCollection(ms, stmt, (Collection) parameter);
51 | } else if (parameter.getClass().isArray()) {
52 | handleCollection(ms, stmt, Arrays.asList(parameter));
53 | } else if (parameter instanceof Map) {
54 | Map parameterMap = (Map) parameter;
55 | if (parameterMap.containsKey("collection")) {
56 | handleCollection(ms, stmt, (Collection) parameterMap.get("collection"));
57 | } else if (parameterMap.containsKey("list")) {
58 | handleCollection(ms, stmt, (List) parameterMap.get("list"));
59 | } else if (parameterMap.containsKey("array")) {
60 | handleCollection(ms, stmt, Arrays.asList((Object[]) parameterMap.get("array")));
61 | }
62 | } else {
63 | handleObject(ms, stmt, parameter, idGenerator.nextId());
64 | }
65 | }
66 |
67 | private void handleCollection(MappedStatement ms, Statement stmt, Collection collection) {
68 | if (collection.isEmpty()) {
69 | return;
70 | }
71 | int size = collection.size();
72 | Object[] idArray = idGenerator.nextSegment(size);
73 |
74 | Iterator iterator = collection.iterator();
75 | for (int i = 0; i < size; i++) {
76 | Object parameter = iterator.next();
77 | Object id = idArray[i];
78 | handleObject(ms, stmt, parameter, id);
79 | }
80 | }
81 |
82 | private void handleObject(MappedStatement ms, Statement stmt, Object parameter, Object idValue) {
83 | final String[] keyProperties = ms.getKeyProperties();
84 | final Configuration configuration = ms.getConfiguration();
85 | final MetaObject metaParam = configuration.newMetaObject(parameter);
86 | setValue(metaParam, keyProperties[0], idValue);
87 | }
88 |
89 | private void setValue(MetaObject metaParam, String property, Object value) {
90 | if (metaParam.hasSetter(property)) {
91 | metaParam.setValue(property, value);
92 | } else {
93 | throw new ExecutorException(
94 | "No setter found for the keyProperty '" + property + "' in " + metaParam
95 | .getOriginalObject().getClass().getName() + ".");
96 | }
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/rs/ResultMapParser.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.rs;
2 |
3 | import com.littlenb.mybatisjpa.util.ColumnMetaResolver;
4 | import com.littlenb.mybatisjpa.util.PersistentUtil;
5 | import java.lang.reflect.Field;
6 | import java.lang.reflect.ParameterizedType;
7 | import java.lang.reflect.Type;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.concurrent.ConcurrentHashMap;
11 | import javax.persistence.Id;
12 | import javax.persistence.OneToMany;
13 | import javax.persistence.OneToOne;
14 | import org.apache.ibatis.builder.MapperBuilderAssistant;
15 | import org.apache.ibatis.mapping.ResultFlag;
16 | import org.apache.ibatis.mapping.ResultMap;
17 | import org.apache.ibatis.mapping.ResultMapping;
18 | import org.apache.ibatis.session.Configuration;
19 | import org.apache.ibatis.type.JdbcType;
20 | import org.apache.ibatis.type.TypeHandler;
21 |
22 | /**
23 | * @author sway.li
24 | */
25 | public class ResultMapParser {
26 |
27 | private Configuration configuration;
28 |
29 | /**
30 | * Result Maps collection,key : id
31 | */
32 | private ConcurrentHashMap resultMaps = new ConcurrentHashMap<>();
33 |
34 | public ResultMapParser(Configuration configuration) {
35 | this.configuration = configuration;
36 | }
37 |
38 | public ResultMap reloadResultMap(String resource, String id, Class> type) {
39 | if (!resultMaps.containsKey(id)) {
40 | resultMaps.put(id, resolveResultMap(resource, id, type));
41 | }
42 |
43 | return resultMaps.get(id);
44 | }
45 |
46 | public void registerResultMap(ResultMap resultMap) {
47 | configuration.addResultMap(resultMap);
48 | }
49 |
50 | public ResultMap resolveResultMap(String resource, String id, Class> type) {
51 | List resultMappings = resolveResultMappings(resource, id, type);
52 | return new ResultMap.Builder(configuration, id, type, resultMappings).build();
53 | }
54 |
55 | public List resolveResultMappings(String resource, String id, Class> type) {
56 | List resultMappings = new ArrayList<>();
57 |
58 | MapperBuilderAssistant assistant = new MapperBuilderAssistant(configuration, resource);
59 |
60 | List fields = PersistentUtil.getPersistentFields(type);
61 |
62 | for (Field field : fields) {
63 | // java field name
64 | String property = field.getName();
65 | // sql column name
66 | String column = PersistentUtil.getColumnName(field);
67 | Class> javaType = field.getType();
68 |
69 | //resultMap is not need jdbcType
70 | JdbcType jdbcType = null;
71 |
72 | String nestedSelect = null;
73 | String nestedResultMap = null;
74 | if (PersistentUtil.isAssociationField(field)) {
75 | // OneToOne or OneToMany
76 |
77 | // mappedBy
78 | column = PersistentUtil.getMappedName(field);
79 | if (field.isAnnotationPresent(OneToOne.class)) {
80 | nestedResultMap = id + "_association[" + javaType.getSimpleName() + "]";
81 | registerResultMap(resolveResultMap(resource, nestedResultMap, javaType));
82 | }
83 | if (field.isAnnotationPresent(OneToMany.class)) {
84 | Type genericType = field.getGenericType();
85 | if (genericType instanceof ParameterizedType) {
86 | ParameterizedType pt = (ParameterizedType) genericType;
87 | Class> actualType = (Class>) pt.getActualTypeArguments()[0];
88 | // create resultMap with actualType
89 | nestedResultMap = id + "collection[" + actualType.getSimpleName() + "]";
90 | registerResultMap(resolveResultMap(resource, nestedResultMap, actualType));
91 | }
92 | }
93 | }
94 |
95 | String notNullColumn = null;
96 | String columnPrefix = null;
97 | String resultSet = null;
98 | String foreignColumn = null;
99 | // if primaryKey,then flags.add(ResultFlag.ID);
100 | List flags = new ArrayList<>();
101 | if (field.isAnnotationPresent(Id.class)) {
102 | flags.add(ResultFlag.ID);
103 | }
104 | // lazy or eager
105 | boolean lazy = false;
106 | // typeHandler
107 | Class extends TypeHandler>> typeHandlerClass = ColumnMetaResolver
108 | .resolveTypeHandler(field);
109 |
110 | ResultMapping resultMapping = assistant.buildResultMapping(type, property, column,
111 | javaType, jdbcType, nestedSelect, nestedResultMap, notNullColumn, columnPrefix,
112 | typeHandlerClass, flags, resultSet, foreignColumn, lazy);
113 | resultMappings.add(resultMapping);
114 | }
115 | return resultMappings;
116 |
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/rs/ResultTypePlugin.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.rs;
2 |
3 | import com.littlenb.mybatisjpa.util.FieldReflectUtil;
4 | import java.sql.Statement;
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.List;
8 | import java.util.Map;
9 | import java.util.Properties;
10 | import javax.persistence.Entity;
11 | import javax.persistence.Table;
12 | import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
13 | import org.apache.ibatis.executor.resultset.ResultSetHandler;
14 | import org.apache.ibatis.mapping.MappedStatement;
15 | import org.apache.ibatis.mapping.ResultMap;
16 | import org.apache.ibatis.plugin.Interceptor;
17 | import org.apache.ibatis.plugin.Intercepts;
18 | import org.apache.ibatis.plugin.Invocation;
19 | import org.apache.ibatis.plugin.Plugin;
20 | import org.apache.ibatis.plugin.Signature;
21 | import org.apache.ibatis.session.Configuration;
22 |
23 | /**
24 | * @author sway.li
25 | **/
26 | @Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {
27 | Statement.class})})
28 | public class ResultTypePlugin implements Interceptor {
29 |
30 | @Override
31 | public Object intercept(Invocation invocation) throws Throwable {
32 | if (invocation.getTarget() instanceof DefaultResultSetHandler) {
33 | DefaultResultSetHandler resultSetHandler = (DefaultResultSetHandler) invocation.getTarget();
34 |
35 | Object[] args = invocation.getArgs();
36 | Statement stmt = (Statement) args[0];
37 |
38 | MappedStatement mappedStatement = (MappedStatement) FieldReflectUtil
39 | .getFieldValue(resultSetHandler, "mappedStatement");
40 |
41 | List resultMaps = mappedStatement.getResultMaps();
42 |
43 | if (resultMaps != null && !resultMaps.isEmpty()) {
44 | ResultMap resultMap = resultMaps.get(0);
45 |
46 | if (resultMap.getResultMappings() == null || resultMap.getResultMappings().isEmpty()) {
47 | if (resultMap.getType().isAnnotationPresent(Entity.class) || resultMap.getType()
48 | .isAnnotationPresent(Table.class)) {
49 |
50 | ResultMapParser parser = ResultMapParserHolder
51 | .getInstance(mappedStatement.getConfiguration());
52 | ResultMap newResultMap = parser
53 | .reloadResultMap(mappedStatement.getResource(), resultMap.getId(),
54 | resultMap.getType());
55 |
56 | List newResultMaps = new ArrayList<>();
57 | newResultMaps.add(newResultMap);
58 |
59 | FieldReflectUtil.setFieldValue(mappedStatement, "resultMaps", newResultMaps);
60 |
61 | // modify the resultMaps
62 | FieldReflectUtil.setFieldValue(resultSetHandler, "mappedStatement", mappedStatement);
63 | }
64 | }
65 | }
66 |
67 | // return resultSetHandler.handleResultSets(stmt);
68 | }
69 | return invocation.proceed();
70 | }
71 |
72 | @Override
73 | public Object plugin(Object target) {
74 | return Plugin.wrap(target, this);
75 | }
76 |
77 | @Override
78 | public void setProperties(Properties properties) {
79 |
80 | }
81 |
82 | /**
83 | * Use static inner classes ensure thread safety
84 | */
85 | private static class ResultMapParserHolder {
86 |
87 | private static Map parsers = new HashMap<>();
88 |
89 | static ResultMapParser getInstance(Configuration configuration) {
90 | String id = configuration.getEnvironment().getId();
91 | if (!parsers.containsKey(id)) {
92 | parsers.put(id, new ResultMapParser(configuration));
93 | }
94 | return parsers.get(id);
95 | }
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/statement/AbstractStatementFactory.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.statement;
2 |
3 | import java.lang.reflect.Method;
4 | import java.lang.reflect.ParameterizedType;
5 | import java.lang.reflect.Type;
6 | import java.util.Collection;
7 | import sun.reflect.generics.reflectiveObjects.TypeVariableImpl;
8 |
9 | /**
10 | * @author sway.li
11 | */
12 | public abstract class AbstractStatementFactory implements StatementFactory {
13 |
14 | protected String recognizeResource(String targetClassName) {
15 | return targetClassName.replace(".", "/") + ".java (best guess)";
16 | }
17 |
18 | protected Class> recognizeEntityType(Method method, Class> targetClass) {
19 | Type[] genericTypes = method.getGenericParameterTypes();
20 | Type genericType = genericTypes[0];
21 |
22 | if (genericType instanceof TypeVariableImpl) {
23 | // interface XXXMapper extends IBaseMapper
24 | Type[] interfaces = targetClass.getGenericInterfaces();
25 | for (Type type : interfaces) {
26 | if (type instanceof ParameterizedType) {
27 | ParameterizedType pt = (ParameterizedType) type;
28 | return (Class>) pt.getActualTypeArguments()[0];
29 | }
30 | }
31 | }
32 |
33 | if (genericType instanceof ParameterizedType) {
34 | ParameterizedType pt = (ParameterizedType) genericType;
35 | if (pt.getActualTypeArguments()[0] instanceof TypeVariableImpl) {
36 | // interface XXXMapper extends IBaseMapper
37 | // insert(List list)
38 | Type[] interfaces = targetClass.getGenericInterfaces();
39 | for (Type type : interfaces) {
40 | if (type instanceof ParameterizedType) {
41 | ParameterizedType pt2 = (ParameterizedType) type;
42 | return (Class>) pt2.getActualTypeArguments()[0];
43 | }
44 | }
45 | }
46 | }
47 |
48 | Class> actualType;
49 | if (genericType instanceof ParameterizedType) {
50 | ParameterizedType pt = (ParameterizedType) genericType;
51 | actualType = (Class>) pt.getActualTypeArguments()[0];
52 | } else {
53 | actualType = (Class>) genericType;
54 | }
55 | return actualType;
56 | }
57 |
58 | protected boolean isCollectionParameter(Method method) {
59 | Class>[] parameterTypes = method.getParameterTypes();
60 | if (parameterTypes == null || parameterTypes.length == 0) {
61 | return false;
62 | }
63 | Class> clazz = parameterTypes[0];
64 | return Collection.class.isAssignableFrom(clazz);
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/statement/AnnotationStatementRegistry.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.statement;
2 |
3 | import com.littlenb.mybatisjpa.annotation.InsertDefinition;
4 | import com.littlenb.mybatisjpa.annotation.UpdateDefinition;
5 | import java.lang.annotation.Annotation;
6 | import java.util.Collections;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | /**
11 | * @author sway.li
12 | */
13 | public class AnnotationStatementRegistry {
14 |
15 | private Map, StatementFactory> REGISTERS = new HashMap<>();
16 |
17 | public static AnnotationStatementRegistry getDefaultRegistry() {
18 | AnnotationStatementRegistry registry = new AnnotationStatementRegistry();
19 | registry.register(InsertDefinition.class, InsertStatementFactory.INSTANCE);
20 | registry.register(UpdateDefinition.class, UpdateStatementFactory.INSTANCE);
21 | return registry;
22 | }
23 |
24 | public void register(Class extends Annotation> annotationType, StatementFactory factory) {
25 | if (annotationType == null) {
26 | throw new IllegalArgumentException("The parameter 'annotationType' cannot be null.");
27 | }
28 | if (factory == null) {
29 | throw new IllegalArgumentException("The parameter 'factory' cannot be null.");
30 | }
31 | REGISTERS.put(annotationType, factory);
32 | }
33 |
34 | public Map, StatementFactory> getRegisters() {
35 | return Collections.unmodifiableMap(REGISTERS);
36 | }
37 |
38 | public StatementFactory findFactory(Class extends Annotation> annotationType) {
39 | if (annotationType == null) {
40 | return null;
41 | }
42 |
43 | return REGISTERS.get(annotationType);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/statement/InsertStatementFactory.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.statement;
2 |
3 | import com.littlenb.mybatisjpa.annotation.InsertDefinition;
4 | import com.littlenb.mybatisjpa.support.Constant;
5 | import com.littlenb.mybatisjpa.support.template.InsertBatchSqlTemplate;
6 | import com.littlenb.mybatisjpa.support.template.InsertCertainSqlTemplate;
7 | import com.littlenb.mybatisjpa.support.template.InsertIgnoreNullSqlTemplate;
8 | import com.littlenb.mybatisjpa.support.template.InsertSqlTemplate;
9 | import com.littlenb.mybatisjpa.type.SelectorStrategy;
10 | import com.littlenb.mybatisjpa.util.FieldReflectUtil;
11 | import com.littlenb.mybatisjpa.util.PersistentUtil;
12 | import java.lang.reflect.Field;
13 | import java.lang.reflect.Method;
14 | import java.util.List;
15 | import javax.persistence.GeneratedValue;
16 | import javax.persistence.GenerationType;
17 | import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
18 | import org.apache.ibatis.executor.keygen.KeyGenerator;
19 | import org.apache.ibatis.mapping.MappedStatement;
20 | import org.apache.ibatis.mapping.SqlCommandType;
21 | import org.apache.ibatis.mapping.SqlSource;
22 | import org.apache.ibatis.mapping.StatementType;
23 | import org.apache.ibatis.scripting.LanguageDriver;
24 | import org.apache.ibatis.session.Configuration;
25 |
26 | /**
27 | * @author sway.li
28 | */
29 | public class InsertStatementFactory extends AbstractStatementFactory {
30 |
31 | public static final StatementFactory INSTANCE = new InsertStatementFactory();
32 |
33 | @Override
34 | public MappedStatement parseStatement(Configuration configuration, Method method,
35 | Class> targetClass) {
36 | String resourceName = targetClass.toString();
37 |
38 | if (!configuration.isResourceLoaded(resourceName)) {
39 | configuration.addLoadedResource(resourceName);
40 | }
41 | String targetClassName = targetClass.getName();
42 | Class> type = super.recognizeEntityType(method, targetClass);
43 | LanguageDriver languageDriver = Constant.XML_LANGUAGE_DRIVER;
44 | SqlSource sqlSource = languageDriver
45 | .createSqlSource(configuration, "",
46 | Object.class);
47 | String statementId = targetClassName + "." + method.getName();
48 | MappedStatement.Builder builder = new MappedStatement.Builder(configuration, statementId,
49 | sqlSource, SqlCommandType.INSERT);
50 | builder.resource(super.recognizeResource(targetClassName)).lang(languageDriver)
51 | .statementType(StatementType.PREPARED);
52 |
53 | // keyGenerator
54 | List fields = FieldReflectUtil.findFields(type, GeneratedValue.class);
55 | for (Field generatedField : fields) {
56 | String keyProperty = generatedField.getName();
57 | if (SelectorStrategy.CERTAIN.equals(recognizeStrategy(method))) {
58 | keyProperty = Constant.CERTAINTY_ENTITY_KEY + "." + keyProperty;
59 | }
60 | if (generatedField.isAnnotationPresent(GeneratedValue.class)) {
61 | GeneratedValue generatedValue = generatedField.getAnnotation(GeneratedValue.class);
62 | if (GenerationType.AUTO.equals(generatedValue.strategy())) {
63 | builder.keyGenerator(new Jdbc3KeyGenerator()).keyProperty(keyProperty)
64 | .keyColumn(PersistentUtil.getColumnName(generatedField));
65 | } else if (GenerationType.IDENTITY.equals(generatedValue.strategy())) {
66 | String generator = "".equals(generatedValue.generator()) ? Constant.DEFAULT_KEY_GENERATOR
67 | : generatedValue.generator();
68 | KeyGenerator keyGenerator = configuration.getKeyGenerator(generator);
69 | if (keyGenerator == null) {
70 | throw new IllegalArgumentException(
71 | "mybatisjpa init failure , can not find '" + generator + "' in configuration.");
72 | }
73 | builder.keyGenerator(keyGenerator).keyProperty(keyProperty)
74 | .keyColumn(PersistentUtil.getColumnName(generatedField));
75 | }
76 | }
77 | }
78 |
79 | return builder.build();
80 | }
81 |
82 | private String parseSQL(Method method, Class> type) {
83 | SelectorStrategy strategy = recognizeStrategy(method);
84 | if (SelectorStrategy.IGNORE_NULL.equals(strategy)) {
85 | return InsertIgnoreNullSqlTemplate.INSTANCE.parseSQL(type);
86 | }
87 |
88 | if (SelectorStrategy.CERTAIN.equals(strategy)) {
89 | return InsertCertainSqlTemplate.INSTANCE.parseSQL(type);
90 | }
91 |
92 | if (isCollectionParameter(method)) {
93 | return InsertBatchSqlTemplate.INSTANCE.parseSQL(type);
94 | }
95 |
96 | return InsertSqlTemplate.INSTANCE.parseSQL(type);
97 | }
98 |
99 | private SelectorStrategy recognizeStrategy(Method method) {
100 | InsertDefinition insertDefinition = method.getAnnotation(InsertDefinition.class);
101 | if (insertDefinition == null) {
102 | throw new RuntimeException(
103 | "'" + method.getName() + "' method is not annotation with 'InsertDefinition'.");
104 | }
105 | return insertDefinition.strategy();
106 | }
107 |
108 | }
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/statement/StatementFactory.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.statement;
2 |
3 | import java.lang.reflect.Method;
4 | import org.apache.ibatis.mapping.MappedStatement;
5 | import org.apache.ibatis.session.Configuration;
6 |
7 | /**
8 | * @author sway.li
9 | **/
10 | public interface StatementFactory {
11 |
12 | MappedStatement parseStatement(Configuration configuration, Method method, Class> targetClass);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/statement/UpdateStatementFactory.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.statement;
2 |
3 | import com.littlenb.mybatisjpa.annotation.UpdateDefinition;
4 | import com.littlenb.mybatisjpa.support.Constant;
5 | import com.littlenb.mybatisjpa.support.template.UpdateCertainSqlTemplate;
6 | import com.littlenb.mybatisjpa.support.template.UpdateIgnoreNullSqlTemplate;
7 | import com.littlenb.mybatisjpa.support.template.UpdateSqlTemplate;
8 | import com.littlenb.mybatisjpa.type.SelectorStrategy;
9 | import java.lang.reflect.Method;
10 | import org.apache.ibatis.mapping.MappedStatement;
11 | import org.apache.ibatis.mapping.SqlCommandType;
12 | import org.apache.ibatis.mapping.SqlSource;
13 | import org.apache.ibatis.mapping.StatementType;
14 | import org.apache.ibatis.scripting.LanguageDriver;
15 | import org.apache.ibatis.session.Configuration;
16 |
17 | /**
18 | * @author sway.li
19 | */
20 | public class UpdateStatementFactory extends AbstractStatementFactory {
21 |
22 | public static final StatementFactory INSTANCE = new UpdateStatementFactory();
23 |
24 | @Override
25 | public MappedStatement parseStatement(Configuration configuration, Method method,
26 | Class> targetClass) {
27 | String resourceName = targetClass.toString();
28 |
29 | if (!configuration.isResourceLoaded(resourceName)) {
30 | configuration.addLoadedResource(resourceName);
31 | }
32 | String targetClassName = targetClass.getName();
33 | Class> type = super.recognizeEntityType(method, targetClass);
34 | LanguageDriver languageDriver = Constant.XML_LANGUAGE_DRIVER;
35 | SqlSource sqlSource = languageDriver
36 | .createSqlSource(configuration, "",
37 | Object.class);
38 | String statementId = targetClassName + "." + method.getName();
39 | MappedStatement.Builder builder = new MappedStatement.Builder(configuration, statementId,
40 | sqlSource, SqlCommandType.UPDATE);
41 | builder.resource(super.recognizeResource(targetClassName)).lang(languageDriver)
42 | .statementType(StatementType.PREPARED);
43 |
44 | return builder.build();
45 | }
46 |
47 | private String parseSQL(Method method, Class> type) {
48 | UpdateDefinition updateDefinition = method.getAnnotation(UpdateDefinition.class);
49 | if (updateDefinition == null) {
50 | throw new RuntimeException(
51 | "'" + method.getName() + "' method is not annotation with 'UpdateDefinition'.");
52 | }
53 | SelectorStrategy strategy = updateDefinition.strategy();
54 |
55 | String sql = "";
56 |
57 | if (SelectorStrategy.NONE.equals(strategy)) {
58 | sql = UpdateSqlTemplate.INSTANCE.parseSQL(type);
59 | }
60 |
61 | if (SelectorStrategy.IGNORE_NULL.equals(strategy)) {
62 | sql = UpdateIgnoreNullSqlTemplate.INSTANCE.parseSQL(type);
63 | }
64 |
65 | if (SelectorStrategy.CERTAIN.equals(strategy)) {
66 | sql = UpdateCertainSqlTemplate.INSTANCE.parseSQL(type);
67 | }
68 |
69 | if (!"".equals(updateDefinition.where())) {
70 | sql = sql + " WHERE " + updateDefinition.where();
71 | }
72 |
73 | return sql;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/AnnotationStatementScanner.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support;
2 |
3 | import com.littlenb.mybatisjpa.statement.AnnotationStatementRegistry;
4 | import com.littlenb.mybatisjpa.statement.StatementFactory;
5 | import java.lang.annotation.Annotation;
6 | import java.lang.reflect.Method;
7 | import java.util.Collection;
8 | import java.util.Iterator;
9 | import java.util.Set;
10 | import org.apache.ibatis.annotations.Mapper;
11 | import org.apache.ibatis.builder.IncompleteElementException;
12 | import org.apache.ibatis.builder.annotation.MethodResolver;
13 | import org.apache.ibatis.mapping.MappedStatement;
14 | import org.apache.ibatis.session.Configuration;
15 | import org.reflections.Reflections;
16 | import org.reflections.scanners.MethodAnnotationsScanner;
17 | import org.reflections.scanners.SubTypesScanner;
18 | import org.reflections.scanners.TypeAnnotationsScanner;
19 |
20 | /**
21 | * @author sway.li
22 | **/
23 | public class AnnotationStatementScanner {
24 |
25 | private Configuration configuration;
26 |
27 | private String[] basePackages;
28 |
29 | private AnnotationStatementRegistry annotationStatementRegistry;
30 |
31 | public void scan() {
32 | for (String basePackage : basePackages) {
33 | Reflections reflections = new Reflections(basePackage, new TypeAnnotationsScanner(),
34 | new SubTypesScanner(), new MethodAnnotationsScanner());
35 | Set> mappers = reflections.getTypesAnnotatedWith(Mapper.class);
36 | for (Class> mapperClass : mappers) {
37 | Method[] methods = mapperClass.getMethods();
38 | for (Method method : methods) {
39 | Annotation[] annotations = method.getDeclaredAnnotations();
40 | for (Annotation annotation : annotations) {
41 | StatementFactory statementFactory = annotationStatementRegistry
42 | .findFactory(annotation.annotationType());
43 | if (statementFactory != null) {
44 | MappedStatement statement = statementFactory.parseStatement(configuration, method, mapperClass);
45 | configuration.addMappedStatement(statement);
46 | }
47 | }
48 |
49 | }
50 | }
51 | }
52 | parsePendingMethods();
53 | }
54 |
55 | private void parsePendingMethods() {
56 | Collection incompleteMethods = configuration.getIncompleteMethods();
57 | synchronized (incompleteMethods) {
58 | Iterator iter = incompleteMethods.iterator();
59 | while (iter.hasNext()) {
60 | try {
61 | iter.next().resolve();
62 | iter.remove();
63 | } catch (IncompleteElementException e) {
64 | // This method is still missing a resource
65 | }
66 | }
67 | }
68 | }
69 |
70 | public static class Builder {
71 |
72 | private AnnotationStatementScanner instance = new AnnotationStatementScanner();
73 |
74 | public Builder() {
75 | }
76 |
77 | public Builder configuration(Configuration configuration) {
78 | this.instance.configuration = configuration;
79 | return this;
80 | }
81 |
82 | public Builder basePackages(String[] basePackages) {
83 | this.instance.basePackages = basePackages;
84 | return this;
85 | }
86 |
87 | public Builder annotationStatementRegistry(AnnotationStatementRegistry annotationStatementRegistry) {
88 | this.instance.annotationStatementRegistry = annotationStatementRegistry;
89 | return this;
90 | }
91 |
92 | public AnnotationStatementScanner build() {
93 | return this.instance;
94 | }
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/Certainty.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support;
2 |
3 | import java.util.Collections;
4 | import java.util.Set;
5 |
6 | /**
7 | * @author sway.li
8 | */
9 | public class Certainty {
10 |
11 | private E entity;
12 |
13 | private Set includes;
14 |
15 | private Set excludes;
16 |
17 | public Certainty() {
18 | }
19 |
20 | public static Certainty includes(T entity, Set fields) {
21 | Certainty certainty = new Certainty<>();
22 | certainty.entity = entity;
23 | certainty.includes = fields;
24 | certainty.excludes = Collections.emptySet();
25 | return certainty;
26 | }
27 |
28 | public static Certainty excludes(T entity, Set fields) {
29 | Certainty certainty = new Certainty<>();
30 | certainty.entity = entity;
31 | certainty.includes = Collections.emptySet();
32 | certainty.excludes = fields;
33 | return certainty;
34 | }
35 |
36 | // getter
37 |
38 | public E getEntity() {
39 | return entity;
40 | }
41 |
42 | public Set getIncludes() {
43 | return includes;
44 | }
45 |
46 | public Set getExcludes() {
47 | return excludes;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/Constant.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support;
2 |
3 | import org.apache.ibatis.scripting.LanguageDriver;
4 | import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
5 |
6 | /**
7 | * @author sway.li
8 | */
9 | public interface Constant {
10 |
11 | LanguageDriver XML_LANGUAGE_DRIVER = new XMLLanguageDriver();
12 |
13 | String DEFAULT_KEY_GENERATOR = "defaultKeyGenerator";
14 |
15 | String CERTAINTY_ENTITY_KEY = "entity";
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/MybatisJapConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support;
2 |
3 | import com.littlenb.mybatisjpa.util.NamingPolicy;
4 | import com.littlenb.mybatisjpa.util.NamingStrategy;
5 |
6 | /**
7 | * @author sway.li
8 | */
9 | public class MybatisJapConfiguration {
10 |
11 | private NamingStrategy tableNamingStrategy = NamingPolicy.IDENTITY;
12 |
13 | private NamingStrategy columnNamingStrategy = NamingPolicy.IDENTITY;
14 |
15 | private MybatisJapConfiguration(){
16 | }
17 |
18 | public static MybatisJapConfiguration getInstance(){
19 | return Holder.instance;
20 | }
21 |
22 | private static class Holder{
23 | private static MybatisJapConfiguration instance = new MybatisJapConfiguration();
24 | }
25 |
26 | public NamingStrategy getTableNamingStrategy() {
27 | return tableNamingStrategy;
28 | }
29 |
30 | public void setTableNamingStrategy(NamingStrategy tableNamingStrategy) {
31 | this.tableNamingStrategy = tableNamingStrategy;
32 | }
33 |
34 | public NamingStrategy getColumnNamingStrategy() {
35 | return columnNamingStrategy;
36 | }
37 |
38 | public void setColumnNamingStrategy(NamingStrategy columnNamingStrategy) {
39 | this.columnNamingStrategy = columnNamingStrategy;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/template/InsertBatchSqlTemplate.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support.template;
2 |
3 | import com.littlenb.mybatisjpa.util.ColumnMetaResolver;
4 | import com.littlenb.mybatisjpa.util.PersistentUtil;
5 | import java.lang.reflect.Field;
6 |
7 | /**
8 | * @author sway.li
9 | **/
10 | public class InsertBatchSqlTemplate implements SqlTemplate {
11 |
12 | public static final SqlTemplate INSTANCE = new InsertBatchSqlTemplate();
13 |
14 | @Override
15 | public String parseSQL(final Class> type) {
16 | // columns
17 | StringBuilder columns = new StringBuilder();
18 | columns.append(" ");
19 | // values
20 | StringBuilder values = new StringBuilder();
21 | values.append(" ");
22 |
23 | for (Field field : PersistentUtil.getPersistentFields(type)) {
24 | if (!PersistentUtil.insertable(field)) {
25 | continue;
26 | }
27 | // columns
28 | columns.append(PersistentUtil.getColumnName(field)).append(", ");
29 | // values
30 | values.append(ColumnMetaResolver.resolveSqlPlaceholder(field, "data")).append(", ");
31 | }
32 |
33 | columns.append(" ");
34 | values.append(" ");
35 |
36 | return "INSERT INTO " + PersistentUtil.getTableName(type) + columns.toString() + " VALUES "
37 | + "" + values.toString()
38 | + "";
39 | }
40 | }
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/template/InsertCertainSqlTemplate.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support.template;
2 |
3 | import com.littlenb.mybatisjpa.support.Constant;
4 | import com.littlenb.mybatisjpa.util.ColumnMetaResolver;
5 | import com.littlenb.mybatisjpa.util.PersistentUtil;
6 | import java.lang.reflect.Field;
7 |
8 | /**
9 | * @author sway.li
10 | **/
11 | public class InsertCertainSqlTemplate implements SqlTemplate {
12 |
13 | public static final SqlTemplate INSTANCE = new InsertCertainSqlTemplate();
14 |
15 | @Override
16 | public String parseSQL(Class> type) {
17 | // columns
18 | StringBuilder columns = new StringBuilder();
19 | columns.append(" ");
20 | // values
21 | StringBuilder values = new StringBuilder();
22 | values.append(" ");
23 |
24 | for (Field field : PersistentUtil.getPersistentFields(type)) {
25 | if (!PersistentUtil.insertable(field)) {
26 | continue;
27 | }
28 | // columns
29 | columns.append(String.format(
30 | " ",
31 | field.getName()
32 | ));
33 | columns.append(PersistentUtil.getColumnName(field)).append(", ");
34 | columns.append(" ");
35 | // values
36 | values.append(String.format(
37 | " ",
38 | field.getName()
39 | ));
40 | values.append(
41 | ColumnMetaResolver.resolveSqlPlaceholder(field, Constant.CERTAINTY_ENTITY_KEY))
42 | .append(", ");
43 | values.append(" ");
44 | }
45 |
46 | columns.append(" ");
47 | values.append(" ");
48 |
49 | return "INSERT INTO " + PersistentUtil.getTableName(type) + columns.toString() + " VALUES "
50 | + values.toString();
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/template/InsertIgnoreNullSqlTemplate.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support.template;
2 |
3 | import com.littlenb.mybatisjpa.util.ColumnMetaResolver;
4 | import com.littlenb.mybatisjpa.util.PersistentUtil;
5 | import java.lang.reflect.Field;
6 |
7 | /**
8 | * @author sway.li
9 | **/
10 | public class InsertIgnoreNullSqlTemplate implements SqlTemplate {
11 |
12 | public static final SqlTemplate INSTANCE = new InsertIgnoreNullSqlTemplate();
13 |
14 | @Override
15 | public String parseSQL(Class> type) {
16 | // columns
17 | StringBuilder columns = new StringBuilder();
18 | columns.append(" ");
19 | // values
20 | StringBuilder values = new StringBuilder();
21 | values.append(" ");
22 |
23 | for (Field field : PersistentUtil.getPersistentFields(type)) {
24 | // columns
25 | columns.append(" ");
26 | columns.append(PersistentUtil.getColumnName(field) + ", ");
27 | columns.append(" ");
28 | // values
29 | values.append(" ");
30 | values.append(ColumnMetaResolver.resolveSqlPlaceholder(field) + ", ");
31 | values.append(" ");
32 | }
33 |
34 | columns.append(" ");
35 | values.append(" ");
36 |
37 | return "INSERT INTO " + PersistentUtil.getTableName(type) + columns.toString() + " VALUES "
38 | + values.toString();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/template/InsertSqlTemplate.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support.template;
2 |
3 | import com.littlenb.mybatisjpa.util.ColumnMetaResolver;
4 | import com.littlenb.mybatisjpa.util.PersistentUtil;
5 | import java.lang.reflect.Field;
6 | import org.apache.ibatis.jdbc.SQL;
7 |
8 | /**
9 | * @author sway.li
10 | **/
11 | public class InsertSqlTemplate implements SqlTemplate {
12 |
13 | public static final SqlTemplate INSTANCE = new InsertSqlTemplate();
14 |
15 | @Override
16 | public String parseSQL(final Class> type) {
17 | return new SQL() {
18 | {
19 | INSERT_INTO(PersistentUtil.getTableName(type));
20 | for (Field field : PersistentUtil.getPersistentFields(type)) {
21 | if (PersistentUtil.insertable(field)) {
22 | VALUES(PersistentUtil.getColumnName(field),
23 | ColumnMetaResolver.resolveSqlPlaceholder(field));
24 | }
25 | }
26 | }
27 | }.toString();
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/template/SqlTemplate.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support.template;
2 |
3 | /**
4 | * @author sway.li
5 | */
6 | public interface SqlTemplate {
7 |
8 | String parseSQL(final Class> type);
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/template/UpdateCertainSqlTemplate.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support.template;
2 |
3 | import com.littlenb.mybatisjpa.support.Constant;
4 | import com.littlenb.mybatisjpa.util.ColumnMetaResolver;
5 | import com.littlenb.mybatisjpa.util.PersistentUtil;
6 | import java.lang.reflect.Field;
7 |
8 | /**
9 | * @author sway.li
10 | **/
11 | public class UpdateCertainSqlTemplate implements SqlTemplate {
12 |
13 | public static final SqlTemplate INSTANCE = new UpdateCertainSqlTemplate();
14 |
15 | @Override
16 | public String parseSQL(Class> type) {
17 | // columns
18 | StringBuilder sets = new StringBuilder();
19 | sets.append(" ");
20 | for (Field field : PersistentUtil.getPersistentFields(type)) {
21 | sets.append(String.format(
22 | " ",
23 | field.getName()
24 | ));
25 | // columnName = #{ }
26 |
27 | sets.append(PersistentUtil.getColumnName(field)).append(" = ")
28 | .append(ColumnMetaResolver.resolveSqlPlaceholder(field, Constant.CERTAINTY_ENTITY_KEY))
29 | .append(", ");
30 | sets.append(" ");
31 | }
32 |
33 | sets.append(" ");
34 |
35 | return "UPDATE " + PersistentUtil.getTableName(type) + " SET " + sets.toString();
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/template/UpdateIgnoreNullSqlTemplate.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support.template;
2 |
3 | import com.littlenb.mybatisjpa.util.ColumnMetaResolver;
4 | import com.littlenb.mybatisjpa.util.PersistentUtil;
5 | import java.lang.reflect.Field;
6 |
7 | /**
8 | * @author sway.li
9 | **/
10 | public class UpdateIgnoreNullSqlTemplate implements SqlTemplate {
11 |
12 | public static final SqlTemplate INSTANCE = new UpdateIgnoreNullSqlTemplate();
13 |
14 | @Override
15 | public String parseSQL(Class> type) {
16 | // columns
17 | StringBuilder sets = new StringBuilder();
18 | sets.append(" ");
19 | for (Field field : PersistentUtil.getPersistentFields(type)) {
20 |
21 | sets.append(" ");
22 | // columnName = #{ }
23 |
24 | sets.append(PersistentUtil.getColumnName(field)).append(" = ")
25 | .append(ColumnMetaResolver.resolveSqlPlaceholder(field)).append(" , ");
26 | sets.append(" ");
27 | }
28 |
29 | sets.append(" ");
30 |
31 | return "UPDATE " + PersistentUtil.getTableName(type) + " set " + sets.toString();
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/support/template/UpdateSqlTemplate.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.support.template;
2 |
3 | import com.littlenb.mybatisjpa.util.ColumnMetaResolver;
4 | import com.littlenb.mybatisjpa.util.PersistentUtil;
5 | import java.lang.reflect.Field;
6 | import org.apache.ibatis.jdbc.SQL;
7 |
8 | /**
9 | * @author sway.li
10 | **/
11 | public class UpdateSqlTemplate implements SqlTemplate {
12 |
13 | public static final SqlTemplate INSTANCE = new UpdateSqlTemplate();
14 |
15 | @Override
16 | public String parseSQL(final Class> type) {
17 | return new SQL() {
18 | {
19 | UPDATE(PersistentUtil.getTableName(type));
20 | for (Field field : PersistentUtil.getPersistentFields(type)) {
21 | if (PersistentUtil.updatable(field)) {
22 | SET(PersistentUtil.getColumnName(field) + " = " + ColumnMetaResolver
23 | .resolveSqlPlaceholder(field));
24 | }
25 | }
26 | }
27 | }.toString();
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/type/CodeEnumAdapter.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.type;
2 |
3 | import java.util.Objects;
4 |
5 | /**
6 | * ICodeEnum
适配器
7 | *
8 | * @author sway.li
9 | * @see ICodeEnum
10 | **/
11 | public class CodeEnumAdapter {
12 |
13 | /**
14 | * adapt to {@link ICodeEnum} with code.
15 | *
16 | * @param the type which implements {@link ICodeEnum} and extends {@link Enum}
17 | */
18 | public static T toCodeEnum(Object code, Class type) {
19 |
20 | if (!type.isEnum()) {
21 | throw new IllegalArgumentException(
22 | String.format("type must be Enum,type : %s", type.getName()));
23 | }
24 |
25 | if (!ICodeEnum.class.isAssignableFrom(type)) {
26 | throw new IllegalArgumentException(
27 | String.format("type must be sub class by ICodeEnum,type : %s", type.getName()));
28 | }
29 |
30 | for (T t : type.getEnumConstants()) {
31 |
32 | ICodeEnum codeEnum = (ICodeEnum) t;
33 |
34 | if (Objects.equals(codeEnum.getCode(), code)) {
35 | return t;
36 | }
37 |
38 | }
39 |
40 | throw new IllegalArgumentException(
41 | "Cannot convert " + code + " to " + type.getSimpleName() + " by code.");
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/type/CodeType.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.type;
2 |
3 | /**
4 | * @author sway.li
5 | **/
6 | public enum CodeType {
7 |
8 | INT, STRING
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/type/ICodeEnum.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.type;
2 |
3 |
4 | /**
5 | * 枚举类型扩展
6 | *
7 | * @param Integer or String
8 | * @author sway.li
9 | */
10 | public interface ICodeEnum {
11 |
12 | T getCode();
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/type/IntCodeEnumTypeHandler.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.type;
2 |
3 | import java.sql.CallableStatement;
4 | import java.sql.PreparedStatement;
5 | import java.sql.ResultSet;
6 | import java.sql.SQLException;
7 | import org.apache.ibatis.type.BaseTypeHandler;
8 | import org.apache.ibatis.type.JdbcType;
9 | import org.apache.ibatis.type.MappedJdbcTypes;
10 | import org.apache.ibatis.type.MappedTypes;
11 |
12 | /**
13 | * @author sway.li
14 | **/
15 | @MappedJdbcTypes({JdbcType.INTEGER, JdbcType.TINYINT})
16 | @MappedTypes({ICodeEnum.class})
17 | public class IntCodeEnumTypeHandler extends BaseTypeHandler {
18 |
19 | private Class type;
20 |
21 | public IntCodeEnumTypeHandler(Class type) {
22 | if (type == null) {
23 | throw new IllegalArgumentException("Type argument cannot be null");
24 | }
25 | this.type = type;
26 | }
27 |
28 | @Override
29 | public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType)
30 | throws SQLException {
31 | if (jdbcType == null) {
32 | ps.setInt(i, (Integer) parameter.getCode());
33 | } else {
34 | ps.setObject(i, parameter.getCode(), jdbcType.TYPE_CODE);
35 | }
36 | }
37 |
38 | @Override
39 | public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
40 | int i = rs.getInt(columnName);
41 | if (rs.wasNull()) {
42 | return null;
43 | } else {
44 | return CodeEnumAdapter.toCodeEnum(i, type);
45 | }
46 | }
47 |
48 | @Override
49 | public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
50 | int i = rs.getInt(columnIndex);
51 | if (rs.wasNull()) {
52 | return null;
53 | } else {
54 | return CodeEnumAdapter.toCodeEnum(i, type);
55 | }
56 | }
57 |
58 | @Override
59 | public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
60 | int i = cs.getInt(columnIndex);
61 | if (cs.wasNull()) {
62 | return null;
63 | } else {
64 | return CodeEnumAdapter.toCodeEnum(i, type);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/type/SelectorStrategy.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.type;
2 |
3 | /**
4 | * @author sway.li
5 | */
6 | public enum SelectorStrategy {
7 |
8 | /**
9 | * none
10 | */
11 | NONE,
12 |
13 | /**
14 | * ignore null
15 | */
16 | IGNORE_NULL,
17 |
18 | /**
19 | * @see com.littlenb.mybatisjpa.support.Certainty
20 | */
21 | CERTAIN
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/type/StringCodeEnumTypeHandler.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.type;
2 |
3 | import java.sql.CallableStatement;
4 | import java.sql.PreparedStatement;
5 | import java.sql.ResultSet;
6 | import java.sql.SQLException;
7 | import org.apache.ibatis.type.BaseTypeHandler;
8 | import org.apache.ibatis.type.JdbcType;
9 | import org.apache.ibatis.type.MappedJdbcTypes;
10 | import org.apache.ibatis.type.MappedTypes;
11 |
12 | /**
13 | * @author sway.li
14 | **/
15 | @MappedJdbcTypes({JdbcType.VARCHAR})
16 | @MappedTypes({ICodeEnum.class})
17 | public class StringCodeEnumTypeHandler extends BaseTypeHandler {
18 |
19 | private Class type;
20 |
21 | public StringCodeEnumTypeHandler(Class type) {
22 | if (type == null) {
23 | throw new IllegalArgumentException("Type argument cannot be null");
24 | }
25 | this.type = type;
26 | }
27 |
28 | @Override
29 | public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType)
30 | throws SQLException {
31 | if (jdbcType == null) {
32 | ps.setString(i, (String) parameter.getCode());
33 | } else {
34 | ps.setObject(i, parameter.getCode(), jdbcType.TYPE_CODE);
35 | }
36 | }
37 |
38 | @Override
39 | public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
40 | String s = rs.getString(columnName);
41 | return s == null ? null : CodeEnumAdapter.toCodeEnum(s, type);
42 | }
43 |
44 | @Override
45 | public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
46 | String s = rs.getString(columnIndex);
47 | return s == null ? null : CodeEnumAdapter.toCodeEnum(s, type);
48 | }
49 |
50 | @Override
51 | public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
52 | String s = cs.getString(columnIndex);
53 | return s == null ? null : CodeEnumAdapter.toCodeEnum(s, type);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/util/ColumnMetaResolver.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.util;
2 |
3 | import com.littlenb.mybatisjpa.annotation.CodeEnum;
4 | import com.littlenb.mybatisjpa.annotation.MappedJdbcType;
5 | import com.littlenb.mybatisjpa.type.CodeType;
6 | import com.littlenb.mybatisjpa.type.IntCodeEnumTypeHandler;
7 | import com.littlenb.mybatisjpa.type.StringCodeEnumTypeHandler;
8 | import java.lang.reflect.Field;
9 | import java.util.Objects;
10 | import javax.persistence.EnumType;
11 | import javax.persistence.Enumerated;
12 | import org.apache.ibatis.builder.BuilderException;
13 | import org.apache.ibatis.type.BooleanTypeHandler;
14 | import org.apache.ibatis.type.EnumOrdinalTypeHandler;
15 | import org.apache.ibatis.type.EnumTypeHandler;
16 | import org.apache.ibatis.type.JdbcType;
17 | import org.apache.ibatis.type.TypeHandler;
18 |
19 | /**
20 | * @author sway.li
21 | **/
22 | public class ColumnMetaResolver {
23 |
24 | public static JdbcType resolveJdbcType(String alias) {
25 | if (alias == null) {
26 | return null;
27 | }
28 | try {
29 | return JdbcType.valueOf(alias);
30 | } catch (IllegalArgumentException e) {
31 | throw new BuilderException("Error resolving JdbcType. Cause: " + e, e);
32 | }
33 | }
34 |
35 | public static String resolveJdbcAlias(Field field) {
36 |
37 | if (field.isAnnotationPresent(MappedJdbcType.class)) {
38 | MappedJdbcType jdbcType = field.getAnnotation(MappedJdbcType.class);
39 | return jdbcType.value().name();
40 | }
41 |
42 | if (field.isAnnotationPresent(CodeEnum.class)) {
43 | CodeEnum codeEnum = field.getAnnotation(CodeEnum.class);
44 | if (Objects.equals(codeEnum.value(), CodeType.INT)) {
45 | return JdbcType.INTEGER.name();
46 | }
47 | if (Objects.equals(codeEnum.value(), CodeType.STRING)) {
48 | return JdbcType.VARCHAR.name();
49 | }
50 | }
51 | if (field.getType().isEnum()) {
52 | if (field.isAnnotationPresent(Enumerated.class)) {
53 | Enumerated enumerated = field.getAnnotation(Enumerated.class);
54 | if (Objects.equals(enumerated.value(), EnumType.ORDINAL)) {
55 | return "INTEGER";
56 | }
57 | }
58 | return "VARCHAR";
59 | }
60 |
61 | Class> fieldType = field.getType();
62 |
63 | if (Integer.class.equals(fieldType)) {
64 | return "INTEGER";
65 | }
66 | if (Double.class.equals(fieldType)) {
67 | return "DOUBLE";
68 | }
69 | if (Float.class.equals(fieldType)) {
70 | return "FLOAT";
71 | }
72 | if (String.class.equals(fieldType)) {
73 | return "VARCHAR";
74 | }
75 | if (java.util.Date.class.isAssignableFrom(fieldType)) {
76 | return "TIMESTAMP";
77 | }
78 | return null;
79 | }
80 |
81 | @SuppressWarnings({"unchecked", "rawtypes"})
82 | public static Class extends TypeHandler>> resolveTypeHandler(Field field) {
83 |
84 | if (field.isAnnotationPresent(CodeEnum.class)) {
85 | CodeEnum codeEnum = field.getAnnotation(CodeEnum.class);
86 | if (Objects.equals(codeEnum.value(), CodeType.INT)) {
87 | IntCodeEnumTypeHandler typeHandler = new IntCodeEnumTypeHandler(field.getType());
88 | return (Class extends TypeHandler>>) typeHandler.getClass();
89 | }
90 | if (Objects.equals(codeEnum.value(), CodeType.STRING)) {
91 | StringCodeEnumTypeHandler typeHandler = new StringCodeEnumTypeHandler(field.getType());
92 | return (Class extends TypeHandler>>) typeHandler.getClass();
93 | }
94 | }
95 |
96 | if (field.getType().isEnum()) {
97 | if (field.isAnnotationPresent(Enumerated.class)) {
98 | Enumerated enumerated = field.getAnnotation(Enumerated.class);
99 | if (enumerated.value() == EnumType.ORDINAL) {
100 | EnumOrdinalTypeHandler extends Enum>> typeHandler = new EnumOrdinalTypeHandler(
101 | field.getType());
102 | return (Class extends TypeHandler>>) typeHandler.getClass();
103 |
104 | }
105 | }
106 | EnumTypeHandler extends Enum>> typeHandler = new EnumTypeHandler(field.getType());
107 | return (Class extends TypeHandler>>) typeHandler.getClass();
108 | }
109 |
110 | if (field.getType().equals(Boolean.class)) {
111 | return BooleanTypeHandler.class;
112 | }
113 | return null;
114 | }
115 |
116 | /**
117 | * 装配sql中动态参数的占位符 #{parameterName,jdbcType=,typeHandler=}
118 | */
119 | public static String resolveSqlPlaceholder(Field field) {
120 |
121 | return resolveSqlPlaceholder(field, "");
122 | }
123 |
124 | /**
125 | * 装配sql中动态参数的占位符 #{alias.parameterName,jdbcType=,typeHandler=}
126 | */
127 | public static String resolveSqlPlaceholder(Field field, String alias) {
128 | StringBuilder sqlParameter = new StringBuilder();
129 | sqlParameter.append("#{");
130 | if (alias != null && !"".equals(alias)) {
131 | sqlParameter.append(alias).append(".");
132 | }
133 | sqlParameter.append(field.getName());
134 |
135 | // jdbcType
136 | String jdbcType = resolveJdbcAlias(field);
137 |
138 | if (jdbcType != null) {
139 | sqlParameter.append(", jdbcType=").append(jdbcType);
140 | }
141 | // typeHandler
142 | Class extends TypeHandler>> typeHandler = resolveTypeHandler(field);
143 |
144 | if (typeHandler != null) {
145 | sqlParameter.append(", typeHandler=").append(typeHandler.getName());
146 | }
147 | sqlParameter.append("} ");
148 |
149 | return sqlParameter.toString();
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/util/FieldReflectUtil.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.util;
2 |
3 | import java.lang.annotation.Annotation;
4 | import java.lang.reflect.Field;
5 | import java.lang.reflect.Modifier;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /**
10 | * @author sway.li
11 | */
12 | public class FieldReflectUtil {
13 |
14 | /**
15 | * Set the field value to target object.
16 | *
17 | * @param target obj
18 | * @param name field name
19 | * @throws Exception IllegalArgumentException, IllegalAccessException
20 | */
21 | public static void setFieldValue(T target, String name, Object value) throws Exception {
22 | if (target == null) {
23 | throw new IllegalArgumentException("Target must not be null");
24 | }
25 |
26 | Field field = findField(target.getClass(), name);
27 |
28 | makeAccessible(field);
29 |
30 | field.set(target, value);
31 | }
32 |
33 | /**
34 | * Get the field value from target object.
35 | *
36 | * @param target obj
37 | * @param name field name
38 | * @return value
39 | * @throws Exception IllegalArgumentException, IllegalAccessException
40 | */
41 | public static Object getFieldValue(T target, String name) throws Exception {
42 | if (target == null) {
43 | throw new IllegalArgumentException("Target must not be null");
44 | }
45 |
46 | Field field = findField(target.getClass(), name);
47 |
48 | if (field == null) {
49 | throw new IllegalArgumentException(
50 | "Can not find field " + name + " from " + target.getClass());
51 | }
52 |
53 | makeAccessible(field);
54 |
55 | return field.get(target);
56 | }
57 |
58 | /**
59 | * Attempt to find a field on the supplied Class with the supplied {@code annotationType}.
60 | * Searches all superclasses up to Object.
61 | *
62 | * @param clazz the class to introspect
63 | * @param annotationType the annotation type of the field
64 | * @return Field or null
65 | */
66 | public static List findFields(Class> clazz, Class extends Annotation> annotationType) {
67 | List list = new ArrayList<>();
68 | Class> searchType = clazz;
69 | while (!Object.class.equals(searchType) && searchType != null) {
70 | Field[] fields = searchType.getDeclaredFields();
71 | for (Field field : fields) {
72 | if (field.isAnnotationPresent(annotationType)) {
73 | list.add(field);
74 | }
75 | }
76 | searchType = searchType.getSuperclass();
77 | }
78 | return list;
79 | }
80 |
81 | /**
82 | * copy from org.springframework.util.ReflectionUtils
83 | */
84 | public static Field findField(Class> clazz, String name) {
85 | return findField(clazz, name, null);
86 | }
87 |
88 | /**
89 | * copy from org.springframework.util.ReflectionUtils
90 | */
91 | public static Field findField(Class> clazz, String name, Class> type) {
92 | if (clazz == null) {
93 | throw new IllegalArgumentException("Class must not be null");
94 | }
95 | if (name == null && type == null) {
96 | throw new IllegalArgumentException("Either name or type of the field must be specified");
97 | }
98 | Class> searchType = clazz;
99 | while (Object.class != searchType && searchType != null) {
100 | Field[] fields = searchType.getDeclaredFields();
101 | for (Field field : fields) {
102 | if ((name == null || name.equals(field.getName())) &&
103 | (type == null || type.equals(field.getType()))) {
104 | return field;
105 | }
106 | }
107 | searchType = searchType.getSuperclass();
108 | }
109 | return null;
110 | }
111 |
112 | /**
113 | * copy from org.springframework.util.ReflectionUtils
114 | */
115 | public static void makeAccessible(Field field) {
116 | if ((!Modifier.isPublic(field.getModifiers()) ||
117 | !Modifier.isPublic(field.getDeclaringClass().getModifiers()) ||
118 | Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
119 | field.setAccessible(true);
120 | }
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/util/NamingPolicy.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.util;
2 |
3 | /**
4 | * @author sway.li
5 | * @since 2.5.0
6 | */
7 | public enum NamingPolicy implements NamingStrategy {
8 |
9 | IDENTITY(){
10 | @Override
11 | public String translate(String name) {
12 | return name;
13 | }
14 | },
15 | LOWER_CASE_WITH_UNDERSCORES(){
16 | @Override
17 | public String translate(String name) {
18 | StringBuilder buf = new StringBuilder();
19 | for (int i = 0; i < name.length(); ++i) {
20 | char ch = name.charAt(i);
21 | if (ch >= 'A' && ch <= 'Z') {
22 | char ch_ucase = (char) (ch + 32);
23 | if (i > 0) {
24 | buf.append('_');
25 | }
26 | buf.append(ch_ucase);
27 | } else {
28 | buf.append(ch);
29 | }
30 | }
31 | return buf.toString();
32 | }
33 | },
34 | UPPER_CASE_WITH_UNDERSCORES(){
35 | @Override
36 | public String translate(String name) {
37 | StringBuilder buf = new StringBuilder();
38 | for (int i = 0; i < name.length(); ++i) {
39 | char ch = name.charAt(i);
40 | if (ch >= 'a' && ch <= 'z') {
41 | char ch_ucase = (char) (ch - 32);
42 |
43 | buf.append(ch_ucase);
44 | } else if(ch >= 'A' && ch <= 'Z'){
45 | if (i > 0) {
46 | buf.append('_');
47 | }
48 | buf.append(ch);
49 | } else{
50 | buf.append(ch);
51 | }
52 | }
53 | return buf.toString();
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/util/NamingStrategy.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.util;
2 |
3 | /**
4 | * @author sway.li
5 | * @since 2.5.0
6 | */
7 | public interface NamingStrategy {
8 |
9 | String translate(String name);
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/littlenb/mybatisjpa/util/PersistentUtil.java:
--------------------------------------------------------------------------------
1 | package com.littlenb.mybatisjpa.util;
2 |
3 | import com.littlenb.mybatisjpa.support.MybatisJapConfiguration;
4 | import java.lang.reflect.Field;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 | import javax.persistence.Column;
8 | import javax.persistence.Id;
9 | import javax.persistence.ManyToMany;
10 | import javax.persistence.ManyToOne;
11 | import javax.persistence.OneToMany;
12 | import javax.persistence.OneToOne;
13 | import javax.persistence.Table;
14 | import javax.persistence.Transient;
15 |
16 | /**
17 | * @author sway.li
18 | */
19 | public class PersistentUtil {
20 |
21 | private static MybatisJapConfiguration conf = MybatisJapConfiguration.getInstance();
22 |
23 | public static String getTableName(Class> clazz) {
24 | return getTableName(clazz, conf.getTableNamingStrategy());
25 | }
26 |
27 | public static String getTableName(Class> clazz, NamingStrategy namingStrategy) {
28 | if (clazz.isAnnotationPresent(Table.class)) {
29 | Table table = clazz.getAnnotation(Table.class);
30 | if (!"".equals(table.name().trim())) {
31 | return table.name();
32 | }
33 | }
34 | String tableName = clazz.getSimpleName();
35 |
36 | return namingStrategy.translate(tableName);
37 | }
38 |
39 | public static String getColumnName(Field field) {
40 | return getColumnName(field, conf.getColumnNamingStrategy());
41 | }
42 |
43 | public static String getColumnName(Field field, NamingStrategy namingStrategy) {
44 | if (field.isAnnotationPresent(Column.class)) {
45 | Column column = field.getAnnotation(Column.class);
46 | if (!"".equals(column.name().trim())) {
47 | return column.name();
48 | }
49 | }
50 | String columnName = field.getName();
51 |
52 | return namingStrategy.translate(columnName);
53 | }
54 |
55 | public static String getMappedName(Field field) {
56 | if (field.isAnnotationPresent(OneToOne.class)) {
57 | OneToOne one = field.getAnnotation(OneToOne.class);
58 | if (!one.mappedBy().trim().equals("")) {
59 | return one.mappedBy();
60 | }
61 | }
62 | if (field.isAnnotationPresent(OneToMany.class)) {
63 | OneToMany one = field.getAnnotation(OneToMany.class);
64 | if (!one.mappedBy().trim().equals("")) {
65 | return one.mappedBy();
66 | }
67 | }
68 | return null;
69 | }
70 |
71 | public static List getPersistentFields(Class> clazz) {
72 | List list = new ArrayList<>();
73 | Class> searchType = clazz;
74 | while (!Object.class.equals(searchType) && searchType != null) {
75 | Field[] fields = searchType.getDeclaredFields();
76 | for (Field field : fields) {
77 | if (isPersistentField(field)) {
78 | list.add(field);
79 | }
80 | }
81 | searchType = searchType.getSuperclass();
82 | }
83 | return list;
84 | }
85 |
86 | public static Field getIdField(Class> clazz) {
87 | Class> searchType = clazz;
88 | while (!Object.class.equals(searchType) && searchType != null) {
89 | Field[] fields = searchType.getDeclaredFields();
90 | for (Field field : fields) {
91 | if (field.isAnnotationPresent(Id.class) && isPersistentField(field)) {
92 | return field;
93 | }
94 | }
95 | searchType = searchType.getSuperclass();
96 | }
97 | return null;
98 | }
99 |
100 | public static boolean insertable(Field field) {
101 | if (!isPersistentField(field) || isAssociationField(field)) {
102 | return false;
103 | }
104 |
105 | if (field.isAnnotationPresent(Column.class)) {
106 | Column column = field.getAnnotation(Column.class);
107 | return column.insertable();
108 | }
109 |
110 | return true;
111 | }
112 |
113 | public static boolean updatable(Field field) {
114 | if (!isPersistentField(field) || isAssociationField(field)) {
115 | return false;
116 | }
117 |
118 | if (field.isAnnotationPresent(Column.class)) {
119 | Column column = field.getAnnotation(Column.class);
120 | return column.updatable();
121 | }
122 |
123 | return true;
124 | }
125 |
126 | public static boolean isPersistentField(Field field) {
127 | return !field.isAnnotationPresent(Transient.class) && !isAssociationField(field);
128 | }
129 |
130 | public static boolean isAssociationField(Field field) {
131 | return field.isAnnotationPresent(OneToOne.class)
132 | || field.isAnnotationPresent(OneToMany.class)
133 | || field.isAnnotationPresent(ManyToOne.class)
134 | || field.isAnnotationPresent(ManyToMany.class);
135 | }
136 | }
137 |
--------------------------------------------------------------------------------