├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── README_zh.md ├── _config.yml ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── springframework │ │ └── data │ │ └── ebean │ │ ├── annotation │ │ ├── ExprParam.java │ │ ├── IncludeFields.java │ │ ├── Modifying.java │ │ ├── Query.java │ │ └── package-info.java │ │ ├── domain │ │ ├── AbstractAggregateRoot.java │ │ ├── AbstractEntity.java │ │ ├── DomainEvent.java │ │ ├── DomainService.java │ │ └── package-info.java │ │ ├── querychannel │ │ ├── EbeanQueryChannelService.java │ │ ├── ExprType.java │ │ ├── QueryChannelService.java │ │ └── package-info.java │ │ ├── repository │ │ ├── EbeanRepository.java │ │ ├── config │ │ │ ├── EbeanRepositoriesRegistrar.java │ │ │ ├── EbeanRepositoryConfigExtension.java │ │ │ ├── EbeanRepositoryNameSpaceHandler.java │ │ │ ├── EnableEbeanRepositories.java │ │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── query │ │ │ ├── AbstractEbeanQuery.java │ │ │ ├── AbstractEbeanQueryExecution.java │ │ │ ├── AbstractStringBasedEbeanQuery.java │ │ │ ├── EbeanQueryCreator.java │ │ │ ├── EbeanQueryFactory.java │ │ │ ├── EbeanQueryLookupStrategy.java │ │ │ ├── EbeanQueryMethod.java │ │ │ ├── EbeanQueryWrapper.java │ │ │ ├── ExpressionBasedStringQuery.java │ │ │ ├── InvalidEbeanQueryMethodException.java │ │ │ ├── NamedEbeanQuery.java │ │ │ ├── NativeEbeanQuery.java │ │ │ ├── NativeEbeanUpdate.java │ │ │ ├── OrmEbeanQuery.java │ │ │ ├── OrmEbeanUpdate.java │ │ │ ├── ParameterBinder.java │ │ │ ├── ParameterMetadataProvider.java │ │ │ ├── PartTreeEbeanQuery.java │ │ │ ├── SpelExpressionStringQueryParameterBinder.java │ │ │ ├── StringQuery.java │ │ │ ├── StringQueryParameterBinder.java │ │ │ └── package-info.java │ │ └── support │ │ │ ├── EbeanEntityInformation.java │ │ │ ├── EbeanRepositoryFactory.java │ │ │ ├── EbeanRepositoryFactoryBean.java │ │ │ ├── SimpleEbeanRepository.java │ │ │ └── package-info.java │ │ └── util │ │ ├── Converters.java │ │ ├── ExampleExpressionBuilder.java │ │ └── package-info.java └── resources │ ├── META-INF │ ├── spring.factories │ └── spring.handlers │ └── license.txt └── test ├── java └── org │ └── springframework │ └── data │ └── ebean │ ├── querychannel │ ├── EbeanQueryChannelServiceIntegrationTest.java │ ├── UserDTO.java │ └── UserQuery.java │ ├── repository │ └── UserRepositoryIntegrationTest.java │ └── sample │ ├── config │ └── SampleConfig.java │ └── domain │ ├── Address.java │ ├── FullName.java │ ├── Role.java │ ├── User.java │ ├── UserDomainService.java │ ├── UserEmailChangedEvent.java │ ├── UserInfo.java │ └── UserRepository.java └── resources ├── application.properties ├── ebean-xml-mappings ├── UserDTOMapping.xml ├── UserInfoMapping.xml └── UserMapping.xml ├── ebean.mf └── logback-test.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | .settings/ 4 | *.iml 5 | .project 6 | .classpath 7 | .springBeans 8 | .sonar4clipse 9 | *.sonar4clipseExternals -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | env: 7 | matrix: 8 | - PROFILE=spring43 9 | - PROFILE=spring43-next 10 | 11 | cache: 12 | directories: 13 | - $HOME/.m2 14 | 15 | sudo: false 16 | 17 | install: true 18 | 19 | script: "mvn clean dependency:list test -P${PROFILE} -Dsort" -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | io.github.hexagonframework.data 8 | spring-data-ebean 9 | 2.0.0.RELEASE 10 | jar 11 | 12 | Spring Data Ebean 13 | Spring Data module for Ebean repositories. 14 | https://github.com/hexagonframework/spring-data-ebean 15 | 2017 16 | 17 | 18 | Hexagon Framework 19 | https://github.com/hexagonframework 20 | 21 | 22 | 23 | xueguiyuan 24 | Xuegui Yuan 25 | yuanxuegui@163.com 26 | 27 | 28 | 29 | 30 | 31 | Apache License, Version 2.0 32 | http://www.apache.org/licenses/LICENSE-2.0.txt 33 | 34 | 35 | 36 | 37 | https://github.com/hexagonframework/spring-data-ebean.git 38 | scm:git:git://github.com/hexagonframework/spring-data-ebean.git 39 | scm:git:ssh://git@github.com/hexagonframework/spring-data-ebean.git 40 | 41 | 42 | 43 | UTF-8 44 | 1.8 45 | debug=0 46 | false 47 | false 48 | 5.1.2.RELEASE 49 | 2.1.2.RELEASE 50 | 11.21.1 51 | 11.10.4 52 | reuseReports 53 | 54 | 55 | 56 | 57 | release 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-source-plugin 63 | 3.0.1 64 | 65 | 66 | package 67 | 68 | jar-no-fork 69 | 70 | 71 | 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-javadoc-plugin 76 | 3.0.0 77 | 78 | ${java.version} 79 | 80 | 81 | 82 | package 83 | 84 | jar 85 | 86 | 87 | 88 | 89 | 90 | org.apache.maven.plugins 91 | maven-gpg-plugin 92 | 1.6 93 | 94 | 95 | verify 96 | 97 | sign 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | oss 107 | https://oss.sonatype.org/content/repositories/snapshots/ 108 | 109 | 110 | oss 111 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | org.springframework.data 120 | spring-data-commons 121 | ${springdata.commons} 122 | 123 | 124 | 125 | org.springframework 126 | spring-context 127 | ${spring} 128 | 129 | 130 | 131 | org.springframework 132 | spring-jdbc 133 | ${spring} 134 | 135 | 136 | 137 | org.springframework 138 | spring-tx 139 | ${spring} 140 | 141 | 142 | 143 | org.springframework 144 | spring-core 145 | ${spring} 146 | 147 | 148 | commons-logging 149 | commons-logging 150 | 151 | 152 | 153 | 154 | 155 | io.ebean 156 | ebean 157 | ${ebean.version} 158 | true 159 | 160 | 161 | 162 | io.ebean 163 | ebean-spring-txn 164 | ${ebean-spring-txn.version} 165 | 166 | 167 | 168 | org.springframework 169 | spring-aspects 170 | ${spring} 171 | compile 172 | true 173 | 174 | 175 | 176 | org.projectlombok 177 | lombok 178 | 1.16.16 179 | true 180 | 181 | 182 | 183 | junit 184 | junit 185 | 4.12 186 | test 187 | 188 | 189 | 190 | com.h2database 191 | h2 192 | 1.4.196 193 | test 194 | 195 | 196 | 197 | org.springframework 198 | spring-test 199 | ${spring} 200 | test 201 | 202 | 203 | 204 | ch.qos.logback 205 | logback-classic 206 | 1.2.3 207 | test 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | io.repaint.maven 216 | tiles-maven-plugin 217 | 2.10 218 | true 219 | 220 | 221 | org.avaje.tile:java-compile:1.1 222 | io.ebean.tile:enhancement:5.5 223 | 224 | 225 | 226 | 227 | org.apache.maven.plugins 228 | maven-assembly-plugin 229 | 3.0.0 230 | 231 | 232 | org.codehaus.mojo 233 | wagon-maven-plugin 234 | 2.0.0 235 | 236 | 237 | org.asciidoctor 238 | asciidoctor-maven-plugin 239 | 1.5.6 240 | 241 | 242 | 243 | 244 | 245 | 246 | spring-libs-release 247 | https://repo.spring.io/libs-release 248 | 249 | 250 | 251 | 252 | 253 | spring-plugins-release 254 | https://repo.spring.io/plugins-release 255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/annotation/ExprParam.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.annotation; 2 | 3 | import org.springframework.data.ebean.querychannel.ExprType; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * Expr param. 9 | * 10 | * @author XueguiYuan 11 | * @version 1.0 (created time: 2018/4/29). 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.FIELD) 15 | @Documented 16 | public @interface ExprParam { 17 | 18 | /** 19 | * Query param name. 20 | */ 21 | String name() default ""; 22 | 23 | /** 24 | * Query param name. 25 | */ 26 | String value() default ""; 27 | 28 | /** 29 | * Expr. 30 | */ 31 | ExprType expr() default ExprType.DEFAULT; 32 | 33 | /** 34 | * Case insensitive. 35 | */ 36 | boolean ignoreCase() default true; 37 | 38 | /** 39 | * If true, do nothing when field value is null, else and expr isNull. 40 | */ 41 | boolean escapeNull() default true; 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/annotation/IncludeFields.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Define the fetch path string for query select and fetch. 10 | * 11 | * @author XueguiYuan 12 | * @version 1.0 (created time: 2018/4/29). 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target(ElementType.TYPE) 16 | public @interface IncludeFields { 17 | /** 18 | * Query fetch path string. 19 | */ 20 | String value(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/annotation/Modifying.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.annotation; 18 | 19 | import java.lang.annotation.*; 20 | 21 | /** 22 | * Indicates a method should be regarded as Update{@link io.ebean.UpdateQuery} or SqlUpdate{@link io.ebean.SqlUpdate}. 23 | * 24 | * @author Xuegui Yuan 25 | */ 26 | @Retention(RetentionPolicy.RUNTIME) 27 | @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) 28 | @Documented 29 | public @interface Modifying { 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/annotation/Query.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.annotation; 18 | 19 | import org.springframework.data.annotation.QueryAnnotation; 20 | 21 | import java.lang.annotation.*; 22 | 23 | /** 24 | * Annotation to declare finder queries directly on repository methods. 25 | * 26 | * @author Xuegui Yuan 27 | */ 28 | @Retention(RetentionPolicy.RUNTIME) 29 | @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) 30 | @QueryAnnotation 31 | @Documented 32 | public @interface Query { 33 | 34 | /** 35 | * Defines the Ebean query to be executed when the annotated method is called. 36 | */ 37 | String value() default ""; 38 | 39 | /** 40 | * Configures whether the given query is a SqlQuery. Defaults to {@literal false}. 41 | */ 42 | boolean nativeQuery() default false; 43 | 44 | /** 45 | * The named query to be used. If not defined, a {@link javax.persistence.NamedQuery} with name of 46 | * {@code $ domainClass}.${queryMethodName}} will be used. 47 | */ 48 | String name() default ""; 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/annotation/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Annotations for Ebean specific repositories. 3 | */ 4 | 5 | package org.springframework.data.ebean.annotation; 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/domain/AbstractAggregateRoot.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.domain; 18 | 19 | import org.springframework.data.domain.AfterDomainEventPublication; 20 | import org.springframework.data.domain.DomainEvents; 21 | import org.springframework.util.Assert; 22 | 23 | import javax.persistence.MappedSuperclass; 24 | import javax.persistence.Transient; 25 | import java.util.ArrayList; 26 | import java.util.Collection; 27 | import java.util.Collections; 28 | import java.util.List; 29 | 30 | /** 31 | * Abstract base class for aggregate root, aggregate extends {@link AbstractEntity} and add 32 | * domain event functions. 33 | * 34 | * @author XueguiYuan 35 | */ 36 | @MappedSuperclass 37 | public abstract class AbstractAggregateRoot extends AbstractEntity { 38 | @Transient 39 | private transient final List domainEvents = new ArrayList<>(); 40 | 41 | /** 42 | * Registers the given event object for publication on a call to a Spring Data repository's save methods. 43 | * 44 | * @param event must not be {@literal null}. 45 | * @return the event that has been added. 46 | */ 47 | protected T registerEvent(T event) { 48 | Assert.notNull(event, "Domain event must not be null!"); 49 | 50 | this.domainEvents.add(event); 51 | return event; 52 | } 53 | 54 | /** 55 | * Clears all domain events currently held. Usually invoked by the infrastructure in place in Spring Data 56 | * repositories. 57 | */ 58 | @AfterDomainEventPublication 59 | protected void clearDomainEvents() { 60 | this.domainEvents.clear(); 61 | } 62 | 63 | /** 64 | * All domain events currently captured by the aggregate. 65 | */ 66 | @DomainEvents 67 | protected Collection domainEvents() { 68 | return Collections.unmodifiableList(domainEvents); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/domain/AbstractEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.domain; 18 | 19 | import io.ebean.annotation.CreatedTimestamp; 20 | import io.ebean.annotation.UpdatedTimestamp; 21 | import io.ebean.annotation.WhoCreated; 22 | import io.ebean.annotation.WhoModified; 23 | import org.springframework.data.domain.Auditable; 24 | import org.springframework.data.domain.Persistable; 25 | import org.springframework.util.ClassUtils; 26 | 27 | import javax.persistence.Id; 28 | import javax.persistence.MappedSuperclass; 29 | import javax.persistence.Transient; 30 | import java.time.LocalDateTime; 31 | import java.util.Optional; 32 | 33 | 34 | /** 35 | * Abstract base class for entities. 36 | * {@link #equals(Object)} and {@link #hashCode()} based on that id. 37 | * 38 | * @author Xuegui Yuan 39 | */ 40 | @MappedSuperclass 41 | public abstract class AbstractEntity implements Persistable, Auditable { 42 | 43 | private static final long serialVersionUID = -5554308939380869754L; 44 | 45 | @Id 46 | protected Long id; 47 | 48 | @WhoCreated 49 | String createdBy; 50 | 51 | @CreatedTimestamp 52 | LocalDateTime createdDate; 53 | 54 | @WhoModified 55 | String lastModifiedBy; 56 | 57 | @UpdatedTimestamp 58 | LocalDateTime lastModifiedDate; 59 | 60 | @Override 61 | public Optional getCreatedBy() { 62 | return Optional.ofNullable(createdBy); 63 | } 64 | 65 | @Override 66 | public void setCreatedBy(String createdBy) { 67 | this.createdBy = createdBy; 68 | } 69 | 70 | @Override 71 | public Optional getCreatedDate() { 72 | return Optional.ofNullable(createdDate); 73 | } 74 | 75 | @Override 76 | public void setCreatedDate(LocalDateTime createdDate) { 77 | this.createdDate = createdDate; 78 | } 79 | 80 | @Override 81 | public Optional getLastModifiedBy() { 82 | return Optional.ofNullable(lastModifiedBy); 83 | } 84 | 85 | @Override 86 | public void setLastModifiedBy(String lastModifiedBy) { 87 | this.lastModifiedBy = lastModifiedBy; 88 | } 89 | 90 | @Override 91 | public Optional getLastModifiedDate() { 92 | return Optional.ofNullable(lastModifiedDate); 93 | } 94 | 95 | @Override 96 | public void setLastModifiedDate(LocalDateTime lastModifiedDate) { 97 | this.lastModifiedDate = lastModifiedDate; 98 | } 99 | 100 | @Override 101 | public int hashCode() { 102 | int hashCode = 17; 103 | 104 | hashCode += null == getId() ? 0 : getId().hashCode() * 31; 105 | 106 | return hashCode; 107 | } 108 | 109 | @Override 110 | public Long getId() { 111 | return id; 112 | } 113 | 114 | /** 115 | * Sets the id of the entity. 116 | * 117 | * @param id the id to set 118 | */ 119 | public void setId(final Long id) { 120 | this.id = id; 121 | } 122 | 123 | @Transient 124 | @Override 125 | public boolean isNew() { 126 | return null == getId(); 127 | } 128 | 129 | @Override 130 | public boolean equals(Object obj) { 131 | if (null == obj) { 132 | return false; 133 | } 134 | 135 | if (this == obj) { 136 | return true; 137 | } 138 | 139 | if (!getClass().equals(ClassUtils.getUserClass(obj))) { 140 | return false; 141 | } 142 | 143 | AbstractEntity that = (AbstractEntity) obj; 144 | 145 | return null != this.getId() && this.getId().equals(that.getId()); 146 | } 147 | 148 | @Override 149 | public String toString() { 150 | return String.format("Entity of type %s with id: %s", this.getClass().getName(), getId()); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/domain/DomainEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.domain; 18 | 19 | import org.springframework.context.ApplicationEvent; 20 | 21 | /** 22 | * Domain event. 23 | * 24 | * @author Xuegui Yuan 25 | */ 26 | public class DomainEvent extends ApplicationEvent { 27 | 28 | public DomainEvent(Object source) { 29 | super(source); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/domain/DomainService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.domain; 18 | 19 | import org.springframework.stereotype.Component; 20 | 21 | import java.lang.annotation.*; 22 | 23 | /** 24 | * Domain service use spring @Component 25 | * 26 | * @author Xuegui Yuan 27 | */ 28 | @Target({ElementType.TYPE}) 29 | @Retention(RetentionPolicy.RUNTIME) 30 | @Documented 31 | @Component 32 | public @interface DomainService { 33 | String value() default ""; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/domain/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Ebean specific impl classes to implement domain classes. 3 | */ 4 | 5 | package org.springframework.data.ebean.domain; 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/querychannel/ExprType.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.querychannel; 2 | 3 | /** 4 | * Expr type. 5 | * 6 | * @author XueguiYuan 7 | * @version 1.0 (created time: 2018/4/29). 8 | */ 9 | public enum ExprType { 10 | DEFAULT, EQ, NE, GT, GE, LT, LE, LIKE, STARTS_WITH, ENDS_WITH, CONTAINS, IN 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/querychannel/QueryChannelService.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.querychannel; 2 | 3 | import io.ebean.*; 4 | import org.springframework.data.domain.Pageable; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * @author XueguiYuan 10 | * @version 1.0 (created time: 2018/4/29). 11 | */ 12 | public interface QueryChannelService { 13 | 14 | Query createQuery(Class entityType, Object queryObject); 15 | 16 | Query createQuery(Class entityType, Object queryObject, Pageable pageable); 17 | 18 | Query createQuery(Class entityType); 19 | 20 | Query createQuery(Class entityType, String eql); 21 | 22 | SqlQuery createSqlQuery(String sql); 23 | 24 | Query createSqlQuery(Class entityType, String sql); 25 | 26 | Query createSqlQueryMappingColumns(Class entityType, 27 | String sql, 28 | Map columnMapping); 29 | 30 | Query createSqlQueryMappingTableAlias(Class entityType, 31 | String sql, 32 | Map tableAliasMapping); 33 | 34 | Query createNamedQuery(Class entityType, String queryName); 35 | 36 | DtoQuery createDtoQuery(Class dtoType, String sql); 37 | 38 | DtoQuery createNamedDtoQuery(Class dtoType, String namedQuery); 39 | 40 | ExampleExpression exampleOf(Object example); 41 | 42 | ExampleExpression exampleOf(Object example, 43 | boolean caseInsensitive, 44 | LikeType likeType); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/querychannel/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * EbeanQueryWrapper channel service. 3 | */ 4 | 5 | package org.springframework.data.ebean.querychannel; 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/EbeanRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository; 18 | 19 | import io.ebean.EbeanServer; 20 | import io.ebean.SqlUpdate; 21 | import io.ebean.UpdateQuery; 22 | import org.springframework.data.domain.Example; 23 | import org.springframework.data.domain.Page; 24 | import org.springframework.data.domain.Pageable; 25 | import org.springframework.data.domain.Sort; 26 | import org.springframework.data.repository.NoRepositoryBean; 27 | import org.springframework.data.repository.PagingAndSortingRepository; 28 | import org.springframework.data.repository.query.QueryByExampleExecutor; 29 | 30 | import java.util.List; 31 | import java.util.Optional; 32 | 33 | /** 34 | * Ebean specific extension of {@link org.springframework.data.repository.Repository}. 35 | * 36 | * @author Xuegui Yuan 37 | */ 38 | @NoRepositoryBean 39 | public interface EbeanRepository extends PagingAndSortingRepository, QueryByExampleExecutor { 40 | 41 | /** 42 | * Return the current EbeanServer. 43 | * 44 | * @return the current EbeanServer 45 | */ 46 | EbeanServer db(); 47 | 48 | /** 49 | * Set the current EbeanServer. 50 | * 51 | * @param db current EbeanServer 52 | * @return the current EbeanServer 53 | */ 54 | EbeanServer db(EbeanServer db); 55 | 56 | /** 57 | * Return an UpdateQuery to perform a bulk update of many rows that match the query. 58 | * 59 | * @return the created UpdateQuery 60 | */ 61 | UpdateQuery updateQuery(); 62 | 63 | /** 64 | * Return a SqlUpdate for executing insert update or delete statements. 65 | * 66 | * @param sql native SQL 67 | * @return the created SqlUpdate using native SQL 68 | */ 69 | SqlUpdate sqlUpdateOf(String sql); 70 | 71 | /** 72 | * Update entity which is not loaded. 73 | * 74 | * @param s entity to update 75 | * @param entity extends T 76 | * @return entity Updated entity 77 | */ 78 | S update(S s); 79 | 80 | /** 81 | * Update entities which is not loaded. 82 | * 83 | * @param entities entities to update 84 | * @return entities Updated entities list 85 | */ 86 | Iterable updateAll(Iterable entities); 87 | 88 | /** 89 | * Deletes the entity permanent with the given id. 90 | * 91 | * @param id must not be {@literal null}. 92 | * @throws IllegalArgumentException in case the given {@code id} is {@literal null} 93 | */ 94 | void deletePermanentById(ID id); 95 | 96 | /** 97 | * Deletes a given entity permanent. 98 | * 99 | * @param entity the entity to be deleted 100 | * @throws IllegalArgumentException in case the given entity is {@literal null}. 101 | */ 102 | void deletePermanent(T entity); 103 | 104 | /** 105 | * Deletes the given entities permanent. 106 | * 107 | * @param entities the entities to be deleted 108 | * @throws IllegalArgumentException in case the given {@link Iterable} is {@literal null}. 109 | */ 110 | void deletePermanentAll(Iterable entities); 111 | 112 | /** 113 | * Deletes all entities permanent managed by the repository. 114 | */ 115 | void deletePermanentAll(); 116 | 117 | /** 118 | * Retrieves an entity by its id and select return entity properties with FetchPath string. 119 | * 120 | * @param fetchPath FetchPath string 121 | * @param id ID 122 | * @return the entity only select/fetch with FetchPath string with the given id or {@literal null} if none found 123 | */ 124 | Optional findById(String fetchPath, ID id); 125 | 126 | /** 127 | * Retrieves an entity by its property name value. 128 | * 129 | * @param propertyName property name 130 | * @param propertyValue property value 131 | * @return the entity with the given property name value or {@literal null} if none found 132 | */ 133 | Optional findByProperty(String propertyName, Object propertyValue); 134 | 135 | /** 136 | * Retrieves an entity by its property name value and select return entity properties with FetchPath string. 137 | * 138 | * @param fetchPath FetchPath string 139 | * @param propertyName property name 140 | * @param propertyValue property value 141 | * @return the entity only select/fetch with FetchPath string with the given property name value or {@literal null} if none found 142 | */ 143 | Optional findByProperty(String fetchPath, String propertyName, Object propertyValue); 144 | 145 | /** 146 | * Retrieves an entities by its property name value. 147 | * 148 | * @param propertyName property name 149 | * @param propertyValue property value 150 | * @return the entity with the given property name value or {@literal null} if none found 151 | */ 152 | List findAllByProperty(String propertyName, Object propertyValue); 153 | 154 | /** 155 | * Retrieves all entities by its property name value and select return entity properties with FetchPath string. 156 | * 157 | * @param fetchPath FetchPath string 158 | * @param propertyName property name 159 | * @param propertyValue property value 160 | * @return the entity only select/fetch with FetchPath string with the given property name value or {@literal null} if none found 161 | */ 162 | List findAllByProperty(String fetchPath, String propertyName, Object propertyValue); 163 | 164 | /** 165 | * Retrieves an entity by its property name value and select return entity properties with FetchPath string. 166 | * 167 | * @param fetchPath FetchPath string. 168 | * @param propertyName property name. 169 | * @param propertyValue property value. 170 | * @param sort order by. 171 | * @return the entity only select/fetch with FetchPath string with the given property name value or {@literal null} if none found. 172 | */ 173 | List findAllByProperty(String fetchPath, String propertyName, Object propertyValue, Sort sort); 174 | 175 | /** 176 | * Find all by id list. 177 | * 178 | * @param ids id list. 179 | * @return List all entities list. 180 | */ 181 | @Override 182 | List findAllById(Iterable ids); 183 | 184 | /** 185 | * Find All. 186 | * 187 | * @return List all entities list. 188 | */ 189 | @Override 190 | List findAll(); 191 | 192 | /** 193 | * Find all order by sort config. 194 | * 195 | * @param sort order by. 196 | * @return List all entities list. 197 | */ 198 | @Override 199 | List findAll(Sort sort); 200 | 201 | /** 202 | * Returns all entities and select return entity properties with FetchPath string. 203 | * 204 | * @param fetchPath FetchPath string. 205 | * @return all entities only select/fetch with FetchPath string. 206 | */ 207 | List findAll(String fetchPath); 208 | 209 | /** 210 | * Returns all entities in ids and select return entity properties with FetchPath string. 211 | * 212 | * @param fetchPath FetchPath string. 213 | * @param ids ID list. 214 | * @return all entities by id in ids and select/fetch with FetchPath string. 215 | */ 216 | List findAll(String fetchPath, Iterable ids); 217 | 218 | /** 219 | * Returns all entities sorted by the given options and select return entity properties with FetchPath string. 220 | * 221 | * @param fetchPath FetchPath string. 222 | * @param sort order by. 223 | * @return all entities sorted and select/fetch with FetchPath string. 224 | */ 225 | List findAll(String fetchPath, Sort sort); 226 | 227 | /** 228 | * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object. 229 | * and select return entity properties with FetchPath string. 230 | * 231 | * @param fetchPath FetchPath string. 232 | * @param pageable page request. 233 | * @return a page of entities select/fetch with FetchPath string. 234 | */ 235 | Page findAll(String fetchPath, Pageable pageable); 236 | 237 | /** 238 | * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object. 239 | * and matching the given {@link Example} and select return entity properties with FetchPath string. 240 | * 241 | * @param fetchPath FetchPath string. 242 | * @param example must not be {@literal null}. 243 | * @param pageable page request. 244 | * @return a page of entities select/fetch with FetchPath string. 245 | */ 246 | Page findAll(String fetchPath, Example example, Pageable pageable); 247 | 248 | /** 249 | * Returns all entities matching the given {@link Example}. In case no match could be found an empty {@link Iterable} 250 | * is returned. 251 | * 252 | * @param example must not be {@literal null}. 253 | * @return all entities matching the given {@link Example}. 254 | */ 255 | @Override 256 | List findAll(Example example); 257 | 258 | /** 259 | * Returns all entities matching the given {@link Example} applying the given {@link Sort}. In case no match could be 260 | * found an empty {@link Iterable} is returned. 261 | * 262 | * @param fetchPath FetchPath string. 263 | * @param example must not be {@literal null}. 264 | * @return all entities matching the given {@link Example}. 265 | */ 266 | List findAll(String fetchPath, Example example); 267 | 268 | /** 269 | * Returns all entities matching the given {@link Example} applying the given {@link Sort}. In case no match could be 270 | * found an empty {@link Iterable} is returned. 271 | * 272 | * @param fetchPath FetchPath string. 273 | * @param example must not be {@literal null}. 274 | * @param sort the {@link Sort} specification to sort the results by, must not be {@literal null}. 275 | * @return all entities matching the given {@link Example}. 276 | */ 277 | List findAll(String fetchPath, Example example, Sort sort); 278 | 279 | /** 280 | * Returns all entities matching the given {@link Example} applying the given {@link Sort}. In case no match could be 281 | * found an empty {@link Iterable} is returned. 282 | * 283 | * @param example must not be {@literal null}. 284 | * @param sort the {@link Sort} specification to sort the results by, must not be {@literal null}. 285 | * @return all entities matching the given {@link Example}. 286 | */ 287 | @Override 288 | List findAll(Example example, Sort sort); 289 | } 290 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/config/EbeanRepositoriesRegistrar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.config; 18 | 19 | import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; 20 | import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport; 21 | import org.springframework.data.repository.config.RepositoryConfigurationExtension; 22 | 23 | import java.lang.annotation.Annotation; 24 | 25 | /** 26 | * {@link ImportBeanDefinitionRegistrar} to enable {@link EnableEbeanRepositories} annotation. 27 | * 28 | * @author Xuegui Yuan 29 | */ 30 | class EbeanRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport { 31 | 32 | /* 33 | * (non-Javadoc) 34 | * @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation() 35 | */ 36 | @Override 37 | protected Class getAnnotation() { 38 | return EnableEbeanRepositories.class; 39 | } 40 | 41 | /* 42 | * (non-Javadoc) 43 | * @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getExtension() 44 | */ 45 | @Override 46 | protected RepositoryConfigurationExtension getExtension() { 47 | return new EbeanRepositoryConfigExtension(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/config/EbeanRepositoryConfigExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.config; 18 | 19 | import org.springframework.dao.DataAccessException; 20 | import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; 21 | import org.springframework.data.ebean.repository.EbeanRepository; 22 | import org.springframework.data.ebean.repository.support.EbeanRepositoryFactoryBean; 23 | import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport; 24 | 25 | import javax.persistence.Entity; 26 | import javax.persistence.MappedSuperclass; 27 | import java.lang.annotation.Annotation; 28 | import java.util.Arrays; 29 | import java.util.Collection; 30 | import java.util.Collections; 31 | import java.util.Locale; 32 | 33 | /** 34 | * Ebean specific configuration extension parsing custom attributes from the XML namespace and 35 | * {@link EnableEbeanRepositories} annotation. Also, it registers bean definitions for a 36 | * {@link PersistenceExceptionTranslationPostProcessor} to enable exception translation of persistence specific 37 | * exceptions into Spring's {@link DataAccessException} hierarchy. 38 | * 39 | * @author Xuegui Yuan 40 | */ 41 | public class EbeanRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport { 42 | 43 | private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager"; 44 | private static final String ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE = "enableDefaultTransactions"; 45 | 46 | /* 47 | * (non-Javadoc) 48 | * @see org.springframework.data.repository.config.RepositoryConfigurationExtension#getRepositoryFactoryBeanClassName() 49 | */ 50 | @Override 51 | public String getRepositoryFactoryBeanClassName() { 52 | return EbeanRepositoryFactoryBean.class.getName(); 53 | } 54 | 55 | /* 56 | * (non-Javadoc) 57 | * @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModuleName() 58 | */ 59 | @Override 60 | public String getModuleName() { 61 | return "Ebean"; 62 | } 63 | 64 | 65 | /* 66 | * (non-Javadoc) 67 | * @see org.springframework.data.repository.config14.RepositoryConfigurationExtensionSupport#getModulePrefix() 68 | */ 69 | @Override 70 | protected String getModulePrefix() { 71 | return getModuleName().toLowerCase(Locale.US); 72 | } 73 | 74 | /* 75 | * (non-Javadoc) 76 | * @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getIdentifyingAnnotations() 77 | */ 78 | @Override 79 | protected Collection> getIdentifyingAnnotations() { 80 | return Arrays.asList(Entity.class, MappedSuperclass.class); 81 | } 82 | 83 | /* 84 | * (non-Javadoc) 85 | * @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getIdentifyingTypes() 86 | */ 87 | @Override 88 | protected Collection> getIdentifyingTypes() { 89 | return Collections.>singleton(EbeanRepository.class); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/config/EbeanRepositoryNameSpaceHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.config; 18 | 19 | import org.springframework.beans.factory.xml.NamespaceHandlerSupport; 20 | import org.springframework.data.repository.config.RepositoryBeanDefinitionParser; 21 | import org.springframework.data.repository.config.RepositoryConfigurationExtension; 22 | 23 | /** 24 | * Simple namespace handler for {@literal repositories} namespace. 25 | * 26 | * @author Xuegui Yuan 27 | */ 28 | public class EbeanRepositoryNameSpaceHandler extends NamespaceHandlerSupport { 29 | 30 | @Override 31 | public void init() { 32 | 33 | RepositoryConfigurationExtension extension = new EbeanRepositoryConfigExtension(); 34 | RepositoryBeanDefinitionParser repositoryBeanDefinitionParser = new RepositoryBeanDefinitionParser(extension); 35 | 36 | registerBeanDefinitionParser("repositories", repositoryBeanDefinitionParser); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/config/EnableEbeanRepositories.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.config; 18 | 19 | import org.springframework.beans.factory.FactoryBean; 20 | import org.springframework.context.annotation.ComponentScan.Filter; 21 | import org.springframework.context.annotation.Import; 22 | import org.springframework.data.ebean.repository.support.EbeanRepositoryFactoryBean; 23 | import org.springframework.data.repository.config.DefaultRepositoryBaseClass; 24 | import org.springframework.data.repository.query.QueryLookupStrategy; 25 | import org.springframework.data.repository.query.QueryLookupStrategy.Key; 26 | import org.springframework.transaction.PlatformTransactionManager; 27 | 28 | import java.lang.annotation.*; 29 | 30 | /** 31 | * Annotation to enable Ebean repositories. Will scan the package of the annotated configuration class for Spring Data 32 | * repositories by default. 33 | * 34 | * @author Xuegui Yuan 35 | */ 36 | @Target(ElementType.TYPE) 37 | @Retention(RetentionPolicy.RUNTIME) 38 | @Documented 39 | @Inherited 40 | @Import(EbeanRepositoriesRegistrar.class) 41 | public @interface EnableEbeanRepositories { 42 | 43 | /** 44 | * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.: 45 | * {@code @EnableEbeanRepositories("org.my.pkg")} instead of {@code @EnableEbeanRepositories(basePackages="org.my.pkg")}. 46 | */ 47 | String[] value() default {}; 48 | 49 | /** 50 | * Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this 51 | * attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names. 52 | */ 53 | String[] basePackages() default {}; 54 | 55 | /** 56 | * Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The 57 | * package of each class specified will be scanned. Consider creating a special no-op marker class or interface in 58 | * each package that serves no purpose other than being referenced by this attribute. 59 | */ 60 | Class[] basePackageClasses() default {}; 61 | 62 | /** 63 | * Specifies which types are eligible for component scanning. Further narrows the set of candidate components from 64 | * everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters. 65 | */ 66 | Filter[] includeFilters() default {}; 67 | 68 | /** 69 | * Specifies which types are not eligible for component scanning. 70 | */ 71 | Filter[] excludeFilters() default {}; 72 | 73 | /** 74 | * Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So 75 | * for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning 76 | * for {@code PersonRepositoryImpl}. 77 | * 78 | * @return 79 | */ 80 | String repositoryImplementationPostfix() default "Impl"; 81 | 82 | /** 83 | * Configures the location of where to find the Spring Data named queries properties file. Will default to 84 | * {@code META-INF/ebean-named-queries.properties}. 85 | * 86 | * @return 87 | */ 88 | String namedQueriesLocation() default ""; 89 | 90 | /** 91 | * Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to 92 | * {@link Key#CREATE_IF_NOT_FOUND}. 93 | * 94 | * @return 95 | */ 96 | Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND; 97 | 98 | /** 99 | * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to 100 | * {@link EbeanRepositoryFactoryBean}. 101 | * 102 | * @return 103 | */ 104 | Class repositoryFactoryBeanClass() default EbeanRepositoryFactoryBean.class; 105 | 106 | /** 107 | * Configure the repository base class to be used to create repository proxies for this particular configuration. 108 | * 109 | * @return 110 | * @since 1.9 111 | */ 112 | Class repositoryBaseClass() default DefaultRepositoryBaseClass.class; 113 | 114 | // Ebean specific configuration 115 | 116 | /** 117 | * Configures the name of the {@link io.ebean.EbeanServer} bean definition to be used to create repositories 118 | * discovered through this annotation. Defaults to {@code ebeanServer}. 119 | * 120 | * @return 121 | */ 122 | String ebeanServerRef() default "ebeanServer"; 123 | 124 | /** 125 | * Configures the name of the {@link PlatformTransactionManager} bean definition to be used to create repositories 126 | * discovered through this annotation. Defaults to {@code transactionManager}. 127 | * 128 | * @return 129 | */ 130 | String transactionManagerRef() default "transactionManager"; 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/config/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Classes for Ebean namespace configuration. 3 | */ 4 | 5 | package org.springframework.data.ebean.repository.config; 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Interfaces and inner implementation for Ebean specific repositories. 3 | */ 4 | 5 | package org.springframework.data.ebean.repository; 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/AbstractEbeanQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.data.repository.query.DefaultParameters; 21 | import org.springframework.data.repository.query.RepositoryQuery; 22 | import org.springframework.util.Assert; 23 | 24 | import static org.springframework.data.ebean.repository.query.AbstractEbeanQueryExecution.*; 25 | 26 | /** 27 | * Abstract base class to implement {@link RepositoryQuery}. 28 | * 29 | * @author Xuegui Yuan 30 | */ 31 | public abstract class AbstractEbeanQuery implements RepositoryQuery { 32 | 33 | private final EbeanQueryMethod method; 34 | private final EbeanServer ebeanServer; 35 | 36 | /** 37 | * Creates a new {@link AbstractEbeanQuery} from the given {@link EbeanQueryMethod}. 38 | * 39 | * @param method 40 | * @param ebeanServer 41 | */ 42 | public AbstractEbeanQuery(EbeanQueryMethod method, EbeanServer ebeanServer) { 43 | 44 | Assert.notNull(method, "EbeanQueryMethod must not be null!"); 45 | Assert.notNull(ebeanServer, "EbeanServer must not be null!"); 46 | 47 | this.method = method; 48 | this.ebeanServer = ebeanServer; 49 | } 50 | 51 | /** 52 | * Returns the {@link EbeanServer}. 53 | * 54 | * @return will never be {@literal null}. 55 | */ 56 | protected EbeanServer getEbeanServer() { 57 | return ebeanServer; 58 | } 59 | 60 | @Override 61 | public Object execute(Object[] parameters) { 62 | return doExecute(getExecution(), parameters); 63 | } 64 | 65 | @Override 66 | public EbeanQueryMethod getQueryMethod() { 67 | return method; 68 | } 69 | 70 | /** 71 | * @param execution 72 | * @param values 73 | * @return 74 | */ 75 | private Object doExecute(AbstractEbeanQueryExecution execution, Object[] values) { 76 | Object result = execution.execute(this, values); 77 | return result; 78 | } 79 | 80 | protected AbstractEbeanQueryExecution getExecution() { 81 | if (method.isStreamQuery()) { 82 | return new StreamExecution(); 83 | } else if (method.isCollectionQuery()) { 84 | return new AbstractEbeanQueryExecution.CollectionExecution(); 85 | } else if (method.isSliceQuery()) { 86 | return new SlicedExecution(method.getParameters()); 87 | } else if (method.isPageQuery()) { 88 | return new PagedExecution(method.getParameters()); 89 | } else if (method.isModifyingQuery()) { 90 | return new UpdateExecution(method, ebeanServer); 91 | } else { 92 | return new SingleEntityExecution(); 93 | } 94 | } 95 | 96 | protected ParameterBinder createBinder(Object[] values) { 97 | return new ParameterBinder((DefaultParameters) getQueryMethod().getParameters(), values); 98 | } 99 | 100 | protected EbeanQueryWrapper createQuery(Object[] values) { 101 | return doCreateQuery(values); 102 | } 103 | 104 | /** 105 | * Creates a {@link io.ebean.Query} or {@link io.ebean.SqlQuery} instance for the given values. 106 | * 107 | * @param values must not be {@literal null}. 108 | * @return 109 | */ 110 | protected abstract EbeanQueryWrapper doCreateQuery(Object[] values); 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/AbstractEbeanQueryExecution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.dao.InvalidDataAccessApiUsageException; 21 | import org.springframework.data.domain.Slice; 22 | import org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor; 23 | import org.springframework.data.repository.query.ParameterAccessor; 24 | import org.springframework.data.repository.query.Parameters; 25 | import org.springframework.data.repository.query.ParametersParameterAccessor; 26 | import org.springframework.util.Assert; 27 | 28 | /** 29 | * Set of classes to contain query execution strategies. Depending (mostly) on the return type of a 30 | * {@link org.springframework.data.repository.query.QueryMethod} a {@link AbstractStringBasedEbeanQuery} can be executed 31 | * in various flavors. 32 | * 33 | * @author Xuegui Yuan 34 | */ 35 | public abstract class AbstractEbeanQueryExecution { 36 | 37 | /** 38 | * Executes the given {@link AbstractStringBasedEbeanQuery} with the given {@link ParameterBinder}. 39 | * 40 | * @param query must not be {@literal null}. 41 | * @param values must not be {@literal null}. 42 | * @return 43 | */ 44 | public Object execute(AbstractEbeanQuery query, Object[] values) { 45 | Assert.notNull(query, "AbstractEbeanQuery must not be null!"); 46 | Assert.notNull(values, "Values must not be null!"); 47 | 48 | return doExecute(query, values); 49 | } 50 | 51 | /** 52 | * Method to implement {@link AbstractStringBasedEbeanQuery} executions by single enum values. 53 | * 54 | * @param query 55 | * @param values 56 | * @return 57 | */ 58 | protected abstract Object doExecute(AbstractEbeanQuery query, Object[] values); 59 | 60 | /** 61 | * Executes the query to return a simple collection of entities. 62 | */ 63 | static class CollectionExecution extends AbstractEbeanQueryExecution { 64 | 65 | @Override 66 | protected Object doExecute(AbstractEbeanQuery repositoryQuery, Object[] values) { 67 | EbeanQueryWrapper createQuery = repositoryQuery.createQuery(values); 68 | return createQuery.findList(); 69 | } 70 | } 71 | 72 | /** 73 | * Executes the query to return a {@link Slice} of entities. 74 | * 75 | * @author Xuegui Yuan 76 | */ 77 | static class SlicedExecution extends AbstractEbeanQueryExecution { 78 | 79 | private final Parameters parameters; 80 | 81 | /** 82 | * Creates a new {@link SlicedExecution} using the given {@link Parameters}. 83 | * 84 | * @param parameters must not be {@literal null}. 85 | */ 86 | public SlicedExecution(Parameters parameters) { 87 | this.parameters = parameters; 88 | } 89 | 90 | /* 91 | * (non-Javadoc) 92 | * @see org.springframework.data.ebean.repository.query.AbstractEbeanQueryExecution#doExecute(org.springframework.data.ebean.repository.query.AbstractEbeanQuery, java.lang.Object[]) 93 | */ 94 | @Override 95 | @SuppressWarnings("unchecked") 96 | protected Object doExecute(AbstractEbeanQuery query, Object[] values) { 97 | ParametersParameterAccessor accessor = new ParametersParameterAccessor(parameters, values); 98 | EbeanQueryWrapper createQuery = query.createQuery(values); 99 | return createQuery.findSlice(accessor.getPageable()); 100 | } 101 | } 102 | 103 | /** 104 | * Executes the {@link AbstractStringBasedEbeanQuery} to return a {@link org.springframework.data.domain.Page} of 105 | * entities. 106 | */ 107 | static class PagedExecution extends AbstractEbeanQueryExecution { 108 | 109 | private final Parameters parameters; 110 | 111 | public PagedExecution(Parameters parameters) { 112 | 113 | this.parameters = parameters; 114 | } 115 | 116 | @Override 117 | @SuppressWarnings("unchecked") 118 | protected Object doExecute(final AbstractEbeanQuery repositoryQuery, final Object[] values) { 119 | ParameterAccessor accessor = new ParametersParameterAccessor(parameters, values); 120 | EbeanQueryWrapper createQuery = repositoryQuery.createQuery(values); 121 | return createQuery.findPage(accessor.getPageable()); 122 | } 123 | } 124 | 125 | 126 | /** 127 | * Executes a {@link AbstractStringBasedEbeanQuery} to return a single entity. 128 | */ 129 | static class SingleEntityExecution extends AbstractEbeanQueryExecution { 130 | 131 | @Override 132 | protected Object doExecute(AbstractEbeanQuery query, Object[] values) { 133 | EbeanQueryWrapper createQuery = query.createQuery(values); 134 | return createQuery.findOne(); 135 | } 136 | } 137 | 138 | /** 139 | * Executes a update query such as an update, insert or delete. 140 | */ 141 | static class UpdateExecution extends AbstractEbeanQueryExecution { 142 | 143 | private final EbeanServer ebeanServer; 144 | 145 | /** 146 | * Creates an execution that automatically clears the given {@link EbeanServer} after execution if the given 147 | * {@link EbeanServer} is not {@literal null}. 148 | * 149 | * @param ebeanServer 150 | */ 151 | public UpdateExecution(EbeanQueryMethod method, EbeanServer ebeanServer) { 152 | 153 | Class returnType = method.getReturnType(); 154 | 155 | boolean isVoid = void.class.equals(returnType) || Void.class.equals(returnType); 156 | boolean isInt = int.class.equals(returnType) || Integer.class.equals(returnType); 157 | 158 | Assert.isTrue(isInt || isVoid, "Modifying queries can only use void or int/Integer as return type!"); 159 | 160 | this.ebeanServer = ebeanServer; 161 | } 162 | 163 | @Override 164 | protected Object doExecute(AbstractEbeanQuery query, Object[] values) { 165 | EbeanQueryWrapper createQuery = query.createQuery(values); 166 | return createQuery.update(); 167 | } 168 | } 169 | 170 | /** 171 | * {@link AbstractEbeanQueryExecution} removing entities matching the query. 172 | * 173 | * @author Xuegui Yuan 174 | */ 175 | static class DeleteExecution extends AbstractEbeanQueryExecution { 176 | 177 | private final EbeanServer ebeanServer; 178 | 179 | public DeleteExecution(EbeanServer ebeanServer) { 180 | this.ebeanServer = ebeanServer; 181 | } 182 | 183 | /* 184 | * (non-Javadoc) 185 | * @see org.springframework.data.ebean.repository.query.AbstractEbeanQueryExecution#doExecute(org.springframework.data.ebean.repository.query.AbstractEbeanQuery, java.lang.Object[]) 186 | */ 187 | @Override 188 | protected Object doExecute(AbstractEbeanQuery ebeanQuery, Object[] values) { 189 | EbeanQueryWrapper createQuery = ebeanQuery.createQuery(values); 190 | return createQuery.delete(); 191 | } 192 | } 193 | 194 | /** 195 | * {@link AbstractEbeanQueryExecution} performing an exists check on the query. 196 | * 197 | * @author Xuegui Yuan 198 | */ 199 | static class ExistsExecution extends AbstractEbeanQueryExecution { 200 | 201 | @Override 202 | protected Object doExecute(AbstractEbeanQuery ebeanQuery, Object[] values) { 203 | EbeanQueryWrapper createQuery = ebeanQuery.createQuery(values); 204 | return createQuery.isExists(); 205 | } 206 | } 207 | 208 | /** 209 | * {@link AbstractEbeanQueryExecution} executing a Java 8 Stream. 210 | * 211 | * @author Xuegui Yuan 212 | */ 213 | static class StreamExecution extends AbstractEbeanQueryExecution { 214 | 215 | private static final String NO_SURROUNDING_TRANSACTION = "You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses @Transactional or any other way of declaring a (read-only) transaction."; 216 | 217 | /* 218 | * (non-Javadoc) 219 | * @see org.springframework.data.ebean.repository.query.AbstractEbeanQueryExecution#doExecute(org.springframework.data.ebean.repository.query.AbstractEbeanQuery, java.lang.Object[]) 220 | */ 221 | @Override 222 | protected Object doExecute(final AbstractEbeanQuery ebeanQuery, Object[] values) { 223 | if (!SurroundingTransactionDetectorMethodInterceptor.INSTANCE.isSurroundingTransactionActive()) { 224 | throw new InvalidDataAccessApiUsageException(NO_SURROUNDING_TRANSACTION); 225 | } 226 | 227 | EbeanQueryWrapper createQuery = ebeanQuery.createQuery(values); 228 | return createQuery.findStream(); 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/AbstractStringBasedEbeanQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.data.repository.query.*; 21 | import org.springframework.expression.spel.standard.SpelExpressionParser; 22 | import org.springframework.util.Assert; 23 | 24 | 25 | /** 26 | * Base class for {@link String} based Ebean queries. 27 | * 28 | * @author Xuegui Yuan 29 | */ 30 | abstract class AbstractStringBasedEbeanQuery extends AbstractEbeanQuery { 31 | 32 | private final StringQuery query; 33 | private final QueryMethodEvaluationContextProvider evaluationContextProvider; 34 | private final SpelExpressionParser parser; 35 | 36 | /** 37 | * Creates a new {@link AbstractStringBasedEbeanQuery} from the given {@link EbeanQueryMethod}, {@link io.ebean.EbeanServer} and 38 | * query {@link String}. 39 | * 40 | * @param method must not be {@literal null}. 41 | * @param ebeanServer must not be {@literal null}. 42 | * @param queryString must not be {@literal null}. 43 | * @param evaluationContextProvider must not be {@literal null}. 44 | * @param parser must not be {@literal null}. 45 | */ 46 | public AbstractStringBasedEbeanQuery(EbeanQueryMethod method, EbeanServer ebeanServer, String queryString, 47 | QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) { 48 | 49 | super(method, ebeanServer); 50 | 51 | Assert.hasText(queryString, "EbeanQueryWrapper string must not be null or empty!"); 52 | Assert.notNull(evaluationContextProvider, "ExpressionEvaluationContextProvider must not be null!"); 53 | Assert.notNull(parser, "Parser must not be null or empty!"); 54 | 55 | this.evaluationContextProvider = evaluationContextProvider; 56 | this.query = new ExpressionBasedStringQuery(queryString, method.getEntityInformation(), parser); 57 | this.parser = parser; 58 | } 59 | 60 | /** 61 | * @return the query 62 | */ 63 | public StringQuery getQuery() { 64 | return query; 65 | } 66 | 67 | /* 68 | * (non-Javadoc) 69 | * @see org.springframework.data.ebean.repository.query.AbstractEbeanQuery#doCreateQuery(java.lang.Object[]) 70 | */ 71 | @Override 72 | public EbeanQueryWrapper doCreateQuery(Object[] values) { 73 | ParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(), values); 74 | 75 | EbeanQueryWrapper query = createEbeanQuery(this.query.getQueryString()); 76 | 77 | return createBinder(values).bindAndPrepare(query); 78 | } 79 | 80 | /* 81 | * (non-Javadoc) 82 | * @see org.springframework.data.ebean.repository.query.AbstractEbeanQuery#createBinder(java.lang.Object[]) 83 | */ 84 | @Override 85 | protected ParameterBinder createBinder(Object[] values) { 86 | return new SpelExpressionStringQueryParameterBinder((DefaultParameters) getQueryMethod().getParameters(), values, query, 87 | evaluationContextProvider, parser); 88 | } 89 | 90 | /** 91 | * Creates an appropriate Ebean query from an {@link EbeanServer} according to the current {@link AbstractEbeanQuery} 92 | * type. 93 | * 94 | * @param queryString 95 | * @return 96 | */ 97 | protected EbeanQueryWrapper createEbeanQuery(String queryString) { 98 | EbeanServer ebeanServer = getEbeanServer(); 99 | 100 | ResultProcessor resultFactory = getQueryMethod().getResultProcessor(); 101 | ReturnedType returnedType = resultFactory.getReturnedType(); 102 | 103 | return EbeanQueryWrapper.ofEbeanQuery(ebeanServer.createQuery(returnedType.getReturnedType(), queryString)); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/EbeanQueryCreator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.Expr; 20 | import io.ebean.Expression; 21 | import io.ebean.ExpressionList; 22 | import io.ebean.Query; 23 | import org.springframework.data.domain.Sort; 24 | import org.springframework.data.mapping.PropertyPath; 25 | import org.springframework.data.repository.query.ReturnedType; 26 | import org.springframework.data.repository.query.parser.AbstractQueryCreator; 27 | import org.springframework.data.repository.query.parser.Part; 28 | import org.springframework.data.repository.query.parser.PartTree; 29 | import org.springframework.util.Assert; 30 | 31 | import java.util.Collection; 32 | import java.util.Iterator; 33 | import java.util.List; 34 | 35 | /** 36 | * EbeanQueryWrapper creator to create a {@link io.ebean.Expression} from a {@link PartTree}. 37 | * 38 | * @author Xuegui Yuan 39 | */ 40 | public class EbeanQueryCreator extends AbstractQueryCreator { 41 | 42 | private final ExpressionList root; 43 | private final ParameterMetadataProvider provider; 44 | private final ReturnedType returnedType; 45 | private final PartTree tree; 46 | 47 | /** 48 | * Create a new {@link EbeanQueryCreator}. 49 | * 50 | * @param tree must not be {@literal null}. 51 | * @param type must not be {@literal null}. 52 | * @param expressionList must not be {@literal null}. 53 | * @param provider must not be {@literal null}. 54 | */ 55 | public EbeanQueryCreator(PartTree tree, ReturnedType type, ExpressionList expressionList, 56 | ParameterMetadataProvider provider) { 57 | super(tree); 58 | this.tree = tree; 59 | 60 | this.root = expressionList; 61 | this.provider = provider; 62 | this.returnedType = type; 63 | } 64 | 65 | /** 66 | * Returns all {@link ParameterMetadataProvider.ParameterMetadata} created when creating the query. 67 | * 68 | * @return the parameterExpressions 69 | */ 70 | public List> getParameterExpressions() { 71 | return provider.getExpressions(); 72 | } 73 | 74 | /* 75 | * (non-Javadoc) 76 | * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#create(org.springframework.data.repository.query.parser.Part, java.util.Iterator) 77 | */ 78 | @Override 79 | protected Expression create(Part part, Iterator iterator) { 80 | return toExpression(part, root); 81 | } 82 | 83 | /* 84 | * (non-Javadoc) 85 | * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#and(org.springframework.data.repository.query.parser.Part, java.lang.Object, java.util.Iterator) 86 | */ 87 | @Override 88 | protected Expression and(Part part, Expression base, Iterator iterator) { 89 | return Expr.and(base, toExpression(part, root)); 90 | } 91 | 92 | /* 93 | * (non-Javadoc) 94 | * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#or(java.lang.Object, java.lang.Object) 95 | */ 96 | @Override 97 | protected Expression or(Expression base, Expression expression) { 98 | return Expr.or(base, expression); 99 | } 100 | 101 | /** 102 | * Finalizes the given {@link ExpressionList} and applies the given sort. 103 | */ 104 | @Override 105 | protected final Query complete(Expression expression, Sort sort) { 106 | return root.add(expression).query(); 107 | } 108 | 109 | /** 110 | * Creates a {@link ExpressionList} from the given {@link Part}. 111 | * 112 | * @param part 113 | * @param root 114 | * @return 115 | */ 116 | private Expression toExpression(Part part, ExpressionList root) { 117 | return new ExpressionBuilder(part, root).build(); 118 | } 119 | 120 | /** 121 | * Simple builder to contain logic to create Ebean {@link Expression}s from {@link Part}s. 122 | * 123 | * @author Xuegui Yuan 124 | */ 125 | @SuppressWarnings({"unchecked", "rawtypes"}) 126 | private class ExpressionBuilder { 127 | 128 | private final Part part; 129 | private final ExpressionList root; 130 | 131 | /** 132 | * Creates a new {@link ExpressionBuilder} for the given {@link Part} and {@link ExpressionList}. 133 | * 134 | * @param part must not be {@literal null}. 135 | * @param root must not be {@literal null}. 136 | */ 137 | public ExpressionBuilder(Part part, ExpressionList root) { 138 | Assert.notNull(part, "Part must not be null!"); 139 | Assert.notNull(root, "ExpressionList must not be null!"); 140 | this.part = part; 141 | this.root = root; 142 | } 143 | 144 | /** 145 | * Builds a Ebean {@link Expression} from the underlying {@link Part}. 146 | * 147 | * @return 148 | */ 149 | public Expression build() { 150 | PropertyPath property = part.getProperty(); 151 | Part.Type type = part.getType(); 152 | 153 | switch (type) { 154 | case BETWEEN: 155 | ParameterMetadataProvider.ParameterMetadata first = provider.next(part); 156 | ParameterMetadataProvider.ParameterMetadata second = provider.next(part); 157 | return Expr.between(property.toDotPath(), first.getParameterValue(), second.getParameterValue()); 158 | case AFTER: 159 | case GREATER_THAN: 160 | return Expr.gt(property.toDotPath(), provider.next(part).getParameterValue()); 161 | case GREATER_THAN_EQUAL: 162 | return Expr.ge(property.toDotPath(), provider.next(part).getParameterValue()); 163 | case BEFORE: 164 | case LESS_THAN: 165 | return Expr.lt(property.toDotPath(), provider.next(part).getParameterValue()); 166 | case LESS_THAN_EQUAL: 167 | return Expr.le(property.toDotPath(), provider.next(part).getParameterValue()); 168 | case IS_NULL: 169 | return Expr.isNull(property.toDotPath()); 170 | case IS_NOT_NULL: 171 | return Expr.isNotNull(property.toDotPath()); 172 | case NOT_IN: 173 | ParameterMetadataProvider.ParameterMetadata pmNotIn = provider.next(part, Collection.class); 174 | return Expr.not(Expr.in(property.toDotPath(), ParameterMetadataProvider.ParameterMetadata.toCollection(pmNotIn.getParameterValue()))); 175 | case IN: 176 | ParameterMetadataProvider.ParameterMetadata pmIn = provider.next(part, Collection.class); 177 | return Expr.in(property.toDotPath(), ParameterMetadataProvider.ParameterMetadata.toCollection(pmIn.getParameterValue())); 178 | case STARTING_WITH: 179 | return Expr.startsWith(property.toDotPath(), (String) provider.next(part).getParameterValue()); 180 | case ENDING_WITH: 181 | return Expr.endsWith(property.toDotPath(), (String) provider.next(part).getParameterValue()); 182 | case CONTAINING: 183 | return Expr.contains(property.toDotPath(), (String) provider.next(part).getParameterValue()); 184 | case NOT_CONTAINING: 185 | return Expr.not(Expr.contains(property.toDotPath(), (String) provider.next(part).getParameterValue())); 186 | case LIKE: 187 | return Expr.like(property.toDotPath(), (String) provider.next(part).getParameterValue()); 188 | case NOT_LIKE: 189 | return Expr.not(Expr.like(property.toDotPath(), (String) provider.next(part).getParameterValue())); 190 | case TRUE: 191 | return Expr.eq(property.toDotPath(), true); 192 | case FALSE: 193 | return Expr.eq(property.toDotPath(), false); 194 | case SIMPLE_PROPERTY: 195 | ParameterMetadataProvider.ParameterMetadata pmEquals = provider.next(part); 196 | return pmEquals.isIsNullParameter() ? Expr.isNull(property.toDotPath()) 197 | : Expr.eq(property.toDotPath(), pmEquals.getParameterValue()); 198 | case NEGATING_SIMPLE_PROPERTY: 199 | ParameterMetadataProvider.ParameterMetadata pmNot = provider.next(part); 200 | return pmNot.isIsNullParameter() ? Expr.isNull(property.toDotPath()) 201 | : Expr.ne(property.toDotPath(), pmNot.getParameterValue()); 202 | // case IS_EMPTY: 203 | // return Expr.isEmpty(property.toDotPath()); 204 | // case IS_NOT_EMPTY: 205 | // return Expr.isNotEmpty(property.toDotPath()); 206 | default: 207 | throw new IllegalArgumentException("Unsupported keyword " + type); 208 | } 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/EbeanQueryFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import io.ebean.Query; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | import org.springframework.data.repository.query.QueryMethod; 24 | import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; 25 | import org.springframework.data.repository.query.RepositoryQuery; 26 | import org.springframework.expression.spel.standard.SpelExpressionParser; 27 | 28 | 29 | /** 30 | * Factory to create the appropriate {@link RepositoryQuery} for a {@link EbeanQueryMethod}. 31 | * 32 | * @author Xuegui Yuan 33 | */ 34 | enum EbeanQueryFactory { 35 | 36 | /** 37 | * Instance 38 | */ 39 | INSTANCE; 40 | 41 | private static final SpelExpressionParser PARSER = new SpelExpressionParser(); 42 | private static final Logger LOG = LoggerFactory.getLogger(EbeanQueryFactory.class); 43 | 44 | /** 45 | * Creates a {@link RepositoryQuery} from the given {@link QueryMethod} that is potentially annotated with 46 | * {@link Query}. 47 | * 48 | * @param method must not be {@literal null}. 49 | * @param ebeanServer must not be {@literal null}. 50 | * @param evaluationContextProvider 51 | * @return the {@link RepositoryQuery} derived from the annotation or {@code null} if no annotation found. 52 | */ 53 | AbstractEbeanQuery fromQueryAnnotation(EbeanQueryMethod method, EbeanServer ebeanServer, 54 | QueryMethodEvaluationContextProvider evaluationContextProvider) { 55 | 56 | LOG.debug("Looking up query for method {}", method.getName()); 57 | return fromMethodWithQueryString(method, ebeanServer, method.getAnnotatedQuery(), evaluationContextProvider); 58 | } 59 | 60 | /** 61 | * Creates a {@link RepositoryQuery} from the given {@link String} query. 62 | * 63 | * @param method must not be {@literal null}. 64 | * @param ebeanServer must not be {@literal null}. 65 | * @param queryString must not be {@literal null} or empty. 66 | * @param evaluationContextProvider 67 | * @return 68 | */ 69 | AbstractEbeanQuery fromMethodWithQueryString(EbeanQueryMethod method, EbeanServer ebeanServer, String queryString, 70 | QueryMethodEvaluationContextProvider evaluationContextProvider) { 71 | 72 | if (queryString == null) { 73 | return null; 74 | } 75 | // native 76 | if (method.isNativeQuery()) { 77 | if (method.isModifyingQuery()) { 78 | return new NativeEbeanUpdate(method, ebeanServer, queryString, evaluationContextProvider, PARSER); 79 | } else { 80 | return new NativeEbeanQuery(method, ebeanServer, queryString, evaluationContextProvider, PARSER); 81 | } 82 | } else { // ORM 83 | if (method.isModifyingQuery()) { 84 | return new OrmEbeanUpdate(method, ebeanServer, queryString, evaluationContextProvider, PARSER); 85 | } else { 86 | return new OrmEbeanQuery(method, ebeanServer, queryString, evaluationContextProvider, PARSER); 87 | } 88 | } 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/EbeanQueryLookupStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.data.ebean.annotation.Query; 21 | import org.springframework.data.projection.ProjectionFactory; 22 | import org.springframework.data.repository.core.NamedQueries; 23 | import org.springframework.data.repository.core.RepositoryMetadata; 24 | import org.springframework.data.repository.query.QueryLookupStrategy; 25 | import org.springframework.data.repository.query.QueryLookupStrategy.Key; 26 | import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; 27 | import org.springframework.data.repository.query.RepositoryQuery; 28 | import org.springframework.util.Assert; 29 | 30 | import java.lang.reflect.Method; 31 | 32 | /** 33 | * EbeanQueryWrapper lookup strategy to execute finders. 34 | * 35 | * @author Xuegui Yuan 36 | */ 37 | public final class EbeanQueryLookupStrategy { 38 | 39 | /** 40 | * Private constructor to prevent instantiation. 41 | */ 42 | private EbeanQueryLookupStrategy() { 43 | } 44 | 45 | /** 46 | * Creates a {@link QueryLookupStrategy} for the given {@link EbeanServer} and {@link Key}. 47 | * 48 | * @param ebeanServer must not be {@literal null}. 49 | * @param key may be {@literal null}. 50 | * @param evaluationContextProvider must not be {@literal null}. 51 | * @return 52 | */ 53 | public static QueryLookupStrategy create(EbeanServer ebeanServer, Key key, 54 | QueryMethodEvaluationContextProvider evaluationContextProvider) { 55 | 56 | Assert.notNull(ebeanServer, "EbeanServer must not be null!"); 57 | Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null!"); 58 | 59 | switch (key != null ? key : Key.CREATE_IF_NOT_FOUND) { 60 | case CREATE: 61 | return new CreateQueryLookupStrategy(ebeanServer); 62 | case USE_DECLARED_QUERY: 63 | return new DeclaredQueryLookupStrategy(ebeanServer, evaluationContextProvider); 64 | case CREATE_IF_NOT_FOUND: 65 | return new CreateIfNotFoundQueryLookupStrategy(ebeanServer, new CreateQueryLookupStrategy(ebeanServer), 66 | new DeclaredQueryLookupStrategy(ebeanServer, evaluationContextProvider)); 67 | default: 68 | throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key)); 69 | } 70 | } 71 | 72 | /** 73 | * {@link QueryLookupStrategy} to create a query from the method name. 74 | * 75 | * @author Xuegui Yuan 76 | */ 77 | private static class CreateQueryLookupStrategy extends AbstractQueryLookupStrategy { 78 | 79 | public CreateQueryLookupStrategy(EbeanServer ebeanServer) { 80 | 81 | super(ebeanServer); 82 | } 83 | 84 | @Override 85 | protected RepositoryQuery resolveQuery(EbeanQueryMethod method, EbeanServer ebeanServer, NamedQueries namedQueries) { 86 | 87 | try { 88 | return new PartTreeEbeanQuery(method, ebeanServer); 89 | } catch (IllegalArgumentException e) { 90 | throw new IllegalArgumentException( 91 | String.format("Could not create query metamodel for method %s!", method.toString()), e); 92 | } 93 | } 94 | 95 | } 96 | 97 | /** 98 | * Base class for {@link QueryLookupStrategy} implementations that need access to an {@link EbeanServer}. 99 | * 100 | * @author Oliver Gierke 101 | * @author Thomas Darimont 102 | */ 103 | private abstract static class AbstractQueryLookupStrategy implements QueryLookupStrategy { 104 | 105 | private final EbeanServer ebeanServer; 106 | 107 | /** 108 | * Creates a new {@link AbstractQueryLookupStrategy}. 109 | * 110 | * @param ebeanServer 111 | */ 112 | public AbstractQueryLookupStrategy(EbeanServer ebeanServer) { 113 | this.ebeanServer = ebeanServer; 114 | } 115 | 116 | @Override 117 | public final RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory, 118 | NamedQueries namedQueries) { 119 | return resolveQuery(new EbeanQueryMethod(method, metadata, factory), ebeanServer, namedQueries); 120 | } 121 | 122 | /** 123 | * Resolve query to return .RepositoryQuery 124 | * 125 | * @param method 126 | * @param ebeanServer 127 | * @param namedQueries 128 | * @return RepositoryQuery 129 | */ 130 | protected abstract RepositoryQuery resolveQuery(EbeanQueryMethod method, EbeanServer ebeanServer, NamedQueries namedQueries); 131 | } 132 | 133 | /** 134 | * {@link QueryLookupStrategy} to try to detect a declared query first ( 135 | * {@link Query}, ebean named query). In case none is found we fall back on 136 | * query creation. 137 | * 138 | * @author Oliver Gierke 139 | * @author Thomas Darimont 140 | */ 141 | private static class CreateIfNotFoundQueryLookupStrategy extends AbstractQueryLookupStrategy { 142 | 143 | private final DeclaredQueryLookupStrategy lookupStrategy; 144 | private final CreateQueryLookupStrategy createStrategy; 145 | 146 | /** 147 | * Creates a new {@link CreateIfNotFoundQueryLookupStrategy}. 148 | * 149 | * @param ebeanServer 150 | * @param createStrategy 151 | * @param lookupStrategy 152 | */ 153 | public CreateIfNotFoundQueryLookupStrategy(EbeanServer ebeanServer, 154 | CreateQueryLookupStrategy createStrategy, DeclaredQueryLookupStrategy lookupStrategy) { 155 | super(ebeanServer); 156 | 157 | this.createStrategy = createStrategy; 158 | this.lookupStrategy = lookupStrategy; 159 | } 160 | 161 | /* 162 | * (non-Javadoc) 163 | * @see org.springframework.data.ebean.repository.query.ebeanQueryLookupStrategy.AbstractQueryLookupStrategy#resolveQuery(org.springframework.data.ebean.repository.query.ebeanQueryMethod, javax.persistence.EntityManager, org.springframework.data.repository.core.NamedQueries) 164 | */ 165 | @Override 166 | protected RepositoryQuery resolveQuery(EbeanQueryMethod method, EbeanServer ebeanServer, NamedQueries namedQueries) { 167 | try { 168 | return lookupStrategy.resolveQuery(method, ebeanServer, namedQueries); 169 | } catch (IllegalStateException e) { 170 | return createStrategy.resolveQuery(method, ebeanServer, namedQueries); 171 | } 172 | } 173 | } 174 | 175 | /** 176 | * {@link QueryLookupStrategy} that tries to detect a declared query declared via {@link io.ebean.Query} annotation followed by 177 | * a ebean named query lookup. 178 | * 179 | * @author Oliver Gierke 180 | * @author Thomas Darimont 181 | */ 182 | private static class DeclaredQueryLookupStrategy extends AbstractQueryLookupStrategy { 183 | 184 | private final QueryMethodEvaluationContextProvider evaluationContextProvider; 185 | 186 | /** 187 | * Creates a new {@link DeclaredQueryLookupStrategy}. 188 | * 189 | * @param ebeanServer 190 | * @param evaluationContextProvider 191 | */ 192 | public DeclaredQueryLookupStrategy(EbeanServer ebeanServer, 193 | QueryMethodEvaluationContextProvider evaluationContextProvider) { 194 | super(ebeanServer); 195 | this.evaluationContextProvider = evaluationContextProvider; 196 | } 197 | 198 | /* 199 | * (non-Javadoc) 200 | * @see org.springframework.data.ebean.repository.query.ebeanQueryLookupStrategy.AbstractQueryLookupStrategy#resolveQuery(org.springframework.data.ebean.repository.query.ebeanQueryMethod, javax.persistence.EntityManager, org.springframework.data.repository.core.NamedQueries) 201 | */ 202 | @Override 203 | protected RepositoryQuery resolveQuery(EbeanQueryMethod method, EbeanServer ebeanServer, NamedQueries namedQueries) { 204 | RepositoryQuery query = EbeanQueryFactory.INSTANCE.fromQueryAnnotation(method, ebeanServer, evaluationContextProvider); 205 | 206 | if (null != query) { 207 | return query; 208 | } 209 | 210 | String name = method.getNamedQueryName(); 211 | if (namedQueries.hasQuery(name)) { 212 | return EbeanQueryFactory.INSTANCE.fromMethodWithQueryString(method, ebeanServer, namedQueries.getQuery(name), 213 | evaluationContextProvider); 214 | } 215 | 216 | query = NamedEbeanQuery.lookupFrom(method, ebeanServer); 217 | 218 | if (null != query) { 219 | return query; 220 | } 221 | 222 | throw new IllegalStateException( 223 | String.format("Did neither find a NamedQuery nor an annotated query for method %s!", method)); 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/EbeanQueryMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import org.springframework.core.annotation.AnnotatedElementUtils; 20 | import org.springframework.core.annotation.AnnotationUtils; 21 | import org.springframework.data.ebean.annotation.Modifying; 22 | import org.springframework.data.ebean.annotation.Query; 23 | import org.springframework.data.projection.ProjectionFactory; 24 | import org.springframework.data.repository.core.RepositoryMetadata; 25 | import org.springframework.data.repository.query.QueryMethod; 26 | import org.springframework.util.Assert; 27 | import org.springframework.util.StringUtils; 28 | 29 | import java.lang.annotation.Annotation; 30 | import java.lang.reflect.Method; 31 | 32 | /** 33 | * Ebean specific extension of {@link QueryMethod}. 34 | * 35 | * @author Xuegui Yuan 36 | */ 37 | public class EbeanQueryMethod extends QueryMethod { 38 | 39 | private final Method method; 40 | 41 | /** 42 | * Creates a {@link EbeanQueryMethod}. 43 | * 44 | * @param method must not be {@literal null} 45 | * @param metadata must not be {@literal null} 46 | */ 47 | public EbeanQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory) { 48 | super(method, metadata, factory); 49 | 50 | Assert.notNull(method, "Method must not be null!"); 51 | 52 | this.method = method; 53 | } 54 | 55 | /** 56 | * Returns the actual return type of the method. 57 | * 58 | * @return 59 | */ 60 | Class getReturnType() { 61 | return method.getReturnType(); 62 | } 63 | 64 | /** 65 | * Returns the query string declared in a {@link Query} annotation or {@literal null} if neither the annotation found 66 | * nor the attribute was specified. 67 | * 68 | * @return 69 | */ 70 | String getAnnotatedQuery() { 71 | String query = getAnnotationValue("value", String.class); 72 | return StringUtils.hasText(query) ? query : null; 73 | } 74 | 75 | /** 76 | * Returns the {@link Query} annotation's attribute casted to the given type or default value if no annotation 77 | * available. 78 | * 79 | * @param attribute 80 | * @param type 81 | * @return 82 | */ 83 | private T getAnnotationValue(String attribute, Class type) { 84 | return getMergedOrDefaultAnnotationValue(attribute, Query.class, type); 85 | } 86 | 87 | @SuppressWarnings({"rawtypes", "unchecked"}) 88 | private T getMergedOrDefaultAnnotationValue(String attribute, Class annotationType, Class targetType) { 89 | Annotation annotation = AnnotatedElementUtils.findMergedAnnotation(method, annotationType); 90 | if (annotation == null) { 91 | return targetType.cast(AnnotationUtils.getDefaultValue(annotationType, attribute)); 92 | } 93 | 94 | return targetType.cast(AnnotationUtils.getValue(annotation, attribute)); 95 | } 96 | 97 | /** 98 | * Returns whether the backing query is a native one. 99 | * 100 | * @return 101 | */ 102 | boolean isNativeQuery() { 103 | return getAnnotationValue("nativeQuery", Boolean.class).booleanValue(); 104 | } 105 | 106 | /* 107 | * (non-Javadoc) 108 | * @see org.springframework.data.repository.query.QueryMethod#getNamedQueryName() 109 | */ 110 | @Override 111 | public String getNamedQueryName() { 112 | String annotatedName = getAnnotationValue("name", String.class); 113 | return StringUtils.hasText(annotatedName) ? annotatedName : super.getNamedQueryName(); 114 | } 115 | 116 | /** 117 | * Returns whether the finder is a modifying one. 118 | * 119 | * @return 120 | */ 121 | @Override 122 | public boolean isModifyingQuery() { 123 | return null != AnnotationUtils.findAnnotation(method, Modifying.class); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/EbeanQueryWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.PagedList; 20 | import io.ebean.Query; 21 | import io.ebean.SqlUpdate; 22 | import io.ebean.Update; 23 | import org.springframework.data.domain.Page; 24 | import org.springframework.data.domain.Pageable; 25 | import org.springframework.data.domain.Slice; 26 | import org.springframework.data.domain.SliceImpl; 27 | import org.springframework.data.repository.support.PageableExecutionUtils; 28 | import org.springframework.data.util.StreamUtils; 29 | 30 | import java.util.List; 31 | import java.util.stream.Stream; 32 | 33 | import static org.springframework.data.ebean.repository.query.EbeanQueryWrapper.QueryType.QUERY; 34 | 35 | /** 36 | * Ebean query wrapper, wrap Query、Update、SqlUpdate. 37 | * 38 | * @author Xuegui Yuan 39 | */ 40 | public class EbeanQueryWrapper { 41 | private QueryType queryType; 42 | private T queryInstance; 43 | 44 | public EbeanQueryWrapper(T queryInstance) { 45 | this.queryInstance = queryInstance; 46 | if (queryInstance instanceof Query) { 47 | this.queryType = QUERY; 48 | } else if (queryInstance instanceof Update) { 49 | this.queryType = QueryType.UPDATE; 50 | } else if (queryInstance instanceof SqlUpdate) { 51 | this.queryType = QueryType.SQL_UPDATE; 52 | } else { 53 | throw new IllegalArgumentException("query not supported!"); 54 | } 55 | } 56 | 57 | static EbeanQueryWrapper ofEbeanQuery(T queryInstance) { 58 | return new EbeanQueryWrapper(queryInstance); 59 | } 60 | 61 | void setParameter(String name, Object value) { 62 | switch (queryType) { 63 | case QUERY: 64 | ((Query) queryInstance).setParameter(name, value); 65 | break; 66 | case UPDATE: 67 | ((Update) queryInstance).setParameter(name, value); 68 | break; 69 | case SQL_UPDATE: 70 | ((SqlUpdate) queryInstance).setParameter(name, value); 71 | break; 72 | default: 73 | throw new IllegalArgumentException("query not supported!"); 74 | } 75 | } 76 | 77 | void setParameter(int position, Object value) { 78 | switch (queryType) { 79 | case QUERY: 80 | ((Query) queryInstance).setParameter(position, value); 81 | break; 82 | case UPDATE: 83 | ((Update) queryInstance).setParameter(position, value); 84 | break; 85 | case SQL_UPDATE: 86 | ((SqlUpdate) queryInstance).setParameter(position, value); 87 | break; 88 | default: 89 | throw new IllegalArgumentException("query not supported!"); 90 | } 91 | } 92 | 93 | @SuppressWarnings("unchecked") 94 | E findOne() { 95 | if (queryType == QUERY) { 96 | return ((Query) queryInstance).findOne(); 97 | } 98 | throw new IllegalArgumentException("query not supported!"); 99 | } 100 | 101 | @SuppressWarnings("unchecked") 102 | Page findPage(Pageable pageable) { 103 | if (queryType == QUERY) { 104 | PagedList pagedList = ((Query) queryInstance) 105 | .setFirstRow((int) pageable.getOffset()) 106 | .setMaxRows(pageable.getPageSize()) 107 | .findPagedList(); 108 | return PageableExecutionUtils.getPage(pagedList.getList(), pageable, pagedList::getTotalCount); 109 | 110 | } 111 | throw new IllegalArgumentException("query not supported!"); 112 | } 113 | 114 | int update() { 115 | switch (queryType) { 116 | case QUERY: 117 | return ((Query) queryInstance).update(); 118 | case UPDATE: 119 | return ((Update) queryInstance).execute(); 120 | case SQL_UPDATE: 121 | return ((SqlUpdate) queryInstance).execute(); 122 | default: 123 | throw new IllegalArgumentException("query not supported!"); 124 | } 125 | } 126 | 127 | int delete() { 128 | switch (queryType) { 129 | case QUERY: 130 | return ((Query) queryInstance).delete(); 131 | case UPDATE: 132 | return ((Update) queryInstance).execute(); 133 | case SQL_UPDATE: 134 | return ((SqlUpdate) queryInstance).execute(); 135 | default: 136 | throw new IllegalArgumentException("query not supported!"); 137 | } 138 | } 139 | 140 | boolean isExists() { 141 | if (queryType == QUERY) { 142 | return ((Query) queryInstance).findCount() > 0; 143 | } 144 | throw new IllegalArgumentException("query not supported!"); 145 | } 146 | 147 | @SuppressWarnings("unchecked") 148 | Stream findStream() { 149 | if (queryType == QUERY) { 150 | return StreamUtils.createStreamFromIterator(((Query) queryInstance).findIterate()); 151 | } 152 | throw new IllegalArgumentException("query not supported!"); 153 | } 154 | 155 | @SuppressWarnings("unchecked") 156 | List findList() { 157 | if (queryType == QUERY) { 158 | return ((Query) queryInstance).findList(); 159 | } 160 | throw new IllegalArgumentException("query not supported!"); 161 | } 162 | 163 | @SuppressWarnings("unchecked") 164 | Slice findSlice(Pageable pageable) { 165 | List resultList = null; 166 | int pageSize = pageable.getPageSize(); 167 | int offset = (int) pageable.getOffset(); 168 | if (queryType == QUERY) { 169 | resultList = ((Query) queryInstance).setFirstRow(offset).setMaxRows(pageSize + 1).findList(); 170 | boolean hasNext = resultList.size() > pageSize; 171 | return new SliceImpl(hasNext ? resultList.subList(0, pageSize) : resultList, pageable, hasNext); 172 | } 173 | throw new IllegalArgumentException("query not supported!"); 174 | } 175 | 176 | Integer getMaxRows() { 177 | if (queryType == QUERY) { 178 | return ((Query) queryInstance).getMaxRows(); 179 | } 180 | throw new IllegalArgumentException("query not supported!"); 181 | } 182 | 183 | void setMaxRows(int maxRows) { 184 | if (queryType == QUERY) { 185 | ((Query) queryInstance).setMaxRows(maxRows); 186 | return; 187 | } 188 | throw new IllegalArgumentException("query not supported!"); 189 | } 190 | 191 | int getFirstRow() { 192 | if (queryType == QUERY) { 193 | return ((Query) queryInstance).getFirstRow(); 194 | } 195 | throw new IllegalArgumentException("query not supported!"); 196 | } 197 | 198 | void setFirstRow(int firstRow) { 199 | if (queryType == QUERY) { 200 | ((Query) queryInstance).setFirstRow(firstRow); 201 | return; 202 | } 203 | throw new IllegalArgumentException("query not supported!"); 204 | } 205 | 206 | public QueryType getQueryType() { 207 | return queryType; 208 | } 209 | 210 | public T getQueryInstance() { 211 | return queryInstance; 212 | } 213 | 214 | public enum QueryType { 215 | /** 216 | * Query 217 | */ 218 | QUERY, 219 | /** 220 | * Update 221 | */ 222 | UPDATE, 223 | /** 224 | * SqlUpdate 225 | */ 226 | SQL_UPDATE; 227 | } 228 | 229 | } 230 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/ExpressionBasedStringQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import org.springframework.data.repository.core.EntityMetadata; 20 | import org.springframework.expression.Expression; 21 | import org.springframework.expression.ParserContext; 22 | import org.springframework.expression.spel.standard.SpelExpressionParser; 23 | import org.springframework.expression.spel.support.StandardEvaluationContext; 24 | import org.springframework.util.Assert; 25 | 26 | import java.util.regex.Pattern; 27 | 28 | /** 29 | * Extension of {@link StringQuery} that evaluates the given query string as a SpEL template-expression. 30 | *

31 | * Currently the following template variables are available: 32 | *

    33 | *
  1. {@code #entityName} - the simple class name of the given entity
  2. 34 | *
      35 | * 36 | * @author Xuegui Yuan 37 | */ 38 | class ExpressionBasedStringQuery extends StringQuery { 39 | 40 | private static final String EXPRESSION_PARAMETER = "?#{"; 41 | private static final String QUOTED_EXPRESSION_PARAMETER = "?__HASH__{"; 42 | 43 | private static final Pattern EXPRESSION_PARAMETER_QUOTING = Pattern.compile(Pattern.quote(EXPRESSION_PARAMETER)); 44 | private static final Pattern EXPRESSION_PARAMETER_UNQUOTING = Pattern.compile(Pattern 45 | .quote(QUOTED_EXPRESSION_PARAMETER)); 46 | 47 | private static final String ENTITY_NAME = "entityName"; 48 | private static final String ENTITY_NAME_VARIABLE = "#" + ENTITY_NAME; 49 | private static final String ENTITY_NAME_VARIABLE_EXPRESSION = "#{" + ENTITY_NAME_VARIABLE + "}"; 50 | 51 | /** 52 | * Creates a new {@link ExpressionBasedStringQuery} for the given query and {@link EntityMetadata}. 53 | * 54 | * @param query must not be {@literal null} or empty. 55 | * @param metadata must not be {@literal null}. 56 | * @param parser must not be {@literal null}. 57 | */ 58 | public ExpressionBasedStringQuery(String query, EntityMetadata metadata, SpelExpressionParser parser) { 59 | super(renderQueryIfExpressionOrReturnQuery(query, metadata, parser)); 60 | } 61 | 62 | /** 63 | * @param query, the query expression potentially containing a SpEL expression. Must not be {@literal null}.} 64 | * @param metadata the {@link EntityMetadata} for the given entity. Must not be {@literal null}. 65 | * @param parser Must not be {@literal null}. 66 | * @return 67 | */ 68 | private static String renderQueryIfExpressionOrReturnQuery(String query, EntityMetadata metadata, 69 | SpelExpressionParser parser) { 70 | 71 | Assert.notNull(query, "query must not be null!"); 72 | Assert.notNull(metadata, "metadata must not be null!"); 73 | Assert.notNull(parser, "parser must not be null!"); 74 | 75 | if (!containsExpression(query)) { 76 | return query; 77 | } 78 | 79 | StandardEvaluationContext evalContext = new StandardEvaluationContext(); 80 | evalContext.setVariable(ENTITY_NAME, metadata.getJavaType().getName()); 81 | 82 | query = potentiallyQuoteExpressionsParameter(query); 83 | 84 | Expression expr = parser.parseExpression(query, ParserContext.TEMPLATE_EXPRESSION); 85 | 86 | String result = expr.getValue(evalContext, String.class); 87 | 88 | if (result == null) { 89 | return query; 90 | } 91 | 92 | return potentiallyUnquoteParameterExpressions(result); 93 | } 94 | 95 | private static boolean containsExpression(String query) { 96 | return query.contains(ENTITY_NAME_VARIABLE_EXPRESSION); 97 | } 98 | 99 | private static String potentiallyQuoteExpressionsParameter(String query) { 100 | return EXPRESSION_PARAMETER_QUOTING.matcher(query).replaceAll(QUOTED_EXPRESSION_PARAMETER); 101 | } 102 | 103 | private static String potentiallyUnquoteParameterExpressions(String result) { 104 | return EXPRESSION_PARAMETER_UNQUOTING.matcher(result).replaceAll(EXPRESSION_PARAMETER); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/InvalidEbeanQueryMethodException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | /** 20 | * Signals that we encountered an invalid query method. 21 | * 22 | * @author Xuegui Yuan 23 | */ 24 | public class InvalidEbeanQueryMethodException extends RuntimeException { 25 | 26 | private static final long serialVersionUID = 1L; 27 | 28 | /** 29 | * Creates a new {@link InvalidEbeanQueryMethodException} with the given message. 30 | * 31 | * @param message must not be {@literal null} or empty. 32 | */ 33 | public InvalidEbeanQueryMethodException(String message) { 34 | super(message); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/NamedEbeanQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import io.ebean.Query; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | import org.springframework.data.repository.query.QueryMethod; 24 | import org.springframework.data.repository.query.RepositoryQuery; 25 | 26 | import javax.persistence.PersistenceException; 27 | 28 | /** 29 | * {@link RepositoryQuery} implementation that inspects a {@link QueryMethod} 30 | * for the existence of an {@link org.springframework.data.ebean.annotation.Query} annotation and creates a Ebean named 31 | * {@link io.ebean.Query} from it. 32 | * 33 | * @author Xuegui Yuan 34 | */ 35 | final class NamedEbeanQuery extends AbstractEbeanQuery { 36 | 37 | private static final Logger LOG = LoggerFactory.getLogger(NamedEbeanQuery.class); 38 | 39 | private final String queryName; 40 | private Query query; 41 | 42 | /** 43 | * Creates a new {@link NamedEbeanQuery}. 44 | */ 45 | private NamedEbeanQuery(EbeanQueryMethod method, EbeanServer ebeanServer, Query query) { 46 | super(method, ebeanServer); 47 | 48 | this.queryName = method.getNamedQueryName(); 49 | this.query = query; 50 | } 51 | 52 | /** 53 | * Looks up a named query for the given {@link org.springframework.data.repository.query.QueryMethod}. 54 | * 55 | * @param method 56 | * @return 57 | */ 58 | public static RepositoryQuery lookupFrom(EbeanQueryMethod method, EbeanServer ebeanServer) { 59 | final String queryName = method.getNamedQueryName(); 60 | 61 | LOG.debug("Looking up named query {}", queryName); 62 | 63 | try { 64 | Query query = ebeanServer.createNamedQuery(method.getEntityInformation().getJavaType(), queryName); 65 | return new NamedEbeanQuery(method, ebeanServer, query); 66 | } catch (PersistenceException e) { 67 | LOG.debug("Did not find named query {}", queryName); 68 | return null; 69 | } 70 | } 71 | 72 | @Override 73 | protected EbeanQueryWrapper doCreateQuery(Object[] values) { 74 | return createBinder(values).bindAndPrepare(EbeanQueryWrapper.ofEbeanQuery(query)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/NativeEbeanQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.data.ebean.annotation.Query; 21 | import org.springframework.data.repository.query.*; 22 | import org.springframework.expression.spel.standard.SpelExpressionParser; 23 | 24 | /** 25 | * {@link RepositoryQuery} implementation that inspects a {@link org.springframework.data.repository.query.QueryMethod} 26 | * for the existence of an {@link Query} annotation and creates a Ebean native 27 | * {@link io.ebean.Query} from it. 28 | * 29 | * @author Xuegui Yuan 30 | */ 31 | final class NativeEbeanQuery extends AbstractStringBasedEbeanQuery { 32 | 33 | /** 34 | * Creates a new {@link NativeEbeanQuery} encapsulating the query annotated on the given {@link EbeanQueryMethod}. 35 | * 36 | * @param method must not be {@literal null}. 37 | * @param ebeanServer must not be {@literal null}. 38 | * @param queryString must not be {@literal null} or empty. 39 | * @param evaluationContextProvider 40 | */ 41 | public NativeEbeanQuery(EbeanQueryMethod method, EbeanServer ebeanServer, String queryString, 42 | QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) { 43 | 44 | super(method, ebeanServer, queryString, evaluationContextProvider, parser); 45 | 46 | Parameters parameters = method.getParameters(); 47 | boolean hasPagingOrSortingParameter = parameters.hasPageableParameter() || parameters.hasSortParameter(); 48 | boolean containsPageableOrSortInQueryExpression = queryString.contains("#pageable") 49 | || queryString.contains("#sort"); 50 | 51 | if (hasPagingOrSortingParameter && !containsPageableOrSortInQueryExpression) { 52 | throw new InvalidEbeanQueryMethodException( 53 | "Cannot use native queries with dynamic sorting and/or pagination in method " + method); 54 | } 55 | } 56 | 57 | @Override 58 | protected EbeanQueryWrapper createEbeanQuery(String queryString) { 59 | ResultProcessor resultFactory = getQueryMethod().getResultProcessor(); 60 | ReturnedType returnedType = resultFactory.getReturnedType(); 61 | 62 | return EbeanQueryWrapper.ofEbeanQuery(getEbeanServer().findNative(returnedType.getReturnedType(), queryString)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/NativeEbeanUpdate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.data.ebean.annotation.Query; 21 | import org.springframework.data.repository.query.Parameters; 22 | import org.springframework.data.repository.query.QueryMethod; 23 | import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; 24 | import org.springframework.data.repository.query.RepositoryQuery; 25 | import org.springframework.expression.spel.standard.SpelExpressionParser; 26 | 27 | /** 28 | * {@link RepositoryQuery} implementation that inspects a {@link QueryMethod} 29 | * for the existence of an {@link Query} annotation and creates a Ebean native 30 | * {@link io.ebean.Query} from it. 31 | * 32 | * @author Xuegui Yuan 33 | */ 34 | final class NativeEbeanUpdate extends AbstractStringBasedEbeanQuery { 35 | 36 | /** 37 | * Creates a new {@link NativeEbeanUpdate} encapsulating the query annotated on the given {@link EbeanQueryMethod}. 38 | * 39 | * @param method must not be {@literal null}. 40 | * @param ebeanServer must not be {@literal null}. 41 | * @param queryString must not be {@literal null} or empty. 42 | * @param evaluationContextProvider 43 | */ 44 | public NativeEbeanUpdate(EbeanQueryMethod method, EbeanServer ebeanServer, String queryString, 45 | QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) { 46 | 47 | super(method, ebeanServer, queryString, evaluationContextProvider, parser); 48 | 49 | Parameters parameters = method.getParameters(); 50 | boolean hasPagingOrSortingParameter = parameters.hasPageableParameter() || parameters.hasSortParameter(); 51 | boolean containsPageableOrSortInQueryExpression = queryString.contains("#pageable") 52 | || queryString.contains("#sort"); 53 | 54 | if (hasPagingOrSortingParameter && !containsPageableOrSortInQueryExpression) { 55 | throw new InvalidEbeanQueryMethodException( 56 | "Cannot use native queries with dynamic sorting and/or pagination in method " + method); 57 | } 58 | } 59 | 60 | @Override 61 | protected EbeanQueryWrapper createEbeanQuery(String queryString) { 62 | return EbeanQueryWrapper.ofEbeanQuery(getEbeanServer().createSqlUpdate(queryString)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/OrmEbeanQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.data.ebean.annotation.Query; 21 | import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; 22 | import org.springframework.data.repository.query.RepositoryQuery; 23 | import org.springframework.expression.spel.standard.SpelExpressionParser; 24 | 25 | /** 26 | * {@link RepositoryQuery} implementation that inspects a {@link org.springframework.data.repository.query.QueryMethod} 27 | * for the existence of an {@link Query} annotation and creates a Ebean 28 | * {@link io.ebean.Query} from it. 29 | * 30 | * @author Xuegui Yuan 31 | */ 32 | final class OrmEbeanQuery extends AbstractStringBasedEbeanQuery { 33 | 34 | /** 35 | * Creates a new {@link OrmEbeanQuery} encapsulating the query annotated on the given {@link EbeanQueryMethod}. 36 | * 37 | * @param method must not be {@literal null} 38 | * @param ebeanServer must not be {@literal null} 39 | * @param evaluationContextProvider must not be {@literal null} 40 | * @param parser must not be {@literal null} 41 | */ 42 | public OrmEbeanQuery(EbeanQueryMethod method, EbeanServer ebeanServer, QueryMethodEvaluationContextProvider evaluationContextProvider, 43 | SpelExpressionParser parser) { 44 | this(method, ebeanServer, method.getAnnotatedQuery(), evaluationContextProvider, parser); 45 | } 46 | 47 | /** 48 | * Creates a new {@link OrmEbeanQuery} that encapsulates a simple query string. 49 | * 50 | * @param method must not be {@literal null} 51 | * @param ebeanServer must not be {@literal null} 52 | * @param queryString must not be {@literal null} or empty 53 | * @param evaluationContextProvider must not be {@literal null} 54 | * @param parser must not be {@literal null} 55 | */ 56 | public OrmEbeanQuery(EbeanQueryMethod method, EbeanServer ebeanServer, String queryString, 57 | QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) { 58 | super(method, ebeanServer, queryString, evaluationContextProvider, parser); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/OrmEbeanUpdate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; 21 | import org.springframework.data.repository.query.RepositoryQuery; 22 | import org.springframework.expression.spel.standard.SpelExpressionParser; 23 | 24 | /** 25 | * {@link RepositoryQuery} implementation that inspects a {@link org.springframework.data.repository.query.QueryMethod} 26 | * for the existence of an {@link EbeanUpdate} annotation and creates a Ebean 27 | * {@link io.ebean.Update} from it. 28 | * 29 | * @author Xuegui Yuan 30 | */ 31 | final class OrmEbeanUpdate extends AbstractStringBasedEbeanQuery { 32 | 33 | /** 34 | * Creates a new {@link OrmEbeanUpdate} encapsulating the query annotated on the given {@link EbeanQueryMethod}. 35 | * 36 | * @param method must not be {@literal null} 37 | * @param ebeanServer must not be {@literal null} 38 | * @param evaluationContextProvider must not be {@literal null} 39 | * @param parser must not be {@literal null} 40 | */ 41 | public OrmEbeanUpdate(EbeanQueryMethod method, EbeanServer ebeanServer, QueryMethodEvaluationContextProvider evaluationContextProvider, 42 | SpelExpressionParser parser) { 43 | this(method, ebeanServer, method.getAnnotatedQuery(), evaluationContextProvider, parser); 44 | } 45 | 46 | /** 47 | * Creates a new {@link OrmEbeanUpdate} that encapsulates a simple query string. 48 | * 49 | * @param method must not be {@literal null} 50 | * @param ebeanServer must not be {@literal null} 51 | * @param queryString must not be {@literal null} or empty 52 | * @param evaluationContextProvider must not be {@literal null} 53 | * @param parser must not be {@literal null} 54 | */ 55 | public OrmEbeanUpdate(EbeanQueryMethod method, EbeanServer ebeanServer, String queryString, 56 | QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) { 57 | super(method, ebeanServer, queryString, evaluationContextProvider, parser); 58 | } 59 | 60 | @Override 61 | protected EbeanQueryWrapper createEbeanQuery(String queryString) { 62 | return EbeanQueryWrapper.ofEbeanQuery(getEbeanServer().createUpdate(getQueryMethod().getEntityInformation().getJavaType(), queryString)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/ParameterBinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.Query; 20 | import org.springframework.data.domain.Pageable; 21 | import org.springframework.data.domain.Sort; 22 | import org.springframework.data.repository.query.*; 23 | import org.springframework.util.Assert; 24 | 25 | /** 26 | * {@link ParameterBinder} is used to bind method parameters to a {@link Query}. This is usually done whenever an 27 | * {@link AbstractEbeanQuery} is executed. 28 | * 29 | * @author Xuegui Yuan 30 | */ 31 | public class ParameterBinder { 32 | 33 | private final DefaultParameters parameters; 34 | private final ParameterAccessor accessor; 35 | private final Object[] values; 36 | 37 | ParameterBinder(DefaultParameters parameters) { 38 | this(parameters, new Object[0]); 39 | } 40 | 41 | /** 42 | * Creates a new {@link ParameterBinder}. 43 | * 44 | * @param parameters must not be {@literal null}. 45 | * @param values must not be {@literal null}. 46 | */ 47 | public ParameterBinder(DefaultParameters parameters, Object[] values) { 48 | 49 | Assert.notNull(parameters, "Parameters must not be null!"); 50 | Assert.notNull(values, "Values must not be null!"); 51 | 52 | Assert.isTrue(parameters.getNumberOfParameters() == values.length, "Invalid number of parameters given!"); 53 | 54 | this.parameters = parameters; 55 | this.values = values.clone(); 56 | this.accessor = new ParametersParameterAccessor(parameters, this.values); 57 | } 58 | 59 | /** 60 | * Returns the sort instance to be used for query creation. Will use a {@link Sort} parameter if available or the 61 | * {@link Sort} contained in a {@link Pageable} if available. Returns {@code null} if no {@link Sort} can be found. 62 | * 63 | * @return 64 | */ 65 | public Sort getSort() { 66 | return accessor.getSort(); 67 | } 68 | 69 | /** 70 | * Binds the parameters to the given query and applies special parameter types (e.g. pagination). 71 | * 72 | * @param query must not be {@literal null}. 73 | * @return 74 | */ 75 | public EbeanQueryWrapper bindAndPrepare(EbeanQueryWrapper query) { 76 | Assert.notNull(query, "query must not be null!"); 77 | return bindAndPrepare(query, parameters); 78 | } 79 | 80 | private EbeanQueryWrapper bindAndPrepare(EbeanQueryWrapper query, Parameters parameters) { 81 | EbeanQueryWrapper result = bind(query); 82 | 83 | if (!parameters.hasPageableParameter()) { 84 | return result; 85 | } 86 | 87 | result.setFirstRow((int) getPageable().getOffset()); 88 | result.setMaxRows(getPageable().getPageSize()); 89 | 90 | return result; 91 | } 92 | 93 | /** 94 | * Binds the parameters to the given {@link Query}. 95 | * 96 | * @param query must not be {@literal null}. 97 | * @return 98 | */ 99 | public EbeanQueryWrapper bind(EbeanQueryWrapper query) { 100 | 101 | Assert.notNull(query, "EbeanQueryWrapper must not be null!"); 102 | 103 | int bindableParameterIndex = 0; 104 | int queryParameterPosition = 1; 105 | 106 | for (Parameter parameter : parameters) { 107 | 108 | if (canBindParameter(parameter)) { 109 | 110 | Object value = accessor.getBindableValue(bindableParameterIndex); 111 | bind(query, parameter, value, queryParameterPosition++); 112 | bindableParameterIndex++; 113 | } 114 | } 115 | 116 | return query; 117 | } 118 | 119 | /** 120 | * Returns the {@link Pageable} of the parameters, if available. Returns {@code null} otherwise. 121 | * 122 | * @return 123 | */ 124 | public Pageable getPageable() { 125 | return accessor.getPageable(); 126 | } 127 | 128 | /** 129 | * Returns {@literal true} if the given parameter can be bound. 130 | * 131 | * @param parameter 132 | * @return 133 | */ 134 | protected boolean canBindParameter(Parameter parameter) { 135 | return parameter.isBindable(); 136 | } 137 | 138 | /** 139 | * Perform the actual query parameter binding. 140 | * 141 | * @param query 142 | * @param parameter 143 | * @param value 144 | * @param position 145 | */ 146 | protected void bind(EbeanQueryWrapper query, Parameter parameter, Object value, int position) { 147 | if (parameter.isNamedParameter()) { 148 | query.setParameter(parameter.getName().get(), value); 149 | } else { 150 | query.setParameter(position, value); 151 | } 152 | } 153 | 154 | /** 155 | * Returns the parameters. 156 | * 157 | * @return 158 | */ 159 | Parameters getParameters() { 160 | return parameters; 161 | } 162 | 163 | protected Object[] getValues() { 164 | return values; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/ParameterMetadataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import org.springframework.data.repository.query.Parameter; 20 | import org.springframework.data.repository.query.Parameters; 21 | import org.springframework.data.repository.query.ParametersParameterAccessor; 22 | import org.springframework.data.repository.query.parser.Part; 23 | import org.springframework.data.repository.query.parser.Part.Type; 24 | import org.springframework.util.Assert; 25 | import org.springframework.util.ClassUtils; 26 | import org.springframework.util.ObjectUtils; 27 | 28 | import java.util.*; 29 | 30 | /** 31 | * Helper class to allow easy creation of {@link ParameterMetadata}s. 32 | * 33 | * @author Xuegui Yuan 34 | */ 35 | class ParameterMetadataProvider { 36 | private final Iterator parameters; 37 | private final List> expressions; 38 | private final Iterator bindableParameterValues; 39 | 40 | /** 41 | * Creates a new {@link ParameterMetadataProvider} from the given 42 | * {@link ParametersParameterAccessor} with impl for parameter value customizations. 43 | * 44 | * @param accessor must not be {@literal null}. 45 | */ 46 | public ParameterMetadataProvider(ParametersParameterAccessor accessor) { 47 | this(accessor.iterator(), accessor.getParameters()); 48 | } 49 | 50 | /** 51 | * Creates a new {@link ParameterMetadataProvider} from the given {@link Iterable} of all 52 | * bindable parameter values. 53 | * 54 | * @param bindableParameterValues may be {@literal null}. 55 | * @param parameters must not be {@literal null}. 56 | */ 57 | private ParameterMetadataProvider(Iterator bindableParameterValues, 58 | Parameters parameters) { 59 | Assert.notNull(parameters, "Parameters must not be null!"); 60 | 61 | this.parameters = parameters.getBindableParameters().iterator(); 62 | this.expressions = new ArrayList>(); 63 | this.bindableParameterValues = bindableParameterValues; 64 | } 65 | 66 | /** 67 | * Returns all {@link ParameterMetadata}s built. 68 | * 69 | * @return the expressions 70 | */ 71 | public List> getExpressions() { 72 | return Collections.unmodifiableList(expressions); 73 | } 74 | 75 | /** 76 | * Builds a new {@link ParameterMetadata} for given {@link Part} and the next {@link Parameter}. 77 | * 78 | * @param 79 | * @return 80 | */ 81 | @SuppressWarnings("unchecked") 82 | public ParameterMetadata next(Part part) { 83 | Parameter parameter = parameters.next(); 84 | return (ParameterMetadata) next(part, parameter.getType(), parameter); 85 | } 86 | 87 | /** 88 | * Builds a new {@link ParameterMetadata} for the given type and name. 89 | * 90 | * @param 91 | * @param part must not be {@literal null}. 92 | * @param type parameter type, must not be {@literal null}. 93 | * @param parameter 94 | * @return 95 | */ 96 | private ParameterMetadata next(Part part, Class type, Parameter parameter) { 97 | Assert.notNull(type, "Type must not be null!"); 98 | 99 | ParameterMetadata value = new ParameterMetadata(type, parameter.getName().get(), part.getType(), 100 | bindableParameterValues == null ? ParameterMetadata.PLACEHOLDER : bindableParameterValues.next()); 101 | expressions.add(value); 102 | 103 | return value; 104 | } 105 | 106 | /** 107 | * Builds a new {@link ParameterMetadata} of the given {@link Part} and type. Forwards the underlying 108 | * {@link Parameters} as well. 109 | * 110 | * @param 111 | * @param type must not be {@literal null}. 112 | * @return 113 | */ 114 | @SuppressWarnings("unchecked") 115 | public ParameterMetadata next(Part part, Class type) { 116 | Parameter parameter = parameters.next(); 117 | Class typeToUse = ClassUtils.isAssignable(type, parameter.getType()) ? parameter.getType() : type; 118 | return (ParameterMetadata) next(part, typeToUse, parameter); 119 | } 120 | 121 | /** 122 | * @param 123 | * @author Xuegui Yuan 124 | */ 125 | static class ParameterMetadata { 126 | 127 | static final Object PLACEHOLDER = new Object(); 128 | 129 | private final Type type; 130 | private final Class parameterType; 131 | private final String parameterName; 132 | private final Object parameterValue; 133 | 134 | /** 135 | * Creates a new {@link ParameterMetadata}. 136 | * 137 | * @param parameterType 138 | * @param parameterName 139 | * @param type 140 | * @param value 141 | */ 142 | public ParameterMetadata(Class parameterType, String parameterName, Type type, Object value) { 143 | this.parameterType = parameterType; 144 | this.parameterName = parameterName; 145 | this.parameterValue = value; 146 | this.type = (value == null && Type.SIMPLE_PROPERTY.equals(type) ? Type.IS_NULL : type); 147 | } 148 | 149 | /** 150 | * Returns the given argument as {@link Collection} which means it will return it as is if it's a 151 | * {@link Collections}, turn an array into an {@link ArrayList} or simply wrap any other value into a single element 152 | * {@link Collections}. 153 | * 154 | * @param value 155 | * @return 156 | */ 157 | public static Collection toCollection(Object value) { 158 | if (value == null) { 159 | return null; 160 | } 161 | 162 | if (value instanceof Collection) { 163 | return (Collection) value; 164 | } 165 | 166 | if (ObjectUtils.isArray(value)) { 167 | return Arrays.asList(ObjectUtils.toObjectArray(value)); 168 | } 169 | 170 | return Collections.singleton(value); 171 | } 172 | 173 | /** 174 | * Returns whether the parameter shall be considered an {@literal IS NULL} parameter. 175 | * 176 | * @return 177 | */ 178 | public boolean isIsNullParameter() { 179 | return Type.IS_NULL.equals(type); 180 | } 181 | 182 | public Class getParameterType() { 183 | return parameterType; 184 | } 185 | 186 | public String getParameterName() { 187 | return parameterName; 188 | } 189 | 190 | public Object getParameterValue() { 191 | return parameterValue; 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/PartTreeEbeanQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import io.ebean.EbeanServer; 20 | import io.ebean.ExpressionList; 21 | import io.ebean.Query; 22 | import org.springframework.data.domain.Sort; 23 | import org.springframework.data.repository.query.DefaultParameters; 24 | import org.springframework.data.repository.query.ParametersParameterAccessor; 25 | import org.springframework.data.repository.query.ResultProcessor; 26 | import org.springframework.data.repository.query.parser.PartTree; 27 | 28 | /** 29 | * A {@link AbstractEbeanQuery} implementation based on a {@link PartTree}. 30 | * 31 | * @author Xuegui Yuan 32 | */ 33 | public class PartTreeEbeanQuery extends AbstractEbeanQuery { 34 | 35 | private final Class domainClass; 36 | private final PartTree tree; 37 | private final DefaultParameters parameters; 38 | 39 | private final QueryPreparer queryPreparer; 40 | 41 | /** 42 | * Creates a new {@link PartTreeEbeanQuery}. 43 | * 44 | * @param method must not be {@literal null}. 45 | * @param ebeanServer must not be {@literal null}. 46 | */ 47 | public PartTreeEbeanQuery(EbeanQueryMethod method, EbeanServer ebeanServer) { 48 | super(method, ebeanServer); 49 | 50 | this.domainClass = method.getEntityInformation().getJavaType(); 51 | this.tree = new PartTree(method.getName(), domainClass); 52 | this.parameters = (DefaultParameters) method.getParameters(); 53 | this.queryPreparer = new QueryPreparer(ebeanServer); 54 | } 55 | 56 | @Override 57 | protected AbstractEbeanQueryExecution getExecution() { 58 | if (this.tree.isDelete()) { 59 | return new AbstractEbeanQueryExecution.DeleteExecution(getEbeanServer()); 60 | } else if (this.tree.isExistsProjection()) { 61 | return new AbstractEbeanQueryExecution.ExistsExecution(); 62 | } 63 | 64 | return super.getExecution(); 65 | } 66 | 67 | /* 68 | * (non-Javadoc) 69 | * @see org.springframework.data.ebean.repository.query.AbstractEbeanQuery#doCreateQuery(java.lang.Object[]) 70 | */ 71 | @Override 72 | public EbeanQueryWrapper doCreateQuery(Object[] values) { 73 | return queryPreparer.createQuery(values); 74 | } 75 | 76 | /** 77 | * EbeanQueryWrapper preparer to create {@link Query} instances and potentially cache them. 78 | * 79 | * @author Xuegui Yuan 80 | */ 81 | private class QueryPreparer { 82 | 83 | private final EbeanServer ebeanServer; 84 | 85 | public QueryPreparer(EbeanServer ebeanServer) { 86 | this.ebeanServer = ebeanServer; 87 | } 88 | 89 | /** 90 | * Creates a new {@link Query} for the given parameter values. 91 | * 92 | * @param values 93 | * @return 94 | */ 95 | public EbeanQueryWrapper createQuery(Object[] values) { 96 | ParametersParameterAccessor accessor = new ParametersParameterAccessor(parameters, values); 97 | EbeanQueryCreator ebeanQueryCreator = createCreator(accessor); 98 | return 99 | restrictMaxResultsIfNecessary( 100 | invokeBinding(getBinder(values), 101 | EbeanQueryWrapper.ofEbeanQuery(ebeanQueryCreator.createQuery()))); 102 | } 103 | 104 | protected EbeanQueryCreator createCreator(ParametersParameterAccessor accessor) { 105 | EbeanServer ebeanServer = getEbeanServer(); 106 | Query ebeanQuery = ebeanServer.createQuery(domainClass); 107 | ExpressionList expressionList = ebeanQuery.where(); 108 | 109 | ParameterMetadataProvider provider = new ParameterMetadataProvider(accessor); 110 | 111 | ResultProcessor processor = getQueryMethod().getResultProcessor(); 112 | 113 | return new EbeanQueryCreator(tree, processor.getReturnedType(), expressionList, provider); 114 | } 115 | 116 | /** 117 | * Restricts the max results of the given {@link Query} if the current {@code tree} marks this {@code query} as 118 | * limited. 119 | * 120 | * @param query 121 | * @return 122 | */ 123 | private EbeanQueryWrapper restrictMaxResultsIfNecessary(EbeanQueryWrapper query) { 124 | if (tree.isLimiting()) { 125 | 126 | if (query.getMaxRows() != Integer.MAX_VALUE) { 127 | /* 128 | * In order to return the correct results, we have to adjust the first result offset to be returned if: 129 | * - a Pageable parameter is present 130 | * - AND the requested page number > 0 131 | * - AND the requested page size was bigger than the derived result limitation via the First/Top keyword. 132 | */ 133 | if (query.getMaxRows() > tree.getMaxResults() && query.getFirstRow() > 0) { 134 | query.setFirstRow(query.getFirstRow() - (query.getMaxRows() - tree.getMaxResults())); 135 | } 136 | } 137 | 138 | query.setMaxRows(tree.getMaxResults()); 139 | } 140 | 141 | if (tree.isExistsProjection()) { 142 | query.setMaxRows(1); 143 | } 144 | 145 | return query; 146 | } 147 | 148 | /** 149 | * Invokes parameter binding on the given {@link ExpressionList}. 150 | * 151 | * @param binder 152 | * @param query 153 | * @return 154 | */ 155 | protected EbeanQueryWrapper invokeBinding(ParameterBinder binder, EbeanQueryWrapper query) { 156 | return binder.bindAndPrepare(query); 157 | } 158 | 159 | private ParameterBinder getBinder(Object[] values) { 160 | return new ParameterBinder(parameters, values); 161 | } 162 | 163 | private Sort getDynamicSort(Object[] values) { 164 | return parameters.potentiallySortsDynamically() ? new ParametersParameterAccessor(parameters, values).getSort() 165 | : null; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/SpelExpressionStringQueryParameterBinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import org.springframework.data.repository.query.DefaultParameters; 20 | import org.springframework.data.repository.query.Parameter; 21 | import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; 22 | import org.springframework.expression.EvaluationContext; 23 | import org.springframework.expression.Expression; 24 | import org.springframework.expression.spel.standard.SpelExpressionParser; 25 | import org.springframework.expression.spel.support.StandardEvaluationContext; 26 | import org.springframework.util.Assert; 27 | 28 | import java.util.List; 29 | 30 | /** 31 | * A {@link StringQueryParameterBinder} that is able to bind synthetic query parameters. 32 | * 33 | * @author Xuegui Yuan 34 | */ 35 | class SpelExpressionStringQueryParameterBinder extends StringQueryParameterBinder { 36 | 37 | private final StringQuery query; 38 | private final QueryMethodEvaluationContextProvider evaluationContextProvider; 39 | private final SpelExpressionParser parser; 40 | 41 | /** 42 | * Creates a new {@link SpelExpressionStringQueryParameterBinder}. 43 | * 44 | * @param parameters must not be {@literal null} 45 | * @param values must not be {@literal null} 46 | * @param query must not be {@literal null} 47 | * @param evaluationContextProvider must not be {@literal null} 48 | * @param parser must not be {@literal null} 49 | */ 50 | public SpelExpressionStringQueryParameterBinder(DefaultParameters parameters, Object[] values, StringQuery query, 51 | QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) { 52 | 53 | super(parameters, values, query); 54 | Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null!"); 55 | Assert.notNull(parser, "SpelExpressionParser must not be null!"); 56 | 57 | this.evaluationContextProvider = evaluationContextProvider; 58 | this.query = query; 59 | this.parser = parser; 60 | } 61 | 62 | @Override 63 | public EbeanQueryWrapper bind(EbeanQueryWrapper ebeanQuery) { 64 | return potentiallyBindExpressionParameters(super.bind(ebeanQuery)); 65 | } 66 | 67 | /** 68 | * @param ebeanQuery must not be {@literal null} 69 | * @return 70 | */ 71 | private EbeanQueryWrapper potentiallyBindExpressionParameters(EbeanQueryWrapper ebeanQuery) { 72 | for (StringQuery.ParameterBinding binding : query.getParameterBindings()) { 73 | 74 | if (binding.isExpression()) { 75 | 76 | Expression expr = parseExpressionString(binding.getExpression()); 77 | 78 | Object value = evaluateExpression(expr); 79 | 80 | try { 81 | if (binding.getName() != null) { 82 | ebeanQuery.setParameter(binding.getName(), binding.prepare(value)); 83 | } else { 84 | ebeanQuery.setParameter(binding.getPosition(), binding.prepare(value)); 85 | } 86 | } catch (IllegalArgumentException iae) { 87 | 88 | // Since Eclipse doesn't reliably report whether a query has parameters 89 | // we simply try to set the parameters and ignore possible failures. 90 | } 91 | } 92 | } 93 | 94 | return ebeanQuery; 95 | } 96 | 97 | /** 98 | * Parses the given {@code expressionString} into a SpEL {@link Expression}. 99 | * 100 | * @param expressionString 101 | * @return 102 | */ 103 | private Expression parseExpressionString(String expressionString) { 104 | return parser.parseExpression(expressionString); 105 | } 106 | 107 | /** 108 | * Evaluates the given SpEL {@link Expression}. 109 | * 110 | * @param expr 111 | * @return 112 | */ 113 | private Object evaluateExpression(Expression expr) { 114 | return expr.getValue(getEvaluationContext(), Object.class); 115 | } 116 | 117 | /** 118 | * Returns the {@link StandardEvaluationContext} to use for evaluation. 119 | * 120 | * @return 121 | */ 122 | private EvaluationContext getEvaluationContext() { 123 | return evaluationContextProvider.getEvaluationContext(getParameters(), getValues()); 124 | } 125 | 126 | @Override 127 | protected boolean canBindParameter(Parameter parameter) { 128 | 129 | List parameterBindings = query.getParameterBindings(); 130 | 131 | // if no parameter bindings are present, we simply rely on the check in super. 132 | if (parameterBindings.isEmpty()) { 133 | return super.canBindParameter(parameter); 134 | } 135 | 136 | // otherwise determine whether there are any non expression parameters left to be bound. 137 | int expressionParameterCount = 0; 138 | for (StringQuery.ParameterBinding binding : parameterBindings) { 139 | 140 | if (binding.isExpression()) { 141 | expressionParameterCount++; 142 | } 143 | } 144 | 145 | boolean allParametersAreUsedInExpressions = parameterBindings.size() - expressionParameterCount == 0; 146 | 147 | // if all parameters are used in expressions, then we can skip their bindings now, since they'll get bound later. 148 | return !allParametersAreUsedInExpressions && super.canBindParameter(parameter); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/StringQueryParameterBinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.query; 18 | 19 | import org.springframework.data.repository.query.DefaultParameters; 20 | import org.springframework.data.repository.query.Parameter; 21 | import org.springframework.data.repository.query.Parameters; 22 | import org.springframework.util.Assert; 23 | 24 | import static org.springframework.data.ebean.repository.query.StringQuery.LikeParameterBinding; 25 | import static org.springframework.data.ebean.repository.query.StringQuery.ParameterBinding; 26 | 27 | /** 28 | * {@link ParameterBinder} that takes {@link LikeParameterBinding}s encapsulated in a {@link StringQuery} into account. 29 | * 30 | * @author Xuegui Yuan 31 | */ 32 | public class StringQueryParameterBinder extends ParameterBinder { 33 | 34 | private final StringQuery query; 35 | 36 | /** 37 | * Creates a new {@link StringQueryParameterBinder} from the given {@link Parameters}, method arguments and 38 | * {@link StringQuery}. 39 | * 40 | * @param parameters must not be {@literal null}. 41 | * @param values must not be {@literal null}. 42 | * @param query must not be {@literal null}. 43 | */ 44 | public StringQueryParameterBinder(DefaultParameters parameters, Object[] values, StringQuery query) { 45 | 46 | super(parameters, values); 47 | 48 | Assert.notNull(query, "StringQuery must not be null!"); 49 | this.query = query; 50 | } 51 | 52 | @Override 53 | protected void bind(EbeanQueryWrapper ebeanQuery, Parameter methodParameter, Object value, int position) { 54 | 55 | ParameterBinding binding = getBindingFor(ebeanQuery, position, methodParameter); 56 | super.bind(ebeanQuery, methodParameter, binding.prepare(value), position); 57 | } 58 | 59 | /** 60 | * Finds the {@link LikeParameterBinding} to be applied before binding a parameter value to the query. 61 | * 62 | * @param ebeanQuery must not be {@literal null}. 63 | * @param position 64 | * @param parameter must not be {@literal null}. 65 | * @return the {@link ParameterBinding} for the given parameters or {@literal null} if none available. 66 | */ 67 | private ParameterBinding getBindingFor(Object ebeanQuery, int position, Parameter parameter) { 68 | 69 | Assert.notNull(ebeanQuery, "EbeanQueryWrapper must not be null!"); 70 | Assert.notNull(parameter, "Parameter must not be null!"); 71 | 72 | if (parameter.isNamedParameter()) { 73 | return query.getBindingFor(parameter.getName().orElseThrow(() -> new IllegalArgumentException("Parameter needs to be named!"))); 74 | } 75 | 76 | try { 77 | return query.getBindingFor(position); 78 | 79 | } catch (IllegalArgumentException ex) { 80 | 81 | // We should actually reject parameters unavailable, but as EclipseLink doesn't implement ….getParameter(int) for 82 | // native queries correctly we need to fall back to an indexed parameter 83 | // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=427892 84 | 85 | return new ParameterBinding(position); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/query/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Ebean query implementations. 3 | */ 4 | 5 | package org.springframework.data.ebean.repository.query; 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/support/EbeanEntityInformation.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.repository.support; 2 | 3 | import io.ebean.EbeanServer; 4 | import lombok.NonNull; 5 | import org.springframework.core.ResolvableType; 6 | import org.springframework.data.repository.core.EntityInformation; 7 | 8 | /** 9 | * Extension of {@link EntityInformation} to capture information about ebean entity. 10 | * @author Xuegui Yuan 11 | */ 12 | public class EbeanEntityInformation implements EntityInformation { 13 | 14 | private final EbeanServer ebeanServer; 15 | 16 | private final @NonNull 17 | Class domainClass; 18 | 19 | private Class idClass; 20 | 21 | public EbeanEntityInformation(EbeanServer ebeanServer, Class domainClass) { 22 | this.ebeanServer = ebeanServer; 23 | this.domainClass = domainClass; 24 | 25 | Class idClass = ResolvableType.forClass(domainClass).resolveGeneric(0); 26 | 27 | if (idClass == null) { 28 | throw new IllegalArgumentException(String.format("Could not resolve identifier type for %s!", domainClass)); 29 | } 30 | 31 | this.idClass = (Class) idClass; 32 | } 33 | 34 | @Override 35 | public boolean isNew(T entity) { 36 | return ebeanServer.getBeanState(entity).isNew(); 37 | } 38 | 39 | @Override 40 | public ID getId(T entity) { 41 | return (ID) ebeanServer.getBeanId(entity); 42 | } 43 | 44 | @Override 45 | public Class getIdType() { 46 | return this.idClass; 47 | } 48 | 49 | @Override 50 | public Class getJavaType() { 51 | return this.domainClass; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/support/EbeanRepositoryFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.support; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.data.domain.Persistable; 21 | import org.springframework.data.ebean.repository.EbeanRepository; 22 | import org.springframework.data.ebean.repository.query.EbeanQueryLookupStrategy; 23 | import org.springframework.data.repository.core.EntityInformation; 24 | import org.springframework.data.repository.core.RepositoryInformation; 25 | import org.springframework.data.repository.core.RepositoryMetadata; 26 | import org.springframework.data.repository.core.support.RepositoryFactorySupport; 27 | import org.springframework.data.repository.query.QueryLookupStrategy; 28 | import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; 29 | import org.springframework.util.Assert; 30 | 31 | import java.io.Serializable; 32 | import java.util.Optional; 33 | 34 | /** 35 | * Ebean specific generic repository factory. 36 | * 37 | * @author Xuegui Yuan 38 | */ 39 | public class EbeanRepositoryFactory extends RepositoryFactorySupport { 40 | 41 | private final EbeanServer ebeanServer; 42 | 43 | /** 44 | * Creates a new {@link EbeanRepositoryFactory}. 45 | * 46 | * @param ebeanServer must not be {@literal null} 47 | */ 48 | public EbeanRepositoryFactory(EbeanServer ebeanServer) { 49 | Assert.notNull(ebeanServer, "EbeanServer must not be null!"); 50 | this.ebeanServer = ebeanServer; 51 | } 52 | 53 | /* 54 | * (non-Javadoc) 55 | * @see org.springframework.data.repository.core.impl.RepositoryFactorySupport#setBeanClassLoader(java.lang.ClassLoader) 56 | */ 57 | @Override 58 | public void setBeanClassLoader(ClassLoader classLoader) { 59 | super.setBeanClassLoader(classLoader); 60 | } 61 | 62 | @SuppressWarnings("unchecked") 63 | @Override 64 | public EntityInformation getEntityInformation(Class domainClass) { 65 | return new EbeanEntityInformation(this.ebeanServer, domainClass); 66 | } 67 | 68 | /* 69 | * (non-Javadoc) 70 | * @see org.springframework.data.repository.core.impl.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata) 71 | */ 72 | @Override 73 | protected Object getTargetRepository(RepositoryInformation information) { 74 | return getTargetRepository(information, ebeanServer); 75 | } 76 | 77 | /** 78 | * Callback to create a {@link EbeanRepository} instance with the given {@link EbeanServer} 79 | * 80 | * @param 81 | * @param 82 | * @param ebeanServer 83 | * @return 84 | */ 85 | protected SimpleEbeanRepository getTargetRepository( 86 | RepositoryInformation information, EbeanServer ebeanServer) { 87 | 88 | return getTargetRepositoryViaReflection(information, information.getDomainType(), ebeanServer); 89 | } 90 | 91 | /* 92 | * (non-Javadoc) 93 | * @see org.springframework.data.repository.core.impl.RepositoryFactorySupport#getRepositoryBaseClass(org.springframework.data.repository.core.RepositoryMetadata) 94 | */ 95 | @Override 96 | protected Class getRepositoryBaseClass(RepositoryMetadata metadata) { 97 | return SimpleEbeanRepository.class; 98 | } 99 | 100 | /* 101 | * (non-Javadoc) 102 | * @see org.springframework.data.repository.core.impl.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key, org.springframework.data.repository.query.EvaluationContextProvider) 103 | */ 104 | @Override 105 | protected Optional getQueryLookupStrategy(QueryLookupStrategy.Key key, 106 | QueryMethodEvaluationContextProvider evaluationContextProvider) { 107 | return Optional.ofNullable(EbeanQueryLookupStrategy.create(ebeanServer, key, evaluationContextProvider)); 108 | } 109 | 110 | /** 111 | * Returns whether the given repository interface requires a QueryDsl specific implementation to be chosen. 112 | * 113 | * @param repositoryInterface 114 | * @return 115 | */ 116 | private boolean isQueryDslExecutor(Class repositoryInterface) { 117 | return false; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/support/EbeanRepositoryFactoryBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.repository.support; 18 | 19 | import io.ebean.EbeanServer; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.data.mapping.context.MappingContext; 22 | import org.springframework.data.repository.Repository; 23 | import org.springframework.data.repository.core.support.RepositoryFactorySupport; 24 | import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport; 25 | import org.springframework.util.Assert; 26 | 27 | 28 | /** 29 | * Special adapter for Springs {@link org.springframework.beans.factory.FactoryBean} interface to allow easy setup of 30 | * repository factories via Spring configuration. 31 | * 32 | * @param the type of the repository 33 | * @author Xuegui Yuan 34 | */ 35 | public class EbeanRepositoryFactoryBean, S, ID> 36 | extends TransactionalRepositoryFactoryBeanSupport { 37 | 38 | @Autowired 39 | private EbeanServer ebeanServer; 40 | 41 | /** 42 | * Creates a new {@link EbeanRepositoryFactoryBean} for the given repository interface. 43 | * 44 | * @param repositoryInterface must not be {@literal null}. 45 | */ 46 | public EbeanRepositoryFactoryBean(Class repositoryInterface) { 47 | super(repositoryInterface); 48 | } 49 | 50 | /* 51 | * (non-Javadoc) 52 | * @see org.springframework.data.repository.core.impl.RepositoryFactoryBeanSupport#setMappingContext(org.springframework.data.mapping.context.MappingContext) 53 | */ 54 | @Override 55 | public void setMappingContext(MappingContext mappingContext) { 56 | super.setMappingContext(mappingContext); 57 | } 58 | 59 | /* 60 | * (non-Javadoc) 61 | * 62 | * @see 63 | * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() 64 | */ 65 | @Override 66 | public void afterPropertiesSet() { 67 | Assert.notNull(ebeanServer, "EbeanServer must not be null!"); 68 | super.afterPropertiesSet(); 69 | } 70 | 71 | /* 72 | * (non-Javadoc) 73 | * 74 | * @see org.springframework.data.repository.impl. 75 | * TransactionalRepositoryFactoryBeanSupport#doCreateRepositoryFactory() 76 | */ 77 | @Override 78 | protected RepositoryFactorySupport doCreateRepositoryFactory() { 79 | return createRepositoryFactory(ebeanServer); 80 | } 81 | 82 | /** 83 | * Returns a {@link RepositoryFactorySupport}. 84 | * 85 | * @param ebeanServer 86 | * @return 87 | */ 88 | protected RepositoryFactorySupport createRepositoryFactory(EbeanServer ebeanServer) { 89 | return new EbeanRepositoryFactory(ebeanServer); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/repository/support/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Ebean repository implementations. 3 | */ 4 | 5 | package org.springframework.data.ebean.repository.support; 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/util/Converters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.util; 18 | 19 | import io.ebean.OrderBy; 20 | import io.ebean.PagedList; 21 | import org.springframework.data.domain.Page; 22 | import org.springframework.data.domain.PageImpl; 23 | import org.springframework.data.domain.PageRequest; 24 | import org.springframework.data.domain.Sort; 25 | import org.springframework.util.StringUtils; 26 | 27 | import java.util.ArrayList; 28 | import java.util.Iterator; 29 | import java.util.List; 30 | 31 | /** 32 | * Ebean PageList and Order util to or from Spring data Page or Sort. 33 | * 34 | * @author Xuegui Yuan 35 | */ 36 | public class Converters { 37 | 38 | /** 39 | * Convert spring data Sort to Ebean OrderBy. 40 | * 41 | * @param sort 42 | * @param 43 | * @return 44 | */ 45 | public static OrderBy convertToEbeanOrderBy(Sort sort) { 46 | if (sort == null) { 47 | return null; 48 | } 49 | List list = new ArrayList<>(); 50 | 51 | Iterator orderIterator = sort.iterator(); 52 | while (orderIterator.hasNext()) { 53 | Sort.Order so = orderIterator.next(); 54 | list.add(so.getProperty() + " " + so.getDirection()); 55 | } 56 | return new OrderBy(StringUtils.collectionToCommaDelimitedString(list)); 57 | } 58 | 59 | /** 60 | * Convert Ebean PagedList with Sort to Spring data Page. 61 | * 62 | * @param pagedList 63 | * @param sort 64 | * @param 65 | * @return 66 | */ 67 | public static Page convertToSpringDataPage(PagedList pagedList, Sort sort) { 68 | return new PageImpl(pagedList.getList(), 69 | PageRequest.of(pagedList.getPageIndex(), pagedList.getPageSize(), sort), 70 | pagedList.getTotalCount()); 71 | } 72 | 73 | /** 74 | * Convert Ebean PagedList to Spring data Page. 75 | * 76 | * @param pagedList 77 | * @param 78 | * @return 79 | */ 80 | public static Page convertToSpringDataPage(PagedList pagedList) { 81 | return new PageImpl(pagedList.getList(), 82 | PageRequest.of(pagedList.getPageIndex(), pagedList.getPageSize()), 83 | pagedList.getTotalCount()); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/util/ExampleExpressionBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.util; 18 | 19 | import io.ebean.EbeanServer; 20 | import io.ebean.ExampleExpression; 21 | import io.ebean.LikeType; 22 | import org.springframework.data.domain.Example; 23 | 24 | /** 25 | * Build {@link io.ebean.ExampleExpression} from {@link org.springframework.data.domain.Example} 26 | * 27 | * @author Xuegui Yuan 28 | */ 29 | public class ExampleExpressionBuilder { 30 | 31 | /** 32 | * Return a ExampleExpression from Spring data Example 33 | * 34 | * @param ebeanServer 35 | * @param example 36 | * @param 37 | * @return 38 | */ 39 | public static ExampleExpression exampleExpression(EbeanServer ebeanServer, Example example) { 40 | LikeType likeType; 41 | switch (example.getMatcher().getDefaultStringMatcher()) { 42 | case EXACT: 43 | likeType = LikeType.EQUAL_TO; 44 | break; 45 | case CONTAINING: 46 | likeType = LikeType.CONTAINS; 47 | break; 48 | case STARTING: 49 | likeType = LikeType.STARTS_WITH; 50 | break; 51 | case ENDING: 52 | likeType = LikeType.ENDS_WITH; 53 | break; 54 | default: 55 | likeType = LikeType.RAW; 56 | break; 57 | } 58 | return ebeanServer.getExpressionFactory().exampleLike(example.getProbe(), 59 | example.getMatcher().isIgnoreCaseEnabled(), 60 | likeType); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/data/ebean/util/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Converter to util Ebean classes to spring data classes. 3 | */ 4 | 5 | package org.springframework.data.ebean.util; 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.data.repository.core.support.RepositoryFactorySupport=org.springframework.data.ebean.repository.support.EbeanRepositoryFactory 2 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.handlers: -------------------------------------------------------------------------------- 1 | http\://www.springframework.org/schema/data/ebean=org.springframework.data.ebean.repository.config.EbeanRepositoryNameSpaceHandler 2 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/querychannel/EbeanQueryChannelServiceIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.querychannel; 2 | 3 | import io.ebean.Query; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.data.ebean.sample.config.SampleConfig; 9 | import org.springframework.data.ebean.sample.domain.User; 10 | import org.springframework.data.ebean.sample.domain.UserInfo; 11 | import org.springframework.data.ebean.sample.domain.UserRepository; 12 | import org.springframework.test.context.ContextConfiguration; 13 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | 20 | /** 21 | * @author Xuegui Yuan 22 | */ 23 | @RunWith(SpringJUnit4ClassRunner.class) 24 | @ContextConfiguration(classes = SampleConfig.class) 25 | public class EbeanQueryChannelServiceIntegrationTest { 26 | // Test fixture 27 | User user; 28 | @Autowired 29 | private QueryChannelService queryChannel; 30 | @Autowired 31 | private UserRepository repository; 32 | 33 | @Before 34 | public void initUser() { 35 | repository.deleteAll(); 36 | user = new User("QueryChannel", "Test", "testquerychannel@163.com"); 37 | user.setAge(29); 38 | user = repository.save(user); 39 | } 40 | 41 | 42 | @Test 43 | public void createSqlQueryMappingColumns() { 44 | String sql1 = "select first_name, last_name, email_address from user where last_name= :lastName"; 45 | String sql2 = "select first_name as firstName, last_name as lastName, email_address as emailAddress from user where last_name= :lastName"; 46 | Map columnsMapping = new HashMap<>(); 47 | columnsMapping.put("first_name", "firstName"); 48 | columnsMapping.put("last_name", "lastName"); 49 | 50 | Query query1 = queryChannel.createSqlQuery(UserInfo.class, 51 | sql1); 52 | Query query2 = queryChannel.createSqlQuery(UserInfo.class, 53 | sql2); 54 | Query query3 = queryChannel.createSqlQueryMappingColumns(UserInfo.class, 55 | sql1, columnsMapping); 56 | 57 | query1.setParameter("lastName", "Test"); 58 | query2.setParameter("lastName", "Test"); 59 | query3.setParameter("lastName", "Test"); 60 | UserInfo userInfo1 = query1.findOne(); 61 | UserInfo userInfo2 = query2.findOne(); 62 | UserInfo userInfo3 = query3.findOne(); 63 | assertEquals("QueryChannel", userInfo1.getFirstName()); 64 | assertEquals("testquerychannel@163.com", userInfo1.getEmailAddress()); 65 | assertEquals("QueryChannel", userInfo2.getFirstName()); 66 | assertEquals("testquerychannel@163.com", userInfo2.getEmailAddress()); 67 | assertEquals("QueryChannel", userInfo3.getFirstName()); 68 | assertEquals("testquerychannel@163.com", userInfo3.getEmailAddress()); 69 | } 70 | 71 | @Test 72 | public void createNamedQuery() { 73 | UserInfo userInfo = queryChannel.createNamedQuery(UserInfo.class, 74 | "userInfoByEmail").setParameter("emailAddress", 75 | "testquerychannel@163.com").findOne(); 76 | assertEquals("QueryChannel", userInfo.getFirstName()); 77 | assertEquals("testquerychannel@163.com", userInfo.getEmailAddress()); 78 | } 79 | 80 | @Test 81 | public void createNamedQueryWhere() { 82 | UserInfo userInfo = queryChannel.createNamedQuery(UserInfo.class, 83 | "userInfo").where() 84 | .eq("emailAddress", "testquerychannel@163.com").findOne(); 85 | assertEquals("QueryChannel", userInfo.getFirstName()); 86 | assertEquals("testquerychannel@163.com", userInfo.getEmailAddress()); 87 | } 88 | 89 | @Test 90 | public void createDtoQuery() { 91 | String sql = "select first_name, last_name, email_address from user where email_address = :emailAddress"; 92 | UserDTO userDTO = queryChannel.createDtoQuery(UserDTO.class, sql) 93 | .setParameter("emailAddress", "testquerychannel@163.com") 94 | .findOne(); 95 | assertEquals("QueryChannel", userDTO.getFirstName()); 96 | assertEquals("testquerychannel@163.com", userDTO.getEmailAddress()); 97 | } 98 | 99 | @Test 100 | public void createNamedDtoQuery() { 101 | UserDTO userDTO = queryChannel.createNamedDtoQuery(UserDTO.class, "byEmail") 102 | .setParameter("emailAddress", "testquerychannel@163.com") 103 | .findOne(); 104 | assertEquals("QueryChannel", userDTO.getFirstName()); 105 | assertEquals("testquerychannel@163.com", userDTO.getEmailAddress()); 106 | } 107 | 108 | @Test 109 | public void query_queryObject() { 110 | UserQuery userQuery = new UserQuery(); 111 | userQuery.setEmailAddress("testquerychannel@163.com"); 112 | userQuery.setAgeStart(1); 113 | userQuery.setAgeEnd(30); 114 | 115 | User user = queryChannel.createQuery(User.class, userQuery) 116 | .findOne(); 117 | assertEquals("testquerychannel@163.com", user.getEmailAddress()); 118 | 119 | UserDTO userDTO = queryChannel.createQuery(User.class, userQuery) 120 | .asDto(UserDTO.class) 121 | .setRelaxedMode() 122 | .findOne(); 123 | assertEquals("testquerychannel@163.com", userDTO.getEmailAddress()); 124 | } 125 | 126 | @Test 127 | public void applyQueryObject() { 128 | UserQuery userQuery = new UserQuery(); 129 | userQuery.setEmailAddress("testquerychannel@163.com"); 130 | userQuery.setAgeStart(1); 131 | userQuery.setAgeEnd(30); 132 | UserInfo userInfo = EbeanQueryChannelService.applyWhere(queryChannel.createNamedQuery(UserInfo.class, 133 | "userInfo").where(), userQuery).findOne(); 134 | assertEquals("QueryChannel", userInfo.getFirstName()); 135 | assertEquals("testquerychannel@163.com", userInfo.getEmailAddress()); 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/querychannel/UserDTO.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.querychannel; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * @author XueguiYuan 8 | * @version 1.0 (created time: 2018/3/3). 9 | */ 10 | @Getter 11 | @Setter 12 | public class UserDTO { 13 | private String lastName; 14 | private String firstName; 15 | private String emailAddress; 16 | private int age; 17 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/querychannel/UserQuery.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.querychannel; 2 | 3 | import lombok.Data; 4 | import org.springframework.data.ebean.annotation.ExprParam; 5 | import org.springframework.data.ebean.annotation.IncludeFields; 6 | 7 | /** 8 | * @author XueguiYuan 9 | * @version 1.0 (created time: 2018/4/29). 10 | */ 11 | @Data 12 | @IncludeFields("emailAddress,fullName(lastName,firstName),age") 13 | public class UserQuery { 14 | @ExprParam(expr = ExprType.CONTAINS) 15 | private String emailAddress; 16 | 17 | @ExprParam(name = "age", expr = ExprType.GE) 18 | private int ageStart; 19 | 20 | @ExprParam(name = "age", expr = ExprType.LE) 21 | private int ageEnd; 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/sample/config/SampleConfig.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.sample.config; 2 | 3 | import io.ebean.EbeanServer; 4 | import io.ebean.EbeanServerFactory; 5 | import io.ebean.config.CurrentUserProvider; 6 | import io.ebean.config.ServerConfig; 7 | import io.ebean.spring.txn.SpringJdbcTransactionManager; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.Primary; 11 | import org.springframework.data.ebean.querychannel.EbeanQueryChannelService; 12 | import org.springframework.data.ebean.querychannel.QueryChannelService; 13 | import org.springframework.data.ebean.repository.config.EnableEbeanRepositories; 14 | import org.springframework.data.ebean.sample.domain.UserDomainService; 15 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 16 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 17 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 18 | import org.springframework.transaction.PlatformTransactionManager; 19 | import org.springframework.transaction.annotation.EnableTransactionManagement; 20 | 21 | import javax.sql.DataSource; 22 | 23 | /** 24 | * @author Xuegui Yuan 25 | */ 26 | @Configuration 27 | @EnableEbeanRepositories(value = "org.springframework.data.ebean.sample") 28 | @EnableTransactionManagement 29 | public class SampleConfig { 30 | @Bean 31 | public PlatformTransactionManager transactionManager(DataSource dataSource) { 32 | return new DataSourceTransactionManager(dataSource); 33 | } 34 | 35 | @Bean 36 | public QueryChannelService ebeanQueryChannelService(EbeanServer ebeanServer) { 37 | return new EbeanQueryChannelService(ebeanServer); 38 | } 39 | 40 | @SuppressWarnings("SpringJavaAutowiringInspection") 41 | @Bean 42 | @Primary 43 | public ServerConfig defaultEbeanServerConfig() { 44 | ServerConfig config = new ServerConfig(); 45 | 46 | config.setDataSource(dataSource()); 47 | config.setExternalTransactionManager(new SpringJdbcTransactionManager()); 48 | 49 | config.loadFromProperties(); 50 | config.setDefaultServer(true); 51 | config.setRegister(true); 52 | config.setAutoCommitMode(false); 53 | config.setExpressionNativeIlike(true); 54 | 55 | config.setCurrentUserProvider(new CurrentUserProvider() { 56 | @Override 57 | public Object currentUser() { 58 | return "test"; // just for test, can rewrite to get the currentUser from threadLocal 59 | } 60 | }); 61 | 62 | return config; 63 | } 64 | 65 | @Bean 66 | public DataSource dataSource() { 67 | return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build(); 68 | } 69 | 70 | @Bean 71 | @Primary 72 | public EbeanServer defaultEbeanServer(ServerConfig defaultEbeanServerConfig) { 73 | return EbeanServerFactory.create(defaultEbeanServerConfig); 74 | } 75 | 76 | @Bean 77 | public UserDomainService userDomainService() { 78 | return new UserDomainService(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/sample/domain/Address.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.sample.domain; 18 | 19 | import javax.persistence.Embeddable; 20 | import lombok.AllArgsConstructor; 21 | import lombok.Data; 22 | import lombok.NoArgsConstructor; 23 | 24 | /** 25 | * @author Thomas Darimont 26 | */ 27 | @Embeddable 28 | @Data 29 | @NoArgsConstructor 30 | @AllArgsConstructor 31 | public class Address { 32 | private String country; 33 | private String city; 34 | private String streetName; 35 | private String streetNo; 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/sample/domain/FullName.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.sample.domain; 2 | 3 | import java.io.Serializable; 4 | import javax.persistence.Embeddable; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * @author Xuegui Yuan 11 | */ 12 | @Embeddable 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public final class FullName implements Serializable { 17 | private String firstName; 18 | private String lastName; 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/sample/domain/Role.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.sample.domain; 18 | 19 | import javax.persistence.Entity; 20 | import javax.persistence.GeneratedValue; 21 | import javax.persistence.Id; 22 | 23 | /** 24 | * Sample domain class representing roles. Mapped with XML. 25 | * 26 | * @author Oliver Gierke 27 | * @author Thomas Darimont 28 | */ 29 | @Entity 30 | public class Role { 31 | 32 | private static final String PREFIX = "ROLE_"; 33 | 34 | @Id 35 | @GeneratedValue 36 | private Integer id; 37 | private String name; 38 | 39 | /** 40 | * Creates a new instance of {@code Role}. 41 | */ 42 | public Role() { 43 | } 44 | 45 | /** 46 | * Creates a new preconfigured {@code Role}. 47 | * 48 | * @param name 49 | */ 50 | public Role(final String name) { 51 | this.name = name; 52 | } 53 | 54 | /** 55 | * Returns the id. 56 | * 57 | * @return 58 | */ 59 | public Integer getId() { 60 | 61 | return id; 62 | } 63 | 64 | /** 65 | * @return the name 66 | */ 67 | public String getName() { 68 | return name; 69 | } 70 | 71 | /* 72 | * (non-Javadoc) 73 | * 74 | * @see java.lang.Object#toString() 75 | */ 76 | @Override 77 | public String toString() { 78 | 79 | return PREFIX + name; 80 | } 81 | 82 | /** 83 | * Returns whether the role is to be considered new. 84 | * 85 | * @return 86 | */ 87 | public boolean isNew() { 88 | 89 | return id == null; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/sample/domain/User.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.data.ebean.sample.domain; 18 | 19 | import lombok.Getter; 20 | import lombok.Setter; 21 | import org.springframework.data.ebean.domain.AbstractAggregateRoot; 22 | 23 | import javax.persistence.*; 24 | import java.util.Arrays; 25 | import java.util.Date; 26 | import java.util.HashSet; 27 | import java.util.Set; 28 | 29 | /** 30 | * Domain class representing a person emphasizing the use of {@code AbstractEntity}. No declaration of an id is 31 | * required. The id is typed by the parameterizable superclass. 32 | * 33 | * @author Xuegui Yuan 34 | */ 35 | @Entity 36 | @Table(name = "user") 37 | @Getter 38 | @Setter 39 | public class User extends AbstractAggregateRoot { 40 | 41 | @Embedded 42 | private FullName fullName; 43 | private int age; 44 | private boolean active; 45 | 46 | @Column(nullable = false, unique = true) 47 | private String emailAddress; 48 | 49 | @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) 50 | private Set colleagues; 51 | 52 | @ManyToMany 53 | private Set roles; 54 | 55 | @ManyToOne 56 | private User manager; 57 | 58 | @Embedded 59 | private Address address; 60 | 61 | @Lob 62 | private byte[] binaryData; 63 | 64 | @Temporal(TemporalType.DATE) 65 | private Date dateOfBirth; 66 | 67 | /** 68 | * Creates a new empty instance of {@code User}. 69 | */ 70 | public User() { 71 | } 72 | 73 | /** 74 | * Creates a new instance of {@code User} with preinitialized values for firstName, lastName, email address and roles. 75 | * 76 | * @param firstName 77 | * @param lastName 78 | * @param emailAddress 79 | * @param roles 80 | */ 81 | public User(String firstName, String lastName, String emailAddress, Role... roles) { 82 | this.fullName = new FullName(firstName, lastName); 83 | this.emailAddress = emailAddress; 84 | this.active = true; 85 | this.roles = new HashSet(Arrays.asList(roles)); 86 | this.colleagues = new HashSet(); 87 | } 88 | 89 | public void changeEmail(String emailAddress) { 90 | this.emailAddress = emailAddress; 91 | UserEmailChangedEvent emailChangedEvent = new UserEmailChangedEvent(this); 92 | this.registerEvent(emailChangedEvent); 93 | } 94 | 95 | /** 96 | * Adds a new colleague to the user. Adding the user himself as colleague is a no-op. 97 | * 98 | * @param collegue 99 | */ 100 | public void addColleague(User collegue) { 101 | 102 | // Prevent from adding the user himself as colleague. 103 | if (this.equals(collegue)) { 104 | return; 105 | } 106 | 107 | colleagues.add(collegue); 108 | collegue.getColleagues().add(this); 109 | } 110 | 111 | /** 112 | * Removes a colleague from the list of colleagues. 113 | * 114 | * @param colleague 115 | */ 116 | public void removeColleague(User colleague) { 117 | colleagues.remove(colleague); 118 | colleague.getColleagues().remove(this); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/sample/domain/UserDomainService.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.sample.domain; 2 | 3 | import org.springframework.data.ebean.domain.DomainService; 4 | import org.springframework.scheduling.annotation.Async; 5 | import org.springframework.transaction.event.TransactionalEventListener; 6 | 7 | /** 8 | * @author Xuegui Yuan 9 | */ 10 | @DomainService 11 | public class UserDomainService { 12 | 13 | @Async 14 | @TransactionalEventListener 15 | public UserEmailChangedEvent handleUserEmailChanged(UserEmailChangedEvent emailChangedEvent) { 16 | System.out.println("UserEmailChangedEvent:" + emailChangedEvent.getSource()); 17 | return null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/sample/domain/UserEmailChangedEvent.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.sample.domain; 2 | 3 | import org.springframework.data.ebean.domain.DomainEvent; 4 | 5 | /** 6 | * @author Xuegui Yuan 7 | */ 8 | public class UserEmailChangedEvent extends DomainEvent { 9 | public UserEmailChangedEvent(Object source) { 10 | super(source); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/sample/domain/UserInfo.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.sample.domain; 2 | 3 | import io.ebean.annotation.Sql; 4 | import javax.persistence.Entity; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | /** 9 | * @author Xuegui Yuan 10 | */ 11 | @Entity 12 | @Sql 13 | @Getter 14 | @Setter 15 | public class UserInfo { 16 | private String firstName; 17 | private String lastName; 18 | private String emailAddress; 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/data/ebean/sample/domain/UserRepository.java: -------------------------------------------------------------------------------- 1 | package org.springframework.data.ebean.sample.domain; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.data.ebean.annotation.Modifying; 8 | import org.springframework.data.ebean.annotation.Query; 9 | import org.springframework.data.ebean.repository.EbeanRepository; 10 | import org.springframework.data.repository.query.Param; 11 | import org.springframework.stereotype.Repository; 12 | 13 | /** 14 | * @author Xuegui Yuan 15 | */ 16 | @Repository 17 | public interface UserRepository extends EbeanRepository { 18 | @Query("where emailAddress = :emailAddress order by id desc") 19 | User findUserByEmailAddressEqualsOql(@Param("emailAddress") String emailAddress); 20 | 21 | @Query("select (fullName,address) fetch manager (fullName) where fullName.lastName = :lastName order by id desc") 22 | List findByLastnameOql(@Param("lastName") String lastName); 23 | 24 | @Query(nativeQuery = true, value = "select * from user where email_address = :emailAddress order by id desc") 25 | User findUserByEmailAddressEquals(@Param("emailAddress") String emailAddress); 26 | 27 | @Query(nativeQuery = true, value = "select * from user where last_name = :lastName order by id desc") 28 | List findUsersByLastNameEquals(@Param("lastName") String lastName); 29 | 30 | @Query(nativeQuery = true, value = "update user set email_address = :newEmail where email_address = :oldEmail") 31 | @Modifying 32 | int changeUserEmailAddress(@Param("oldEmail") String oldEmail, @Param("newEmail") String newEmail); 33 | 34 | @Query("delete from user where emailAddress = :emailAddress") 35 | @Modifying 36 | int deleteUserByEmailAddressOql(@Param("emailAddress") String emailAddress); 37 | 38 | @Query(nativeQuery = true, value = "delete from user where email_address = :emailAddress") 39 | @Modifying 40 | int deleteUserByEmailAddress(@Param("emailAddress") String emailAddress); 41 | 42 | @Query(name = "withManagerById") 43 | List findByLastNameNamedOql(@Param("lastName") String lastName); 44 | 45 | List findAllByEmailAddressAndFullNameLastName(@Param("emailAddress") String emailAddress, @Param("lastName") String lastName); 46 | 47 | @Query( value = "where emailAddress = :emailAddress") 48 | Page findUserByEmailAddressEqualsOql(@Param("emailAddress") String lastName, Pageable page); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------- 2 | # Load (Dev/Test/Prod) properties external to your war/jar 3 | # ------------------------------------------------------------- 4 | # You can use load.properties to load the properties from a 5 | # file external to your war/jar. 6 | #load.properties.override=${admin.home}/config/my-application.properties 7 | # ------------------------------------------------------------- 8 | # CORE 9 | # ------------------------------------------------------------- 10 | ebean.packages=org.springframework.data.ebean.sample.domain 11 | ebean.mappingLocations=classpath:/ebean-xml-mappings 12 | # ------------------------------------------------------------- 13 | # Generate DDL CREATE ALL & DROP ALL 14 | # ------------------------------------------------------------- 15 | ebean.ddl.generate=true 16 | ebean.ddl.run=true 17 | # ------------------------------------------------------------- 18 | # DB Migration 19 | # ------------------------------------------------------------- 20 | #ebean.migration.applyPrefix=V 21 | ebean.migration.run=false 22 | # ------------------------------------------------------------- 23 | # Logging 24 | # ------------------------------------------------------------- 25 | ebean.debug.sql=true 26 | ebean.debug.lazyload=false 27 | # Use java util logging to log transaction details 28 | #ebean.loggingToJavaLogger=true 29 | # General logging level: (none, explicit, all) 30 | ebean.logging=all 31 | # Sharing log files: (none, explicit, all) 32 | ebean.logging.logfilesharing=all 33 | # location of transaction logs 34 | ebean.logging.directory=logs 35 | #ebean.logging.directory=${catalina.base}/logs/trans 36 | # Specific Log levels (none, summary, binding, sql) 37 | ebean.logging.iud=sql 38 | ebean.logging.query=sql 39 | ebean.logging.sqlquery=sql 40 | ebean.logging.txnCommit=none -------------------------------------------------------------------------------- /src/test/resources/ebean-xml-mappings/UserDTOMapping.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | select first_name, 7 | last_name, 8 | email_address 9 | from user 10 | where email_address = :emailAddress 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/resources/ebean-xml-mappings/UserInfoMapping.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | select first_name, last_name, email_address from user 7 | 8 | 9 | 10 | 11 | select first_name, last_name, email_address from user 12 | where email_address = :emailAddress 13 | order by id desc 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/ebean-xml-mappings/UserMapping.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | select (fullName,address) 7 | fetch manager (lastName) 8 | where fullName.lastName = :lastName order by id desc 9 | 10 | 11 | 12 | 13 | select * from user 14 | where email_address = :emailAddress 15 | order by id desc 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/test/resources/ebean.mf: -------------------------------------------------------------------------------- 1 | entity-packages: org.springframework.data.ebean.sample.domain -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TRACE 5 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 12 | log/application.log 13 | 14 | TRACE 15 | 16 | 17 | log/application.log.%d{yyyy-MM-dd} 18 | 90 19 | 20 | 21 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 22 | 23 | 24 | 25 | 26 | log/readAuditQuery.log 27 | 28 | log/readAuditQuery.log.%d{yyyy-MM-dd} 29 | 90 30 | 31 | 32 | %d{HH:mm:ss.SSS} %msg%n 33 | 34 | 35 | 36 | 37 | log/readAudit.log 38 | 39 | log/readAudit.log.%d{yyyy-MM-dd} 40 | 90 41 | 42 | 43 | %d{HH:mm:ss.SSS} %msg%n 44 | 45 | 46 | 47 | 48 | log/change-log.log 49 | 50 | log/changeLog.log.%d{yyyy-MM-dd} 51 | 90 52 | 53 | 54 | %d{HH:mm:ss.SSS} %msg%n 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | --------------------------------------------------------------------------------