├── .github └── workflows │ ├── deploy.yaml │ └── tag.yaml ├── .gitignore ├── .mise.toml ├── LICENSE ├── README.adoc ├── setup.sh ├── slides ├── 01-openrewrite.adoc ├── 02-running-recipes.adoc ├── 03-declarative-recipes.adoc ├── 04-catalogue.adoc ├── 05-coding-recipes.adoc ├── css │ └── meetup.css ├── dev.sh ├── favicon.svg ├── images │ ├── anatomy.png │ ├── avatar.png │ ├── catalog.avif │ ├── catalog.jpg │ ├── chercher_remplacer.png │ ├── click_droit.png │ ├── concepts.jpg │ ├── conclusion.jpg │ ├── declarative.jpg │ ├── feedback.png │ ├── github.png │ ├── jta.png │ ├── jta_1.png │ ├── llm.png │ ├── logo_event.png │ ├── logo_onepoint.jpeg │ ├── openrewrite.svg │ ├── permis_de_refactoring.png │ ├── qrcode_github.png │ ├── regexp.png │ ├── reusinage_de_code.png │ ├── running.avif │ ├── sound │ │ └── punition.mp3 │ ├── title.png │ ├── under_logo.svg │ └── upside_down.png ├── index-docinfo-footer.html ├── index.adoc ├── intro.adoc └── outro.adoc ├── toxic-library-remover ├── licenseHeader.txt ├── pom.xml ├── rewrite.yml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── jtama │ │ │ └── openrewrite │ │ │ ├── RemoveFooBarUtilsIsEmpty.java │ │ │ ├── RemoveFooBarUtilsStringFormatted.java │ │ │ ├── RemoveLogStartInvocations.java │ │ │ └── UseObjectsCompare.java │ └── resources │ │ ├── META-INF │ │ └── rewrite │ │ │ └── rewrite.yml │ │ └── logback.xml │ └── test │ └── java │ ├── .editorconfig │ └── com │ └── github │ └── jtama │ └── openrewrite │ ├── RemoveFooBarCompareTest.java │ ├── RemoveFooBarIsEmptyTest.java │ ├── RemoveFooBarUtilsStringFormattedTest.java │ └── RemoveLogStartInvocationTest.java ├── toxic-library-user ├── README.adoc ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── github │ └── jtama │ └── app │ ├── exception │ ├── DuplicateEntityException.java │ ├── InvalidBookingException.java │ ├── InvalidNameException.java │ ├── OnerentExceptionHandler.java │ ├── UnavailableException.java │ └── UnknownEntityException.java │ ├── hostels │ ├── Hostel.java │ ├── HostelController.java │ └── HostelReservationService.java │ ├── reservation │ └── Reservation.java │ ├── rocket │ ├── Rocket.java │ ├── RocketController.java │ ├── RocketReservationService.java │ └── RocketType.java │ ├── security │ ├── HeaderAuthenticationRequest.java │ ├── NaiveAuth.java │ └── NaiveSecurityProvider.java │ └── util │ └── MonthValidator.java └── toxic-library ├── pom.xml └── src └── main └── java └── com └── github └── jtama └── toxic ├── BigDecimalUtils.java └── FooBarUtils.java /.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Build and deploy latest version 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | 8 | permissions: 9 | contents: write 10 | 11 | concurrency: 12 | group: ci-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | build-and-deploy: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 🛎️ 20 | uses: actions/checkout@v4 21 | 22 | - name: Install required dependencies 23 | run: ./setup.sh 24 | 25 | - name: Install and Build 🔧 26 | uses: addnab/docker-run-action@v3 27 | with: 28 | image: asciidoctor/docker-asciidoctor:1.80.0 29 | options: -v ${{ github.workspace }}/slides:/documents 30 | run: asciidoctor-revealjs -r asciidoctor-diagram /documents/index.adoc 31 | 32 | - name: Copy build to folder 📦 33 | run: | 34 | cd slides && \ 35 | mkdir -p build/${{ github.ref_name }}/reveal.js/dist && \ 36 | cp -r favicon.svg *.html images css highlight.js build/${{ github.ref_name }}/ && \ 37 | cp -r reveal.js/dist/* build/${{ github.ref_name }}/reveal.js/dist/ && \ 38 | cp -r reveal.js/plugin build/${{ github.ref_name }}/reveal.js/ 39 | 40 | - name: Deploy 🚀 41 | uses: JamesIves/github-pages-deploy-action@v4.5.0 42 | with: 43 | folder: slides/build 44 | branch: gh-pages 45 | clean: false -------------------------------------------------------------------------------- /.github/workflows/tag.yaml: -------------------------------------------------------------------------------- 1 | name: Build and deploy tag release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | permissions: 9 | contents: write 10 | 11 | concurrency: 12 | group: ci-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | build-and-deploy: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 🛎️ 20 | uses: actions/checkout@v4 21 | 22 | - name: Install required dependencies 23 | run: ./setup.sh 24 | 25 | - name: Install and Build 🔧 26 | uses: addnab/docker-run-action@v3 27 | with: 28 | image: asciidoctor/docker-asciidoctor:1.80.0 29 | options: -v ${{ github.workspace }}/slides:/documents 30 | run: asciidoctor-revealjs -r asciidoctor-diagram /documents/index.adoc 31 | 32 | - name: Copy build to folder 📦 33 | run: | 34 | cd slides && \ 35 | mkdir -p build/${{ github.ref_name }}/reveal.js/dist && \ 36 | cp -r favicon.svg *.html images css highlight.js build/${{ github.ref_name }} && \ 37 | cp -r reveal.js/dist/* build/${{ github.ref_name }}/reveal.js/dist/ && \ 38 | cp -r reveal.js/plugin build/${{ github.ref_name }}/reveal.js/ 39 | 40 | - name: Deploy 🚀 41 | uses: JamesIves/github-pages-deploy-action@v4.5.0 42 | with: 43 | folder: slides/build 44 | branch: gh-pages 45 | clean: false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | target 4 | .DS_Store 5 | slides/reveal.js 6 | slides/highlight.js 7 | *.html 8 | .asciidoctor 9 | !index-docinfo-footer.html 10 | openrewrite-sample-recipes/target/ 11 | toxic-library/target/ 12 | /slides/reveal.js/ 13 | -------------------------------------------------------------------------------- /.mise.toml: -------------------------------------------------------------------------------- 1 | [tools] 2 | java = "temurin-21.0.4+7.0.LTS" 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial-ShareAlike 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International 58 | Public License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-NonCommercial-ShareAlike 4.0 International Public License 63 | ("Public License"). To the extent this Public License may be 64 | interpreted as a contract, You are granted the Licensed Rights in 65 | consideration of Your acceptance of these terms and conditions, and the 66 | Licensor grants You such rights in consideration of benefits the 67 | Licensor receives from making the Licensed Material available under 68 | these terms and conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Adapter's License means the license You apply to Your Copyright 84 | and Similar Rights in Your contributions to Adapted Material in 85 | accordance with the terms and conditions of this Public License. 86 | 87 | c. BY-NC-SA Compatible License means a license listed at 88 | creativecommons.org/compatiblelicenses, approved by Creative 89 | Commons as essentially the equivalent of this Public License. 90 | 91 | d. Copyright and Similar Rights means copyright and/or similar rights 92 | closely related to copyright including, without limitation, 93 | performance, broadcast, sound recording, and Sui Generis Database 94 | Rights, without regard to how the rights are labeled or 95 | categorized. For purposes of this Public License, the rights 96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 97 | Rights. 98 | 99 | e. Effective Technological Measures means those measures that, in the 100 | absence of proper authority, may not be circumvented under laws 101 | fulfilling obligations under Article 11 of the WIPO Copyright 102 | Treaty adopted on December 20, 1996, and/or similar international 103 | agreements. 104 | 105 | f. Exceptions and Limitations means fair use, fair dealing, and/or 106 | any other exception or limitation to Copyright and Similar Rights 107 | that applies to Your use of the Licensed Material. 108 | 109 | g. License Elements means the license attributes listed in the name 110 | of a Creative Commons Public License. The License Elements of this 111 | Public License are Attribution, NonCommercial, and ShareAlike. 112 | 113 | h. Licensed Material means the artistic or literary work, database, 114 | or other material to which the Licensor applied this Public 115 | License. 116 | 117 | i. Licensed Rights means the rights granted to You subject to the 118 | terms and conditions of this Public License, which are limited to 119 | all Copyright and Similar Rights that apply to Your use of the 120 | Licensed Material and that the Licensor has authority to license. 121 | 122 | j. Licensor means the individual(s) or entity(ies) granting rights 123 | under this Public License. 124 | 125 | k. NonCommercial means not primarily intended for or directed towards 126 | commercial advantage or monetary compensation. For purposes of 127 | this Public License, the exchange of the Licensed Material for 128 | other material subject to Copyright and Similar Rights by digital 129 | file-sharing or similar means is NonCommercial provided there is 130 | no payment of monetary compensation in connection with the 131 | exchange. 132 | 133 | l. Share means to provide material to the public by any means or 134 | process that requires permission under the Licensed Rights, such 135 | as reproduction, public display, public performance, distribution, 136 | dissemination, communication, or importation, and to make material 137 | available to the public including in ways that members of the 138 | public may access the material from a place and at a time 139 | individually chosen by them. 140 | 141 | m. Sui Generis Database Rights means rights other than copyright 142 | resulting from Directive 96/9/EC of the European Parliament and of 143 | the Council of 11 March 1996 on the legal protection of databases, 144 | as amended and/or succeeded, as well as other essentially 145 | equivalent rights anywhere in the world. 146 | 147 | n. You means the individual or entity exercising the Licensed Rights 148 | under this Public License. Your has a corresponding meaning. 149 | 150 | 151 | Section 2 -- Scope. 152 | 153 | a. License grant. 154 | 155 | 1. Subject to the terms and conditions of this Public License, 156 | the Licensor hereby grants You a worldwide, royalty-free, 157 | non-sublicensable, non-exclusive, irrevocable license to 158 | exercise the Licensed Rights in the Licensed Material to: 159 | 160 | a. reproduce and Share the Licensed Material, in whole or 161 | in part, for NonCommercial purposes only; and 162 | 163 | b. produce, reproduce, and Share Adapted Material for 164 | NonCommercial purposes only. 165 | 166 | 2. Exceptions and Limitations. For the avoidance of doubt, where 167 | Exceptions and Limitations apply to Your use, this Public 168 | License does not apply, and You do not need to comply with 169 | its terms and conditions. 170 | 171 | 3. Term. The term of this Public License is specified in Section 172 | 6(a). 173 | 174 | 4. Media and formats; technical modifications allowed. The 175 | Licensor authorizes You to exercise the Licensed Rights in 176 | all media and formats whether now known or hereafter created, 177 | and to make technical modifications necessary to do so. The 178 | Licensor waives and/or agrees not to assert any right or 179 | authority to forbid You from making technical modifications 180 | necessary to exercise the Licensed Rights, including 181 | technical modifications necessary to circumvent Effective 182 | Technological Measures. For purposes of this Public License, 183 | simply making modifications authorized by this Section 2(a) 184 | (4) never produces Adapted Material. 185 | 186 | 5. Downstream recipients. 187 | 188 | a. Offer from the Licensor -- Licensed Material. Every 189 | recipient of the Licensed Material automatically 190 | receives an offer from the Licensor to exercise the 191 | Licensed Rights under the terms and conditions of this 192 | Public License. 193 | 194 | b. Additional offer from the Licensor -- Adapted Material. 195 | Every recipient of Adapted Material from You 196 | automatically receives an offer from the Licensor to 197 | exercise the Licensed Rights in the Adapted Material 198 | under the conditions of the Adapter's License You apply. 199 | 200 | c. No downstream restrictions. You may not offer or impose 201 | any additional or different terms or conditions on, or 202 | apply any Effective Technological Measures to, the 203 | Licensed Material if doing so restricts exercise of the 204 | Licensed Rights by any recipient of the Licensed 205 | Material. 206 | 207 | 6. No endorsement. Nothing in this Public License constitutes or 208 | may be construed as permission to assert or imply that You 209 | are, or that Your use of the Licensed Material is, connected 210 | with, or sponsored, endorsed, or granted official status by, 211 | the Licensor or others designated to receive attribution as 212 | provided in Section 3(a)(1)(A)(i). 213 | 214 | b. Other rights. 215 | 216 | 1. Moral rights, such as the right of integrity, are not 217 | licensed under this Public License, nor are publicity, 218 | privacy, and/or other similar personality rights; however, to 219 | the extent possible, the Licensor waives and/or agrees not to 220 | assert any such rights held by the Licensor to the limited 221 | extent necessary to allow You to exercise the Licensed 222 | Rights, but not otherwise. 223 | 224 | 2. Patent and trademark rights are not licensed under this 225 | Public License. 226 | 227 | 3. To the extent possible, the Licensor waives any right to 228 | collect royalties from You for the exercise of the Licensed 229 | Rights, whether directly or through a collecting society 230 | under any voluntary or waivable statutory or compulsory 231 | licensing scheme. In all other cases the Licensor expressly 232 | reserves any right to collect such royalties, including when 233 | the Licensed Material is used other than for NonCommercial 234 | purposes. 235 | 236 | 237 | Section 3 -- License Conditions. 238 | 239 | Your exercise of the Licensed Rights is expressly made subject to the 240 | following conditions. 241 | 242 | a. Attribution. 243 | 244 | 1. If You Share the Licensed Material (including in modified 245 | form), You must: 246 | 247 | a. retain the following if it is supplied by the Licensor 248 | with the Licensed Material: 249 | 250 | i. identification of the creator(s) of the Licensed 251 | Material and any others designated to receive 252 | attribution, in any reasonable manner requested by 253 | the Licensor (including by pseudonym if 254 | designated); 255 | 256 | ii. a copyright notice; 257 | 258 | iii. a notice that refers to this Public License; 259 | 260 | iv. a notice that refers to the disclaimer of 261 | warranties; 262 | 263 | v. a URI or hyperlink to the Licensed Material to the 264 | extent reasonably practicable; 265 | 266 | b. indicate if You modified the Licensed Material and 267 | retain an indication of any previous modifications; and 268 | 269 | c. indicate the Licensed Material is licensed under this 270 | Public License, and include the text of, or the URI or 271 | hyperlink to, this Public License. 272 | 273 | 2. You may satisfy the conditions in Section 3(a)(1) in any 274 | reasonable manner based on the medium, means, and context in 275 | which You Share the Licensed Material. For example, it may be 276 | reasonable to satisfy the conditions by providing a URI or 277 | hyperlink to a resource that includes the required 278 | information. 279 | 3. If requested by the Licensor, You must remove any of the 280 | information required by Section 3(a)(1)(A) to the extent 281 | reasonably practicable. 282 | 283 | b. ShareAlike. 284 | 285 | In addition to the conditions in Section 3(a), if You Share 286 | Adapted Material You produce, the following conditions also apply. 287 | 288 | 1. The Adapter's License You apply must be a Creative Commons 289 | license with the same License Elements, this version or 290 | later, or a BY-NC-SA Compatible License. 291 | 292 | 2. You must include the text of, or the URI or hyperlink to, the 293 | Adapter's License You apply. You may satisfy this condition 294 | in any reasonable manner based on the medium, means, and 295 | context in which You Share Adapted Material. 296 | 297 | 3. You may not offer or impose any additional or different terms 298 | or conditions on, or apply any Effective Technological 299 | Measures to, Adapted Material that restrict exercise of the 300 | rights granted under the Adapter's License You apply. 301 | 302 | 303 | Section 4 -- Sui Generis Database Rights. 304 | 305 | Where the Licensed Rights include Sui Generis Database Rights that 306 | apply to Your use of the Licensed Material: 307 | 308 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 309 | to extract, reuse, reproduce, and Share all or a substantial 310 | portion of the contents of the database for NonCommercial purposes 311 | only; 312 | 313 | b. if You include all or a substantial portion of the database 314 | contents in a database in which You have Sui Generis Database 315 | Rights, then the database in which You have Sui Generis Database 316 | Rights (but not its individual contents) is Adapted Material, 317 | including for purposes of Section 3(b); and 318 | 319 | c. You must comply with the conditions in Section 3(a) if You Share 320 | all or a substantial portion of the contents of the database. 321 | 322 | For the avoidance of doubt, this Section 4 supplements and does not 323 | replace Your obligations under this Public License where the Licensed 324 | Rights include other Copyright and Similar Rights. 325 | 326 | 327 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 328 | 329 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 330 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 331 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 332 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 333 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 334 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 335 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 336 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 337 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 338 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 339 | 340 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 341 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 342 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 343 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 344 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 345 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 346 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 347 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 348 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 349 | 350 | c. The disclaimer of warranties and limitation of liability provided 351 | above shall be interpreted in a manner that, to the extent 352 | possible, most closely approximates an absolute disclaimer and 353 | waiver of all liability. 354 | 355 | 356 | Section 6 -- Term and Termination. 357 | 358 | a. This Public License applies for the term of the Copyright and 359 | Similar Rights licensed here. However, if You fail to comply with 360 | this Public License, then Your rights under this Public License 361 | terminate automatically. 362 | 363 | b. Where Your right to use the Licensed Material has terminated under 364 | Section 6(a), it reinstates: 365 | 366 | 1. automatically as of the date the violation is cured, provided 367 | it is cured within 30 days of Your discovery of the 368 | violation; or 369 | 370 | 2. upon express reinstatement by the Licensor. 371 | 372 | For the avoidance of doubt, this Section 6(b) does not affect any 373 | right the Licensor may have to seek remedies for Your violations 374 | of this Public License. 375 | 376 | c. For the avoidance of doubt, the Licensor may also offer the 377 | Licensed Material under separate terms or conditions or stop 378 | distributing the Licensed Material at any time; however, doing so 379 | will not terminate this Public License. 380 | 381 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 382 | License. 383 | 384 | 385 | Section 7 -- Other Terms and Conditions. 386 | 387 | a. The Licensor shall not be bound by any additional or different 388 | terms or conditions communicated by You unless expressly agreed. 389 | 390 | b. Any arrangements, understandings, or agreements regarding the 391 | Licensed Material not stated herein are separate from and 392 | independent of the terms and conditions of this Public License. 393 | 394 | 395 | Section 8 -- Interpretation. 396 | 397 | a. For the avoidance of doubt, this Public License does not, and 398 | shall not be interpreted to, reduce, limit, restrict, or impose 399 | conditions on any use of the Licensed Material that could lawfully 400 | be made without permission under this Public License. 401 | 402 | b. To the extent possible, if any provision of this Public License is 403 | deemed unenforceable, it shall be automatically reformed to the 404 | minimum extent necessary to make it enforceable. If the provision 405 | cannot be reformed, it shall be severed from this Public License 406 | without affecting the enforceability of the remaining terms and 407 | conditions. 408 | 409 | c. No term or condition of this Public License will be waived and no 410 | failure to comply consented to unless expressly agreed to by the 411 | Licensor. 412 | 413 | d. Nothing in this Public License constitutes or may be interpreted 414 | as a limitation upon, or waiver of, any privileges and immunities 415 | that apply to the Licensor or You, including from the legal 416 | processes of any jurisdiction or authority. 417 | 418 | ======================================================================= 419 | 420 | Creative Commons is not a party to its public 421 | licenses. Notwithstanding, Creative Commons may elect to apply one of 422 | its public licenses to material it publishes and in those instances 423 | will be considered the “Licensor.” The text of the Creative Commons 424 | public licenses is dedicated to the public domain under the CC0 Public 425 | Domain Dedication. Except for the limited purpose of indicating that 426 | material is shared under a Creative Commons public license or as 427 | otherwise permitted by the Creative Commons policies published at 428 | creativecommons.org/policies, Creative Commons does not authorize the 429 | use of the trademark "Creative Commons" or any other trademark or logo 430 | of Creative Commons without its prior written consent including, 431 | without limitation, in connection with any unauthorized modifications 432 | to any of its public licenses or any other arrangements, 433 | understandings, or agreements concerning use of licensed material. For 434 | the avoidance of doubt, this paragraph does not form part of the 435 | public licenses. 436 | 437 | Creative Commons may be contacted at creativecommons.org. -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Openrewrite: Refactoring as Code 2 | 3 | Readable version available on https://jtama.github.io/refactoring-as-code/#/[Github Pages -> ici] 4 | 5 | == Slides 6 | === Generate 7 | 8 | [source%linenums,bash] 9 | ---- 10 | cd slides 11 | jbang qrcode@maxandersen -i images/feedback.png -o images/feedback.png 12 | jbang qrcode@maxandersen -i image/github.png https://github.com/jtama/openrewrite-refactoring-as-code --qr-colo="linear-gradient(90deg, rgba(36,14,0,1) 0%, rgba(9,121,105,1) 35%, rgba(0,212,255,1) 100%);" 13 | podman container run --rm -v $(pwd)/slides:/documents -w /documents asciidoctor/docker-asciidoctor:1.80.0 asciidoctor-revealjs -r asciidoctor-diagram index.adoc 14 | ---- 15 | 16 | === Run locally 17 | 18 | [source%linenums,bash] 19 | ---- 20 | podman container run --name prez --rm -d -p 8080:80 -v $(pwd)/slides:/usr/share/nginx/html nginx 21 | podman container run --name coder --rm -d -p 8443:8443 -v $(pwd):/config/workspace -v ~/.m2:/config/.m2 -e MAVEN_CONFIG=/config/.m2 ghcr.io/jtama/java_jbang_codeserver:latest 22 | ---- 23 | 24 | == `toxic-library` 25 | 26 | Contains a small dumb maven module mocking a toxic library. 27 | 28 | Install locally with `mvn clean install`. 29 | 30 | == `toxic-library-remover` 31 | 32 | Contains sample code demonstrating OpenRewrite capabilities. 33 | 34 | Install locally with `mvn clean install`. 35 | 36 | == `toxic-library-user` 37 | 38 | Contains a small java application using the `toxic-library`. 39 | 40 | Clean using : 41 | 42 | include::toxic-library-user/README.adoc[] -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cd slides 3 | git clone https://github.com/hakimel/reveal.js --depth 1 --branch 5.1.0 4 | rm -rf reveal.js/.git 5 | git clone https://github.com/denehyg/reveal.js-menu --depth 1 --branch 2.1.0 reveal.js/plugin/menu 6 | rm -rf reveal.js/plugin/menu/.git 7 | cd reveal.js && npm i && npm run build && cd ../ 8 | mkdir highlight.js 9 | curl -sLo highlight.js/highlight.min.js https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.3/highlight.min.js -------------------------------------------------------------------------------- /slides/01-openrewrite.adoc: -------------------------------------------------------------------------------- 1 | 2 | [%notitle] 3 | == Openrewrite 4 | 5 | image::openrewrite.svg[width=30%] 6 | image::under_logo.svg[] 7 | 8 | [.notes] 9 | -- 10 | C'est un outil java open-source - Apache 2 11 | 12 | . Debezium 13 | . SdkMan 14 | . Feign 15 | . Hibernate 16 | . Jackson 17 | . JBang 18 | . JReleaser 19 | . Quarkus 20 | -- 21 | 22 | [.transparency.no-transition] 23 | === Les concepts 24 | 25 | image::concepts.jpg[background, size=cover] 26 | 27 | [%notitle] 28 | === Les concepts (2/2) 29 | 30 | [%step] 31 | . Recipe 32 | . **L**ossless **S**yntax **T**ree 33 | . Le pattern visitor 34 | 35 | [.notes] 36 | -- 37 | * Programming languages 38 | ** Java 39 | ** Kotlin 40 | ** Groovy 41 | * Data formats 42 | ** XML 43 | ** Properties 44 | ** YAML 45 | ** JSON 46 | ** Protobuf 47 | * Build tools 48 | ** Maven 49 | ** Gradle 50 | 51 | Par exemple 73 points d'extension pour Java... 52 | -- 53 | 54 | [.transparency.no-transition] 55 | === Anatomie d'une recette 56 | 57 | image::anatomy.png[background, size=cover] 58 | 59 | [%notitle] 60 | === Anatomie d'une recette (2/2) 61 | 62 | [source,java,highlight="3|5|7|9|11|13"] 63 | ---- 64 | public abstract class Recipe implements Cloneable { 65 | 66 | public abstract String getDisplayName(); 67 | 68 | public abstract String getDescription(); 69 | 70 | public Set getTags() { ... } 71 | 72 | public List getRecipeList() { ... } 73 | 74 | public TreeVisitor getVisitor() { ... } 75 | 76 | public void addDataTable(DataTable dataTable) { ... } 77 | } 78 | ---- 79 | 80 | 81 | [.notes] 82 | -- 83 | Des résultats sous forme de _data tables_, et le concept de préconditions. 84 | -- 85 | 86 | [.columns] 87 | === ! 88 | 89 | [.column.is-one-third] 90 | -- 91 | image::permis_de_refactoring.png[] 92 | -- 93 | 94 | [.column] 95 | -- 96 | ✅ Vue d'ensemble du véhicule 97 | -- 98 | 99 | -------------------------------------------------------------------------------- /slides/02-running-recipes.adoc: -------------------------------------------------------------------------------- 1 | 2 | [%notitle] 3 | == Exécution d'une recette 4 | 5 | image::running.avif[background, size=cover] 6 | 7 | [%notitle] 8 | === En modifiant vos poms (1/2) 9 | 10 | [source%linenums,xml,highlight="5..7|15..17|10",step=0] 11 | ---- 12 | 13 | 14 | 15 | 16 | org.openrewrite.maven 17 | rewrite-maven-plugin 18 | 5.46.0 19 | 20 | 21 | org.openrewrite.java.testing.junit5.JUnit4to5Migration 22 | 23 | 24 | 25 | 26 | org.openrewrite.recipe 27 | rewrite-testing-frameworks 28 | RELEASE 29 | 30 | 31 | 32 | 33 | 34 | 35 | ---- 36 | [.fragment, data-fragment-index=0] 37 | Déclaration du plugin 38 | [.fragment, data-fragment-index=1] 39 | Ajout de la dépendance de la recette 40 | [.fragment, data-fragment-index=2] 41 | Activation des recettes 42 | 43 | [%notitle] 44 | === En modifiant vos poms (2/2) 45 | 46 | [source%linenums,console,.fragment] 47 | ---- 48 | $ mvn rewrite:run 49 | ---- 50 | 51 | [.notes] 52 | -- 53 | Pareil avec gradle 54 | -- 55 | 56 | [.no-transition] 57 | === Sans modifier vos poms 58 | 59 | [.fragment] 60 | [source%linenums,console,highlight="1|2..3|4..5",step=0] 61 | ---- 62 | $ mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \ 63 | -Drewrite.recipeArtifactCoordinates=\ 64 | org.openrewrite.recipe:rewrite-testing-frameworks:RELEASE\ 65 | -Drewrite.activeRecipes=\ 66 | org.openrewrite.java.testing.junit5.JUnit4to5Migration 67 | ---- 68 | [.fragment, data-fragment-index=0] 69 | Déclaration du plugin 70 | [.fragment, data-fragment-index=1] 71 | Ajout de la dépendance de la recette 72 | [.fragment, data-fragment-index=2] 73 | Activation des recettes 74 | 75 | [.notes] 76 | -- 77 | Il existe aussi une intégration avec IntelliJ qui facilite beaucoup la vie. 78 | -- 79 | 80 | [.columns] 81 | === ! 82 | 83 | [.column.is-one-third] 84 | -- 85 | image::permis_de_refactoring.png[] 86 | -- 87 | 88 | [.column] 89 | -- 90 | - ✅ Vue d'ensemble du véhicule 91 | - ✅ Savoir démarrer le véhicule 92 | -- 93 | 94 | [.notes] 95 | -- 96 | Les façons de faire décrites ci-dessus ne sont valables que si les recettes ne prennent pas de paramètres. Si telle n'est pas le cas, il va falloir passer à l'étape suivante 97 | -- 98 | -------------------------------------------------------------------------------- /slides/03-declarative-recipes.adoc: -------------------------------------------------------------------------------- 1 | 2 | [.transparency.no-transition] 3 | == Declarative recipes 4 | 5 | image::declarative.jpg[background, size=cover] 6 | 7 | [.notes] 8 | -- 9 | Une recette déclarative est en fait juste un format de déclaration de recette sans avoir à écrire du code. 10 | -- 11 | 12 | 13 | [%notitle] 14 | === Et ça ressemble à ? 15 | 16 | [source%linenums,yaml,highlight="3|4..10|13..17|12|20|26..28|29..32"] 17 | ---- 18 | --- 19 | type: specs.openrewrite.org/v1beta/recipe 20 | name: com.github.jtama.openrewrite.RedIsDead 21 | displayName: Removes that toxic dependency 22 | description: | 23 | Migrate from AcmeToxic ☠️ to AcmeHealthy 😇, 24 | removes dependencies and migrates code. 25 | tags: 26 | - acme 27 | - toxic 28 | recipeList: 29 | - com.github.jtama.openrewrite.CaVaCouperCherie 30 | - org.openrewrite.maven.RemoveDependency: 31 | groupId: com.github.jtama 32 | artifactId: toxic-library 33 | - org.openrewrite.maven.RemoveUnusedProperties: 34 | propertyPattern: .*toxic\.version 35 | --- 36 | type: specs.openrewrite.org/v1beta/recipe 37 | name: com.github.jtama.openrewrite.CaVaCouperCherie 38 | displayName: Ça va vous épater 39 | description: | 40 | Rech. proj. pr proj. priv. Self Dem. Brt. Poss. S’adr. à l’hô. Mart 41 | tags: 42 | - acme 43 | preconditions: 44 | - org.openrewrite.java.search.FindTypes: 45 | fullyQualifiedTypeName: com.github.jtama.toxic.FooBarUtils 46 | recipeList: 47 | - org.openrewrite.java.ChangeMethodTargetToStatic: 48 | methodPattern: com.github.jtama.toxic.BigDecimalUtils valueOf(..) 49 | fullyQualifiedTargetTypeName: java.math.BigDecimal 50 | ---- 51 | 52 | [.notes] 53 | -- 54 | On va créer une recette declarative qui permet de supprimer une dépendance toxique. 55 | Et on imagine ici que la dernière recette est accessible ailleurs. 56 | -- 57 | 58 | [%notitle] 59 | === Comment et où ? 60 | 61 | 62 | Dans un fichier qui doit s'appeler `rewrite.yml` 63 | 64 | [.fragment] 65 | À la racine d'un projet. 66 | [.fragment] 67 | Dans le répertoire `META-INF/rewrite` 68 | 69 | [.notes] 70 | -- 71 | Attention, pas `yaml` 72 | Projet Maven ou Gradle... 73 | -- 74 | 75 | [%notitle] 76 | === Et on l'exécute comme ça 77 | 78 | [.fragment] 79 | [source%linenums,console,highlight="1|2..3"] 80 | ---- 81 | $ mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \ 82 | -Drewrite.activeRecipes=\ 83 | com.github.jtama.openrewrite.RemovesThatToxicDependency 84 | ---- 85 | 86 | [.no-transition] 87 | === Distribution 88 | 89 | Inclure ce fichier dans un module maven fantôme... 90 | 91 | 92 | [.columns] 93 | === ! 94 | 95 | [.column.is-one-third] 96 | -- 97 | image::permis_de_refactoring.png[] 98 | -- 99 | 100 | [.column] 101 | -- 102 | - ✅ Vue d'ensemble du véhicule 103 | - ✅ Savoir démarrer le véhicule 104 | - ✅ Savoir lire une carte 105 | - ✅ Savoir conduire en ville 106 | -- -------------------------------------------------------------------------------- /slides/04-catalogue.adoc: -------------------------------------------------------------------------------- 1 | [.transparency.no-transition] 2 | == Catalogue de recettes 3 | 4 | image::catalog.avif[background, size=cover] 5 | 6 | [.notes] 7 | -- 8 | C'est en tout cas vrai pour toutes les recettes proposées par OpenRewrite, mais il peut y en avoir d'autres. 9 | -- 10 | 11 | [%notitle,background-iframe="https://docs.openrewrite.org/recipes/java/testing/junit5/junit4to5migration"] 12 | === Partons à la découverte du catalogue 13 | 14 | [.notes] 15 | -- 16 | Plus de 500 recettes la dernière fois que j'ai compté. 17 | -- 18 | 19 | 20 | [.columns] 21 | === ! 22 | 23 | [.column.is-one-third] 24 | -- 25 | image::permis_de_refactoring.png[] 26 | -- 27 | 28 | [.column] 29 | -- 30 | - ✅ Vue d'ensemble du véhicule 31 | - ✅ Savoir démarrer le véhicule 32 | - ✅ Savoir lire une carte 33 | -- -------------------------------------------------------------------------------- /slides/05-coding-recipes.adoc: -------------------------------------------------------------------------------- 1 | [.no-transition] 2 | == Ecrire sa propre recette 3 | 4 | Demo time ! 5 | 6 | [%notitle,background-iframe="http://localhost:8443"] 7 | === GO 8 | 9 | [.columns] 10 | === ! 11 | 12 | [.column.is-one-third] 13 | -- 14 | image::permis_de_refactoring.png[] 15 | -- 16 | 17 | [.column] 18 | -- 19 | - ✅ Vue d'ensemble du véhicule 20 | - ✅ Savoir démarrer le véhicule 21 | - ✅ Savoir lire une carte 22 | - ✅ Savoir conduire en ville 23 | - ✅ Savoir drifter sur la glace 24 | -- 25 | 26 | -------------------------------------------------------------------------------- /slides/css/meetup.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Poppins"); 2 | 3 | 4 | :root { 5 | --r-background-color: #EEEEEE; 6 | --r-main-color: #111012; 7 | --r-main-font: 'Poppins'; 8 | } 9 | 10 | body { 11 | 12 | footer { 13 | z-index: 10; 14 | position: absolute; 15 | left: 0%; 16 | width: 100%; 17 | bottom: 0; 18 | min-height: 80px; 19 | text-align: center; 20 | } 21 | 22 | .reveal { 23 | h1 { 24 | /*display: none;*/ 25 | 26 | text-shadow: 0 0 7px #fff, 27 | 0 0 10px #fff, 28 | 0 0 21px #fff, 29 | 0 0 42px #84c8d8, 30 | 0 0 82px #84c8d8, 31 | 0 0 92px #84c8d8, 32 | 0 0 102px #84c8d8, 33 | 0 0 151px #84c8d8; 34 | } 35 | 36 | h2 { 37 | text-shadow: -1px 0 #EEEEEE, 0 1px #EEEEEE, 1px 0 #EEEEEE, 0 -1px #EEEEEE; 38 | position: fixed; 39 | left: 50%; 40 | top: 6px; 41 | transform: translateX(-50%); 42 | width: 100%; 43 | } 44 | 45 | ul { 46 | list-style-type: none; 47 | } 48 | 49 | .progress { 50 | color: #241F35; 51 | height: 7px; 52 | } 53 | 54 | } 55 | 56 | 57 | .slide-background.conclusion { 58 | background: no-repeat center/80% url("../images/conclusion.jpg"); 59 | } 60 | 61 | 62 | .light h2 { 63 | color: var(--r-background-color); 64 | -webkit-text-stroke: 2px black; 65 | text-stroke: 2px black; 66 | font-size: var(--r-heading2-size); 67 | } 68 | 69 | 70 | .transparency.slide-background.present { 71 | opacity: 0.50; 72 | } 73 | 74 | .big { 75 | font-size: 60px; 76 | color: #012d3f; 77 | } 78 | 79 | .use-case { 80 | font-family: "Gochi Hand", serif; 81 | } 82 | 83 | .red { 84 | color: #111012; 85 | } 86 | 87 | img { 88 | border-radius: 10px; 89 | } 90 | 91 | .vertical-align-middle > p { 92 | vertical-align: middle; 93 | } 94 | 95 | .vertical-align-middle > p > span { 96 | vertical-align: middle; 97 | margin: 0; 98 | } 99 | 100 | .vertical-align-middle > p > span > img { 101 | vertical-align: middle; 102 | margin: 0; 103 | } 104 | 105 | .important-text > * { 106 | font-size: xxx-large; 107 | font-weight: bold; 108 | color: #012d3f; 109 | } 110 | 111 | .small { 112 | font-size: small; 113 | } 114 | 115 | .medium { 116 | font-size: 38px; 117 | } 118 | 119 | .column.has-text-right > div > div.hdlist.small > table { 120 | margin-right: 0; 121 | } 122 | 123 | .column.has-text-left > div > div.hdlist.small > table { 124 | margin-left: 0; 125 | } 126 | 127 | section { 128 | .lesson{ 129 | &::before { 130 | content: ""; 131 | background:url("../images/permis_de_refactoring.png"); 132 | background-size: contain; 133 | background-repeat: no-repeat; 134 | width:350px; 135 | height:350px; 136 | display: inline-block; 137 | overflow: hidden; 138 | } 139 | } 140 | 141 | } 142 | 143 | .blur { 144 | filter: blur(4px); 145 | } 146 | 147 | .chercher_remplacer { 148 | position: fixed; 149 | top: 125px; 150 | left: 821px; 151 | } 152 | 153 | .regexp { 154 | position: fixed; 155 | top: 125px; 156 | left: 197px; 157 | } 158 | 159 | .llm { 160 | position: fixed; 161 | top: 355px; 162 | left: 197px; 163 | } 164 | 165 | .click_droit { 166 | position: fixed; 167 | top: 355px; 168 | left: 821px; 169 | overflow: hidden; 170 | } 171 | 172 | li { 173 | list-style-type: none; 174 | } 175 | 176 | audio { 177 | display: none; 178 | } 179 | 180 | .down { 181 | position: fixed; 182 | bottom: 0; 183 | right: 0; 184 | } 185 | } -------------------------------------------------------------------------------- /slides/dev.sh: -------------------------------------------------------------------------------- 1 | fswatch -or . -e *.adoc -I --no-defer | xargs -n1 -I{} podman container run --rm -v $(pwd):/documents -w /documents asciidoctor/docker-asciidoctor:1.80 asciidoctor-revealjs -r asciidoctor-diagram index.adoc -------------------------------------------------------------------------------- /slides/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /slides/images/anatomy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/anatomy.png -------------------------------------------------------------------------------- /slides/images/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/avatar.png -------------------------------------------------------------------------------- /slides/images/catalog.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/catalog.avif -------------------------------------------------------------------------------- /slides/images/catalog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/catalog.jpg -------------------------------------------------------------------------------- /slides/images/chercher_remplacer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/chercher_remplacer.png -------------------------------------------------------------------------------- /slides/images/click_droit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/click_droit.png -------------------------------------------------------------------------------- /slides/images/concepts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/concepts.jpg -------------------------------------------------------------------------------- /slides/images/conclusion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/conclusion.jpg -------------------------------------------------------------------------------- /slides/images/declarative.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/declarative.jpg -------------------------------------------------------------------------------- /slides/images/feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/feedback.png -------------------------------------------------------------------------------- /slides/images/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/github.png -------------------------------------------------------------------------------- /slides/images/jta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/jta.png -------------------------------------------------------------------------------- /slides/images/jta_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/jta_1.png -------------------------------------------------------------------------------- /slides/images/llm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/llm.png -------------------------------------------------------------------------------- /slides/images/logo_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/logo_event.png -------------------------------------------------------------------------------- /slides/images/logo_onepoint.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/logo_onepoint.jpeg -------------------------------------------------------------------------------- /slides/images/openrewrite.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 3 | 4 | 5 | -------------------------------------------------------------------------------- /slides/images/permis_de_refactoring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/permis_de_refactoring.png -------------------------------------------------------------------------------- /slides/images/qrcode_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/qrcode_github.png -------------------------------------------------------------------------------- /slides/images/regexp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/regexp.png -------------------------------------------------------------------------------- /slides/images/reusinage_de_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/reusinage_de_code.png -------------------------------------------------------------------------------- /slides/images/running.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/running.avif -------------------------------------------------------------------------------- /slides/images/sound/punition.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/sound/punition.mp3 -------------------------------------------------------------------------------- /slides/images/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/title.png -------------------------------------------------------------------------------- /slides/images/under_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /slides/images/upside_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtama/openrewrite-refactoring-as-code/076a89938ce33bf8f3336a4e2ba472a80e2b65ca/slides/images/upside_down.png -------------------------------------------------------------------------------- /slides/index-docinfo-footer.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
8 | 9 | 23 | -------------------------------------------------------------------------------- /slides/index.adoc: -------------------------------------------------------------------------------- 1 | = Openrewrite - Refactoring as code 2 | :docinfo: private 3 | :source-highlighter: highlight.js 4 | :highlightjsdir: highlight.js 5 | :autofit-option: 6 | :icons: font 7 | :favicon: favicon.svg 8 | :revealjs_slideNumber: true 9 | :revealjs_theme: white 10 | :revealjs_history: true 11 | :revealjs_pdfseparatefragments: false 12 | :revealjs_width: 1200 13 | :title-slide-background-image: title.png 14 | :title-slide-background-size: cover 15 | :title-slide-background-repeat: no-repeat 16 | :title-slide-filter: blur(4px) 17 | :customcss: css/meetup.css 18 | :imagesdir: images 19 | 20 | include::intro.adoc[] 21 | include::01-openrewrite.adoc[] 22 | include::02-running-recipes.adoc[] 23 | include::04-catalogue.adoc[] 24 | include::03-declarative-recipes.adoc[] 25 | include::05-coding-recipes.adoc[] 26 | include::outro.adoc[] 27 | 28 | -------------------------------------------------------------------------------- /slides/intro.adoc: -------------------------------------------------------------------------------- 1 | [%notitle] 2 | == Openrewrite 3 | 4 | image::upside_down.png[background, size=contain] 5 | 6 | [%notitle,transition=none] 7 | === Chercher / Remplacer 8 | 9 | image::upside_down.png[background, size=contain] 10 | image::chercher_remplacer.png[role=chercher_remplacer] 11 | 12 | [%notitle,transition=none] 13 | === Regexp 14 | 15 | image::upside_down.png[background, size=contain] 16 | image::chercher_remplacer.png[role=chercher_remplacer] 17 | image::regexp.png[role=regexp] 18 | 19 | [%notitle,transition=none] 20 | === Click droit 21 | 22 | image::upside_down.png[background, size=contain] 23 | image::chercher_remplacer.png[role=chercher_remplacer] 24 | image::regexp.png[role=regexp] 25 | image::click_droit.png[role=click_droit] 26 | 27 | [%notitle,transition=none] 28 | === LLM/RAG 29 | 30 | image::upside_down.png[background, size=contain] 31 | image::chercher_remplacer.png[role=chercher_remplacer] 32 | image::regexp.png[role=regexp] 33 | image::click_droit.png[role=click_droit] 34 | image::llm.png[role=llm] 35 | 36 | [%notitle,transition=none,%notitle] 37 | === Punition 38 | 39 | image::upside_down.png[background, size=contain] 40 | image::chercher_remplacer.png[role=chercher_remplacer] 41 | image::regexp.png[role=regexp] 42 | image::click_droit.png[role=click_droit] 43 | image::llm.png[role=llm] 44 | audio::sound/punition.mp3[data-autoplay] 45 | 46 | [%notitle.columns.is-vcentered.transparency] 47 | === Présentation 48 | 49 | [.column.is-one-third] 50 | -- 51 | image::jta_1.png[] 52 | -- 53 | 54 | [.column.is-3.has-text-left.medium] 55 | -- 56 | Jérôme 57 | 58 | Tech Lead/Architecte, Instructeur en permis de réécriture 59 | -- 60 | 61 | [.column] 62 | -- 63 | [.vertical-align-middle] 64 | image:logo_onepoint.jpeg[width=50] 65 | onepoint BDX 66 | 67 | [.vertical-align-middle] 68 | icon:github[] @jtama image:avatar.png[width=100] 69 | -- 70 | 71 | [%notitle] 72 | === Le permis 73 | 74 | image::permis_de_refactoring.png[width=600] 75 | 76 | -------------------------------------------------------------------------------- /slides/outro.adoc: -------------------------------------------------------------------------------- 1 | [.transparency.no-transition] 2 | == Points d'attention 3 | 4 | image::conclusion.jpg[background, size=cover] 5 | 6 | === ! 7 | 8 | 9 | - Quand on n'a qu'un marteau tout ressemble à un clou. 10 | 11 | [.fragment] 12 | Composition de recettes complexes. 13 | 14 | [.fragment] 15 | _java preview feature_ 16 | 17 | 18 | [.transparency.columns.no-transition] 19 | === Merci ! 20 | 21 | [.column] 22 | -- 23 | [.important-text.has-text-left.vertical-align-middle] 24 | Le dépôt github : 25 | 26 | image:qrcode_github.png[alt="https://github.com/jtama/openrewrite-refactor-as-code", width=400] 27 | -- 28 | 29 | [.column] 30 | -- 31 | 32 | [.important-text.has-text-left.vertical-align-middle] 33 | Feedback : 34 | 35 | image:qrcode_feedback.png[width=400] 36 | -- -------------------------------------------------------------------------------- /toxic-library-remover/licenseHeader.txt: -------------------------------------------------------------------------------- 1 | Copyright 2024 Jérôme TAMA. 2 |

3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 |

7 | https://www.apache.org/licenses/LICENSE-2.0 8 |

9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /toxic-library-remover/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | com.github.jtama 7 | toxic-library-remover 8 | 1.0.1-SNAPSHOT 9 | 10 | 11 | UTF-8 12 | UTF-8 13 | 21 14 | 21 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | org.openrewrite.recipe 23 | rewrite-recipe-bom 24 | 3.4.0 25 | pom 26 | import 27 | 28 | 29 | org.junit 30 | junit-bom 31 | 5.13.0-M2 32 | pom 33 | import 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.openrewrite 43 | rewrite-templating 44 | 45 | 46 | javax.annotation 47 | javax.annotation-api 48 | 1.3.2 49 | 50 | 51 | 52 | 53 | org.openrewrite.meta 54 | rewrite-analysis 55 | 56 | 57 | org.openrewrite 58 | rewrite-java 59 | 60 | 61 | org.openrewrite.recipe 62 | rewrite-migrate-java 63 | 64 | 65 | org.openrewrite.recipe 66 | rewrite-static-analysis 67 | 68 | 69 | io.quarkus 70 | quarkus-micrometer-registry-prometheus 71 | 3.17.3 72 | 73 | 74 | 75 | 76 | 77 | com.google.errorprone 78 | error_prone_core 79 | 2.37.0 80 | provided 81 | true 82 | 83 | 84 | com.google.auto.service 85 | auto-service-annotations 86 | 87 | 88 | 89 | 90 | 91 | com.github.jtama 92 | toxic-library 93 | 19.666.45-RC18-FINAL 94 | 95 | 96 | 97 | org.openrewrite 98 | rewrite-test 99 | test 100 | 101 | 102 | 103 | org.junit.jupiter 104 | junit-jupiter 105 | test 106 | 107 | 108 | 109 | org.assertj 110 | assertj-core 111 | 4.0.0-M1 112 | test 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | org.apache.maven.plugins 121 | maven-compiler-plugin 122 | 3.13.0 123 | 124 | 21 125 | 126 | -parameters 127 | 128 | 129 | 130 | org.openrewrite 131 | rewrite-templating 132 | 133 | 134 | 135 | 136 | 140 | 141 | org.openrewrite.maven 142 | rewrite-maven-plugin 143 | 5.46.1 144 | 145 | true 146 | 147 | 148 | 149 | 150 | org.openrewrite.recipe 151 | rewrite-migrate-java 152 | 2.30.1 153 | 154 | 155 | org.openrewrite.recipe 156 | rewrite-rewrite 157 | 0.1.0 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /toxic-library-remover/rewrite.yml: -------------------------------------------------------------------------------- 1 | --- 2 | type: specs.openrewrite.org/v1beta/recipe 3 | name: com.yourorg.ApplyRecipeBestPractices 4 | displayName: Apply Recipe best practices 5 | description: Apply best practices to your recipes, through OpenRewrite's best practices recipe & IntelliJ IDEA plugin. 6 | recipeList: 7 | - org.openrewrite.recipes.OpenRewriteBestPractices -------------------------------------------------------------------------------- /toxic-library-remover/src/main/java/com/github/jtama/openrewrite/RemoveFooBarUtilsIsEmpty.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.openrewrite; 2 | 3 | import com.github.jtama.toxic.FooBarUtils; 4 | import com.google.errorprone.refaster.annotation.AfterTemplate; 5 | import com.google.errorprone.refaster.annotation.BeforeTemplate; 6 | import org.openrewrite.java.template.RecipeDescriptor; 7 | 8 | import java.util.List; 9 | 10 | @RecipeDescriptor( 11 | name = "Remove `FooBarUtils.isEmpty` methodes usages", 12 | description = "Replace any usage of `FooBarUtils.isEMpty` method by standards equivalent.") 13 | public class RemoveFooBarUtilsIsEmpty { 14 | 15 | @RecipeDescriptor( 16 | name = "Replace `FooBarUtils.isEmptyString(String)` with standard equivalent", 17 | description = "Replace `FooBarUtils.isEmptyString(String)` with ternary 'value == null || value.isEmpty()'." 18 | ) 19 | public static class RemoveStringIsEmpty { 20 | 21 | @BeforeTemplate 22 | boolean before(String value) { 23 | return FooBarUtils.isEmpty(value); 24 | } 25 | 26 | @AfterTemplate 27 | boolean after(String value) { 28 | return value == null || value.isEmpty(); 29 | } 30 | 31 | } 32 | 33 | 34 | @RecipeDescriptor( 35 | name = "Replace `FooBarUtils.isEmptyList(List)` with standard equivalent", 36 | description = "Replace `FooBarUtils.isEmptyList(List)` with ternary 'value == null || value.isEmpty()'." 37 | ) 38 | public static class RemoveListIsEmpty { 39 | 40 | @BeforeTemplate 41 | public boolean before(List value) { 42 | return FooBarUtils.isEmpty(value); 43 | } 44 | 45 | @AfterTemplate 46 | public boolean after(List value) { 47 | return value == null || value.isEmpty(); 48 | } 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /toxic-library-remover/src/main/java/com/github/jtama/openrewrite/RemoveFooBarUtilsStringFormatted.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 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 | * https://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 | package com.github.jtama.openrewrite; 17 | 18 | import org.openrewrite.ExecutionContext; 19 | import org.openrewrite.Preconditions; 20 | import org.openrewrite.Recipe; 21 | import org.openrewrite.TreeVisitor; 22 | import org.openrewrite.internal.ListUtils; 23 | import org.openrewrite.java.JavaIsoVisitor; 24 | import org.openrewrite.java.JavaTemplate; 25 | import org.openrewrite.java.MethodMatcher; 26 | import org.openrewrite.java.search.UsesType; 27 | import org.openrewrite.java.tree.Expression; 28 | import org.openrewrite.java.tree.J; 29 | import org.openrewrite.java.tree.Space; 30 | 31 | import java.util.List; 32 | 33 | public class RemoveFooBarUtilsStringFormatted extends Recipe { 34 | 35 | @Override 36 | public String getDisplayName() { 37 | return "Remove `FooBarUtils.stringFormatted`"; 38 | } 39 | 40 | @Override 41 | public String getDescription() { 42 | return "Replace any usage of `FooBarUtils.stringFormatted` with `String.formatted` method."; 43 | } 44 | 45 | @Override 46 | public TreeVisitor getVisitor() { 47 | return new Preconditions.Check( 48 | new UsesType<>("com.github.jtama.toxic.FooBarUtils", true), 49 | new ToStringFormattedVisitor()); 50 | } 51 | 52 | 53 | private static class ToStringFormattedVisitor extends JavaIsoVisitor { 54 | 55 | private final MethodMatcher toxicStringFormatted = new MethodMatcher("com.github.jtama.toxic.FooBarUtils stringFormatted(String,..)"); 56 | private JavaTemplate stringFormatted = JavaTemplate.builder("#{any(java.lang.String)}.formatted()").build(); 57 | 58 | @Override 59 | public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { 60 | J.MethodInvocation methodInvocation = super.visitMethodInvocation(method, ctx); 61 | if (!toxicStringFormatted.matches(methodInvocation)) { 62 | return methodInvocation; 63 | } 64 | maybeRemoveImport("com.github.jtama.toxic.FooBarUtils"); 65 | List arguments = methodInvocation.getArguments(); 66 | J.MethodInvocation mi = stringFormatted.apply( 67 | getCursor(), 68 | methodInvocation.getCoordinates().replace(), 69 | arguments.get(0)); 70 | mi = mi.withArguments(ListUtils.mapFirst( 71 | arguments.subList(1, arguments.size()), 72 | expression -> expression.withPrefix(Space.EMPTY))); 73 | return mi; 74 | } 75 | } 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /toxic-library-remover/src/main/java/com/github/jtama/openrewrite/RemoveLogStartInvocations.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.openrewrite; 2 | 3 | import org.openrewrite.Cursor; 4 | import org.openrewrite.ExecutionContext; 5 | import org.openrewrite.Preconditions; 6 | import org.openrewrite.Recipe; 7 | import org.openrewrite.TreeVisitor; 8 | import org.openrewrite.java.AnnotationMatcher; 9 | import org.openrewrite.java.JavaIsoVisitor; 10 | import org.openrewrite.java.JavaParser; 11 | import org.openrewrite.java.JavaTemplate; 12 | import org.openrewrite.java.MethodMatcher; 13 | import org.openrewrite.java.RemoveMethodInvocationsVisitor; 14 | import org.openrewrite.java.search.UsesType; 15 | import org.openrewrite.java.tree.J; 16 | 17 | import java.util.Collections; 18 | import java.util.Comparator; 19 | 20 | public class RemoveLogStartInvocations extends Recipe { 21 | 22 | 23 | @Override 24 | public String getDisplayName() { 25 | return "Remove `FooBarUtils.compare()` usages"; 26 | } 27 | 28 | @Override 29 | public String getDescription() { 30 | return "Replace any usage of `FooBarUtils.compare()` method by `Objects.compare()` invocations."; 31 | } 32 | 33 | @Override 34 | public TreeVisitor getVisitor() { 35 | return new Preconditions.Check(new UsesType<>("com.github.jtama.toxic.FooBarUtils", true), 36 | new ReplaceCompareVisitor()); 37 | } 38 | 39 | private static class ReplaceCompareVisitor extends JavaIsoVisitor { 40 | 41 | public static final String LOG_START_INVOCATION_PATTERN = "com.github.jtama.toxic.FooBarUtils logStart()"; 42 | private final MethodMatcher logStartInvocaMatcher = new MethodMatcher(LOG_START_INVOCATION_PATTERN); 43 | private final AnnotationMatcher logStartMatcher = new AnnotationMatcher("@io.micrometer.core.annotation.Timed"); 44 | private final JavaTemplate annotationTemplate = JavaTemplate.builder("@Timed") 45 | .imports("io.micrometer.core.annotation.Timed") 46 | .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath())) 47 | .build(); 48 | 49 | public ReplaceCompareVisitor() { 50 | maybeRemoveImport("com.github.jtama.toxic.FooBarUtils"); 51 | } 52 | 53 | @Override 54 | public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { 55 | J.MethodDeclaration md = super.visitMethodDeclaration(method, ctx); 56 | Cursor cursor = getCursor(); 57 | if (cursor.getMessage("appendAnnotation", false)) { 58 | if (md.getLeadingAnnotations().stream() 59 | .noneMatch(logStartMatcher::matches)) { 60 | maybeAddImport("io.micrometer.core.annotation.Timed"); 61 | md = annotationTemplate.apply(cursor, method.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); 62 | } 63 | } 64 | return md; 65 | } 66 | 67 | @Override 68 | public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { 69 | J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); 70 | if (!logStartInvocaMatcher.matches(mi)) { 71 | return mi; 72 | } 73 | getCursor().putMessageOnFirstEnclosing(J.MethodDeclaration.class, "appendAnnotation", true); 74 | this.doAfterVisit(new RemoveMethodInvocationsVisitor(Collections.singletonList(LOG_START_INVOCATION_PATTERN))); 75 | return null; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /toxic-library-remover/src/main/java/com/github/jtama/openrewrite/UseObjectsCompare.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.openrewrite; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.openrewrite.ExecutionContext; 5 | import org.openrewrite.Preconditions; 6 | import org.openrewrite.Recipe; 7 | import org.openrewrite.TreeVisitor; 8 | import org.openrewrite.java.JavaIsoVisitor; 9 | import org.openrewrite.java.JavaParser; 10 | import org.openrewrite.java.JavaTemplate; 11 | import org.openrewrite.java.MethodMatcher; 12 | import org.openrewrite.java.search.UsesType; 13 | import org.openrewrite.java.tree.Comment; 14 | import org.openrewrite.java.tree.J; 15 | import org.openrewrite.java.tree.TextComment; 16 | import org.openrewrite.marker.Markers; 17 | 18 | import java.util.List; 19 | 20 | public class UseObjectsCompare extends Recipe { 21 | 22 | 23 | @Override 24 | public String getDisplayName() { 25 | return "Remove `FooBarUtils.compare()` usages"; 26 | } 27 | 28 | @Override 29 | public String getDescription() { 30 | return "Replace any usage of `FooBarUtils.compare()` method by `Objects.compare()` invocations."; 31 | } 32 | 33 | @Override 34 | public TreeVisitor getVisitor() { 35 | return new Preconditions.Check(new UsesType<>("com.github.jtama.toxic.FooBarUtils", true), 36 | new ReplaceCompareVisitor()); 37 | } 38 | 39 | private static class ReplaceCompareVisitor extends JavaIsoVisitor { 40 | 41 | private final MethodMatcher compareMethodMatcher = new MethodMatcher("com.github.jtama.toxic.FooBarUtils compare(..)"); 42 | private final JavaTemplate objectsCompareTemplate = JavaTemplate.builder("Objects.compare(#{any(java.lang.Object)}, #{any(java.lang.Object)}, #{any(java.util.Comparator)})") 43 | .imports("java.util.Objects") 44 | .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath())) 45 | .build(); 46 | 47 | public ReplaceCompareVisitor() { 48 | maybeRemoveImport("com.github.jtama.toxic.FooBarUtils"); 49 | } 50 | 51 | @Override 52 | public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { 53 | J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); 54 | if (compareMethodMatcher.matches(mi)) { 55 | maybeAddImport("java.util.Objects"); 56 | mi = objectsCompareTemplate.apply(getCursor(), mi.getCoordinates().replace(), 57 | mi.getArguments().get(0), mi.getArguments().get(1), mi.getArguments().get(2)); 58 | String comment = "Comparing %s using %s".formatted( 59 | mi.getArguments().get(0).getType().toString(), 60 | mi.getArguments().get(2).getType().toString()); 61 | if (getCursor().getParent().getParent().getValue() instanceof J.Block) { 62 | mi = mi.withComments(getComment(comment, mi)); 63 | } else { 64 | getCursor().dropParentUntil(this::isAcceptable).putMessage("comment", comment); 65 | } 66 | } 67 | return mi; 68 | } 69 | 70 | @Override 71 | public J.Assignment visitAssignment(J.Assignment assignment, ExecutionContext executionContext) { 72 | J.Assignment visitedAssignment = super.visitAssignment(assignment, executionContext); 73 | String comment = getCursor().getMessage("comment", ""); 74 | if (!comment.isEmpty() && visitedAssignment.getComments().isEmpty()) { 75 | visitedAssignment = visitedAssignment.withComments(getComment(comment, visitedAssignment)); 76 | getCursor().clearMessages(); 77 | } 78 | return visitedAssignment; 79 | } 80 | 81 | @Override 82 | public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext executionContext) { 83 | J.VariableDeclarations visitVariableDeclarations = super.visitVariableDeclarations(multiVariable, executionContext); 84 | String comment = getCursor().getMessage("comment", ""); 85 | if (!comment.isEmpty() && visitVariableDeclarations.getComments().isEmpty()) { 86 | visitVariableDeclarations = visitVariableDeclarations.withComments(getComment(comment, visitVariableDeclarations)); 87 | getCursor().clearMessages(); 88 | } 89 | return visitVariableDeclarations; 90 | } 91 | 92 | @Override 93 | public J.Return visitReturn(J.Return _return, ExecutionContext executionContext) { 94 | J.Return visitedReturn = super.visitReturn(_return, executionContext); 95 | String comment = getCursor().getMessage("comment", ""); 96 | if (!comment.isEmpty() && visitedReturn.getComments().isEmpty()) { 97 | visitedReturn = visitedReturn.withComments(getComment(comment, visitedReturn)); 98 | getCursor().clearMessages(); 99 | } 100 | return visitedReturn; 101 | } 102 | 103 | private @NotNull List getComment(String commment, J j) { 104 | return List.of(new TextComment(false, commment, j.getPrefix().getWhitespace(), Markers.EMPTY)); 105 | } 106 | 107 | private boolean isAcceptable(Object j) { 108 | return switch (j) { 109 | case J.VariableDeclarations v -> true; 110 | case J.Return r -> true; 111 | case J.Assignment a -> true; 112 | default -> false; 113 | }; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /toxic-library-remover/src/main/resources/META-INF/rewrite/rewrite.yml: -------------------------------------------------------------------------------- 1 | --- 2 | type: specs.openrewrite.org/v1beta/recipe 3 | name: com.github.jtama.openrewrite.RemovesThatToxicDependency 4 | displayName: Removes that toxic dependency 5 | description: | 6 | Migrate from AcmeToxic ☠️ to AcmeHealthy 😇, 7 | removes dependencies and migrates code. 8 | tags: 9 | - acme 10 | - toxic 11 | recipeList: 12 | - org.openrewrite.java.ChangeMethodTargetToStatic: 13 | methodPattern: com.github.jtama.toxic.BigDecimalUtils valueOf(..) 14 | fullyQualifiedTargetTypeName: java.math.BigDecimal 15 | - com.github.jtama.openrewrite.VousAllezVoirCeQueVousAllezVoir 16 | - org.openrewrite.java.RemoveUnusedImports 17 | - org.openrewrite.staticanalysis.RemoveUnusedPrivateFields 18 | - org.openrewrite.maven.RemoveDependency: 19 | groupId: com.github.jtama 20 | artifactId: toxic-library 21 | - org.openrewrite.maven.RemoveProperty: 22 | propertyName: toxic.version 23 | --- 24 | type: specs.openrewrite.org/v1beta/recipe 25 | name: com.github.jtama.openrewrite.VousAllezVoirCeQueVousAllezVoir 26 | displayName: Ça va vous épater 27 | description: | 28 | Rech. proj. pr proj. priv. Self Dem. Brt. Poss. S’adr. à l’hô. Mart 29 | tags: 30 | - acme 31 | preconditions: 32 | - org.openrewrite.java.search.FindTypes: 33 | fullyQualifiedTypeName: com.github.jtama.toxic.FooBarUtils 34 | recipeList: 35 | - com.github.jtama.openrewrite.RemoveFooBarUtilsIsEmptyRecipes 36 | - com.github.jtama.openrewrite.RemoveFooBarUtilsStringFormatted 37 | - com.github.jtama.openrewrite.RemoveLogStartInvocations 38 | - com.github.jtama.openrewrite.UseObjectsCompare -------------------------------------------------------------------------------- /toxic-library-remover/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /toxic-library-remover/src/test/java/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # Limit continuation indent to 2 spaces for Java files, as we heavily use continuations around our text blocks. 4 | [*.java] 5 | indent_size = 4 6 | ij_continuation_indent_size = 2 7 | -------------------------------------------------------------------------------- /toxic-library-remover/src/test/java/com/github/jtama/openrewrite/RemoveFooBarCompareTest.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.openrewrite; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.openrewrite.DocumentExample; 5 | import org.openrewrite.java.JavaParser; 6 | import org.openrewrite.test.RecipeSpec; 7 | import org.openrewrite.test.RewriteTest; 8 | 9 | import static org.openrewrite.java.Assertions.java; 10 | 11 | class RemoveFooBarCompareTest implements RewriteTest { 12 | 13 | @Override 14 | public void defaults(RecipeSpec spec) { 15 | spec.recipe(new UseObjectsCompare()) 16 | .parser(JavaParser.fromJavaVersion() 17 | .logCompilationWarningsAndErrors(true) 18 | .classpath("toxic-library")); 19 | } 20 | 21 | @DocumentExample 22 | @Test 23 | void replaceAndCommentDeclaration() { 24 | rewriteRun( 25 | //language=java 26 | java( 27 | """ 28 | import com.github.jtama.toxic.FooBarUtils; 29 | 30 | public class ManualGearCar { 31 | private static final FooBarUtils UTILS = new FooBarUtils(); 32 | 33 | public void virage(String param) { 34 | int val = UTILS.compare(param, 35 | "au frein à main ?", 36 | (o1,o2) -> o1.compareTo(o2)); 37 | } 38 | } 39 | """, 40 | """ 41 | import com.github.jtama.toxic.FooBarUtils; 42 | 43 | import java.util.Objects; 44 | 45 | public class ManualGearCar { 46 | private static final FooBarUtils UTILS = new FooBarUtils(); 47 | 48 | public void virage(String param) { 49 | //Comparing java.lang.String using java.util.Comparator 50 | int val = Objects.compare(param, "au frein à main ?", (o1, o2) -> o1.compareTo(o2)); 51 | } 52 | } 53 | """)); 54 | } 55 | 56 | @Test 57 | void replaceAndCommentAssignment() { 58 | rewriteRun( 59 | //language=java 60 | java( 61 | """ 62 | import com.github.jtama.toxic.FooBarUtils; 63 | 64 | public class ManualGearCar { 65 | private static final FooBarUtils UTILS = new FooBarUtils(); 66 | 67 | public void virage(String param) { 68 | int val; 69 | val = UTILS.compare(param, 70 | "au frein à main ?", 71 | (o1,o2) -> o1.compareTo(o2)); 72 | } 73 | } 74 | """, 75 | """ 76 | import com.github.jtama.toxic.FooBarUtils; 77 | 78 | import java.util.Objects; 79 | 80 | public class ManualGearCar { 81 | private static final FooBarUtils UTILS = new FooBarUtils(); 82 | 83 | public void virage(String param) { 84 | int val; 85 | //Comparing java.lang.String using java.util.Comparator 86 | val = Objects.compare(param, "au frein à main ?", (o1, o2) -> o1.compareTo(o2)); 87 | } 88 | } 89 | """)); 90 | } 91 | 92 | @Test 93 | void replaceAndCommentReturn() { 94 | rewriteRun( 95 | //language=java 96 | java( 97 | """ 98 | import com.github.jtama.toxic.FooBarUtils; 99 | 100 | public class ManualGearCar { 101 | private static final FooBarUtils UTILS = new FooBarUtils(); 102 | 103 | public int virage(String param) { 104 | return UTILS.compare(param, 105 | "au frein à main ?", 106 | (o1,o2) -> o1.compareTo(o2)); 107 | } 108 | } 109 | """, 110 | """ 111 | import com.github.jtama.toxic.FooBarUtils; 112 | 113 | import java.util.Objects; 114 | 115 | public class ManualGearCar { 116 | private static final FooBarUtils UTILS = new FooBarUtils(); 117 | 118 | public int virage(String param) { 119 | //Comparing java.lang.String using java.util.Comparator 120 | return Objects.compare(param, "au frein à main ?", (o1, o2) -> o1.compareTo(o2)); 121 | } 122 | } 123 | """)); 124 | } 125 | 126 | @Test 127 | void replaceAndCommentInvocations() { 128 | rewriteRun( 129 | //language=java 130 | java( 131 | """ 132 | import com.github.jtama.toxic.FooBarUtils; 133 | 134 | public class ManualGearCar { 135 | private static final FooBarUtils UTILS = new FooBarUtils(); 136 | 137 | public void virage(String param) { 138 | UTILS.compare(param, 139 | "au frein à main ?", 140 | (o1,o2) -> o1.compareTo(o2)); 141 | } 142 | } 143 | """, 144 | """ 145 | import com.github.jtama.toxic.FooBarUtils; 146 | 147 | import java.util.Objects; 148 | 149 | public class ManualGearCar { 150 | private static final FooBarUtils UTILS = new FooBarUtils(); 151 | 152 | public void virage(String param) { 153 | //Comparing java.lang.String using java.util.Comparator 154 | Objects.compare(param, "au frein à main ?", (o1, o2) -> o1.compareTo(o2)); 155 | } 156 | } 157 | """)); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /toxic-library-remover/src/test/java/com/github/jtama/openrewrite/RemoveFooBarIsEmptyTest.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.openrewrite; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.openrewrite.DocumentExample; 5 | import org.openrewrite.java.JavaParser; 6 | import org.openrewrite.test.RecipeSpec; 7 | import org.openrewrite.test.RewriteTest; 8 | 9 | import static org.openrewrite.java.Assertions.java; 10 | 11 | class RemoveFooBarIsEmptyTest implements RewriteTest { 12 | 13 | @Override 14 | public void defaults(RecipeSpec spec) { 15 | spec.recipe(new RemoveFooBarUtilsIsEmptyRecipes()) 16 | .parser(JavaParser.fromJavaVersion() 17 | .logCompilationWarningsAndErrors(true) 18 | .classpath("toxic-library")); 19 | } 20 | 21 | @DocumentExample 22 | @Test 23 | void removeAllIsEmptyInvocation() { 24 | rewriteRun( 25 | //language=java 26 | java( 27 | """ 28 | import static com.github.jtama.toxic.FooBarUtils.isEmpty; 29 | 30 | import java.util.List; 31 | 32 | public class ForTestingPurpose { 33 | 34 | public void virage(String param) { 35 | System.out.printf("On le prend ce virage ? %s", isEmpty(param)); 36 | } 37 | 38 | public void auFreinAMain(List values) { 39 | System.out.printf("Au frein à main ? %s", isEmpty(values)); 40 | } 41 | } 42 | """, 43 | """ 44 | import java.util.List; 45 | 46 | public class ForTestingPurpose { 47 | 48 | public void virage(String param) { 49 | System.out.printf("On le prend ce virage ? %s", param == null || param.isEmpty()); 50 | } 51 | 52 | public void auFreinAMain(List values) { 53 | System.out.printf("Au frein à main ? %s", values == null || values.isEmpty()); 54 | } 55 | } 56 | """)); 57 | } 58 | 59 | @Test 60 | void removeIEmptyInvocation() { 61 | rewriteRun( 62 | spec -> spec.recipe(new RemoveFooBarUtilsIsEmptyRecipes.RemoveListIsEmptyRecipe()), 63 | //language=java 64 | java( 65 | """ 66 | import static com.github.jtama.toxic.FooBarUtils.isEmpty; 67 | 68 | import java.util.List; 69 | 70 | public class AutomaticCar { 71 | 72 | public void virage(String param) { 73 | System.out.printf("On le prend ce virage ? %s", isEmpty(param)); 74 | } 75 | 76 | public void auFreinAMain(List values) { 77 | System.out.printf("Au frein à main ? %s", isEmpty(values)); 78 | } 79 | } 80 | """, 81 | """ 82 | import static com.github.jtama.toxic.FooBarUtils.isEmpty; 83 | 84 | import java.util.List; 85 | 86 | public class AutomaticCar { 87 | 88 | public void virage(String param) { 89 | System.out.printf("On le prend ce virage ? %s", isEmpty(param)); 90 | } 91 | 92 | public void auFreinAMain(List values) { 93 | System.out.printf("Au frein à main ? %s", values == null || values.isEmpty()); 94 | } 95 | } 96 | """)); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /toxic-library-remover/src/test/java/com/github/jtama/openrewrite/RemoveFooBarUtilsStringFormattedTest.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.openrewrite; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.openrewrite.DocumentExample; 5 | import org.openrewrite.java.JavaParser; 6 | import org.openrewrite.test.RecipeSpec; 7 | import org.openrewrite.test.RewriteTest; 8 | 9 | import static org.openrewrite.java.Assertions.java; 10 | 11 | class RemoveFooBarUtilsStringFormattedTest implements RewriteTest { 12 | 13 | @Override 14 | public void defaults(RecipeSpec spec) { 15 | spec.recipe(new RemoveFooBarUtilsStringFormatted()) 16 | .parser(JavaParser.fromJavaVersion() 17 | .logCompilationWarningsAndErrors(true) 18 | .classpath("toxic-library") 19 | ); 20 | } 21 | 22 | @DocumentExample 23 | @Test 24 | void removeStringFormattedInvocation() { 25 | rewriteRun( 26 | //language=java 27 | java( 28 | """ 29 | import com.github.jtama.toxic.FooBarUtils; 30 | 31 | public class FullDriftCar { 32 | 33 | public String foo() { 34 | return new FooBarUtils().stringFormatted("Hello %s %s %s", 2L, 35 | "tutu" + 36 | "tata", 37 | this.getClass() 38 | .getName()); 39 | } 40 | } 41 | """, 42 | """ 43 | public class FullDriftCar { 44 | 45 | public String foo() { 46 | return "Hello %s %s %s".formatted(2L, 47 | "tutu" + 48 | "tata", 49 | this.getClass() 50 | .getName()); 51 | } 52 | } 53 | """)); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /toxic-library-remover/src/test/java/com/github/jtama/openrewrite/RemoveLogStartInvocationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.openrewrite; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.openrewrite.DocumentExample; 5 | import org.openrewrite.java.JavaParser; 6 | import org.openrewrite.test.RecipeSpec; 7 | import org.openrewrite.test.RewriteTest; 8 | 9 | import static org.openrewrite.java.Assertions.java; 10 | 11 | class RemoveLogStartInvocationTest implements RewriteTest { 12 | 13 | @Override 14 | public void defaults(RecipeSpec spec) { 15 | spec.recipe(new RemoveLogStartInvocations()) 16 | .parser(JavaParser.fromJavaVersion() 17 | .logCompilationWarningsAndErrors(true) 18 | .classpath("toxic-library", "quarkus-micrometer-registry-prometheus")); 19 | 20 | } 21 | 22 | @DocumentExample 23 | @Test 24 | void removeLogStartInvocations() { 25 | rewriteRun( 26 | //language=java 27 | java( 28 | """ 29 | import com.github.jtama.toxic.FooBarUtils; 30 | 31 | public class ManualGearCar { 32 | 33 | @Deprecated 34 | public void drift(String param) { 35 | FooBarUtils.logStart(); 36 | } 37 | 38 | public void hardBreak(Boolean param) { 39 | // do nothing 40 | } 41 | } 42 | """, 43 | """ 44 | import io.micrometer.core.annotation.Timed; 45 | 46 | public class ManualGearCar { 47 | 48 | @Deprecated 49 | @Timed 50 | public void drift(String param) { 51 | } 52 | 53 | public void hardBreak(Boolean param) { 54 | // do nothing 55 | } 56 | } 57 | """)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /toxic-library-user/README.adoc: -------------------------------------------------------------------------------- 1 | [source%linenums, bash] 2 | ---- 3 | mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \ 4 | -Drewrite.recipeArtifactCoordinates=com.github.jtama:toxic-library-remover:1.0.1-SNAPSHOT \ 5 | -Drewrite.activeRecipes=com.github.jtama.openrewrite.RemovesThatToxicDependency 6 | ---- -------------------------------------------------------------------------------- /toxic-library-user/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.jtama 8 | toxic-library-user 9 | 1.0.1-SNAPSHOT 10 | 11 | 12 | 21 13 | 21 14 | UTF-8 15 | 3.8.1 16 | 3.17.3 17 | 3.5.2 18 | 19.666.45-RC18-FINAL 19 | 20 | 21 | 22 | 23 | io.quarkus 24 | quarkus-bom 25 | ${quarkus.version} 26 | pom 27 | import 28 | 29 | 30 | 31 | 32 | 33 | com.github.jtama 34 | toxic-library 35 | ${toxic.version} 36 | 37 | 38 | io.quarkus 39 | quarkus-resteasy-jsonb 40 | 41 | 42 | io.quarkus 43 | quarkus-micrometer-registry-prometheus 44 | 45 | 46 | io.quarkus 47 | quarkus-security 48 | 49 | 50 | io.quarkus 51 | quarkus-hibernate-orm-panache 52 | 53 | 54 | io.quarkus 55 | quarkus-hibernate-validator 56 | 57 | 58 | io.quarkus 59 | quarkus-jdbc-postgresql 60 | 61 | 62 | io.quarkus 63 | quarkus-junit5 64 | test 65 | 66 | 67 | io.rest-assured 68 | rest-assured 69 | test 70 | 71 | 72 | 73 | 74 | 75 | io.quarkus 76 | quarkus-maven-plugin 77 | ${quarkus.version} 78 | true 79 | 80 | 81 | 82 | build 83 | generate-code 84 | generate-code-tests 85 | 86 | 87 | 88 | 89 | 90 | maven-compiler-plugin 91 | ${compiler-plugin.version} 92 | 93 | 94 | maven-surefire-plugin 95 | ${surefire-plugin.version} 96 | 97 | 98 | org.jboss.logmanager.LogManager 99 | ${maven.home} 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/exception/DuplicateEntityException.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.exception; 2 | 3 | public class DuplicateEntityException extends RuntimeException { 4 | public DuplicateEntityException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/exception/InvalidBookingException.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.exception; 2 | 3 | public class InvalidBookingException extends RuntimeException { 4 | public InvalidBookingException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/exception/InvalidNameException.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.exception; 2 | 3 | public class InvalidNameException extends RuntimeException { 4 | public InvalidNameException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/exception/OnerentExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.exception; 2 | 3 | import jakarta.ws.rs.NotAuthorizedException; 4 | import jakarta.ws.rs.core.Response; 5 | import jakarta.ws.rs.ext.ExceptionMapper; 6 | import jakarta.ws.rs.ext.Provider; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.function.Function; 10 | 11 | @Provider 12 | public class OnerentExceptionHandler implements ExceptionMapper { 13 | 14 | private static Map, Function> mappers; 15 | private static Function functionalError = e -> Response.status(Response.Status.OK).entity(e.getMessage()).build(); 16 | private static Function defaultHandler = e -> Response.status(Response.Status.INTERNAL_SERVER_ERROR) 17 | .entity(e.getMessage()) 18 | .build(); 19 | 20 | static { 21 | mappers = new HashMap<>(); 22 | mappers.put(DuplicateEntityException.class, e -> Response.status(Response.Status.CONFLICT) 23 | .entity(e.getMessage()) 24 | .build()); 25 | mappers.put(UnknownEntityException.class, e -> Response.status(Response.Status.NOT_FOUND) 26 | .entity(e.getMessage()) 27 | .build()); 28 | mappers.put(NotAuthorizedException.class, e -> Response.status(Response.Status.UNAUTHORIZED) 29 | .entity("He non du con") 30 | .build()); 31 | mappers.put(InvalidBookingException.class,functionalError); 32 | mappers.put(InvalidNameException.class,functionalError); 33 | mappers.put(UnavailableException.class,functionalError); 34 | 35 | } 36 | 37 | @Override 38 | public Response toResponse(Exception exception) { 39 | return mappers.getOrDefault(exception.getClass(), defaultHandler).apply(exception); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/exception/UnavailableException.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.exception; 2 | 3 | public class UnavailableException extends RuntimeException { 4 | public UnavailableException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/exception/UnknownEntityException.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.exception; 2 | 3 | public class UnknownEntityException extends RuntimeException { 4 | public UnknownEntityException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/hostels/Hostel.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.hostels; 2 | 3 | import com.github.jtama.app.exception.DuplicateEntityException; 4 | import com.github.jtama.app.exception.InvalidNameException; 5 | import com.github.jtama.toxic.FooBarUtils; 6 | import io.quarkus.hibernate.orm.panache.PanacheEntity; 7 | import io.quarkus.runtime.annotations.RegisterForReflection; 8 | import jakarta.persistence.Entity; 9 | 10 | import java.util.Optional; 11 | import java.util.regex.Matcher; 12 | import java.util.regex.Pattern; 13 | 14 | @Entity 15 | @RegisterForReflection 16 | public class Hostel extends PanacheEntity { 17 | 18 | private static final String PATTERN = "[a-zA-Z]([-a-z0-9]*[a-z0-9])"; 19 | private static final Pattern NAME_PATTERN = Pattern.compile(PATTERN); 20 | 21 | private String name; 22 | 23 | public static Hostel persistIfNotExists(Hostel hostel) { 24 | System.out.println(FooBarUtils.isEmpty(hostel.getName())); 25 | if (!validateName(hostel.getName())) { 26 | throw new InvalidNameException(new FooBarUtils().stringFormatted("Name %s is invalid for a hostel. Name should comply the following pattern %s", hostel.getName(), PATTERN)); 27 | } 28 | if (Hostel.count("name", hostel.name) > 0) { 29 | throw new DuplicateEntityException(new FooBarUtils().stringFormatted("Hostel %s already exists", hostel.name)); 30 | } 31 | hostel.persist(); 32 | return hostel; 33 | } 34 | 35 | private static boolean validateName(String name) { 36 | Matcher matcher = NAME_PATTERN.matcher(name); 37 | return matcher.matches(); 38 | } 39 | 40 | public static Optional findByName(String name) { 41 | return find("name", name).firstResultOptional(); 42 | } 43 | 44 | 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/hostels/HostelController.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.hostels; 2 | 3 | import com.github.jtama.app.reservation.Reservation; 4 | import com.github.jtama.toxic.BigDecimalUtils; 5 | import com.github.jtama.toxic.FooBarUtils; 6 | import jakarta.annotation.security.RolesAllowed; 7 | import jakarta.inject.Inject; 8 | import jakarta.transaction.Transactional; 9 | import jakarta.ws.rs.Consumes; 10 | import jakarta.ws.rs.GET; 11 | import jakarta.ws.rs.POST; 12 | import jakarta.ws.rs.Path; 13 | import jakarta.ws.rs.PathParam; 14 | import jakarta.ws.rs.Produces; 15 | import jakarta.ws.rs.QueryParam; 16 | import jakarta.ws.rs.core.Context; 17 | import jakarta.ws.rs.core.MediaType; 18 | import jakarta.ws.rs.core.SecurityContext; 19 | 20 | import java.security.Security; 21 | import java.util.List; 22 | 23 | @Path("/api/hostels") 24 | @Produces(MediaType.APPLICATION_JSON) 25 | public class HostelController { 26 | 27 | @Inject 28 | HostelReservationService hostelReservationService; 29 | 30 | @GET 31 | public List getAll() { 32 | return Hostel.listAll(); 33 | } 34 | 35 | @POST 36 | @Consumes(MediaType.APPLICATION_JSON) 37 | @RolesAllowed("ADMIN") 38 | @Transactional 39 | public Hostel create(Hostel hostel) { 40 | return Hostel.persistIfNotExists(hostel); 41 | } 42 | 43 | @POST 44 | @Path("/{name}/book") 45 | @RolesAllowed("USER") 46 | public Reservation book(@PathParam("name")String name, @QueryParam("month") Integer month, @Context SecurityContext security) { 47 | BigDecimalUtils.valueOf(month.longValue());// Because I can ! 48 | return hostelReservationService.book(name, month, security.getUserPrincipal().getName()); 49 | } 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/hostels/HostelReservationService.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.hostels; 2 | 3 | import com.github.jtama.app.exception.UnavailableException; 4 | import com.github.jtama.app.exception.UnknownEntityException; 5 | import com.github.jtama.app.reservation.Reservation; 6 | import com.github.jtama.app.util.MonthValidator; 7 | import com.github.jtama.toxic.FooBarUtils; 8 | import jakarta.enterprise.context.ApplicationScoped; 9 | import jakarta.inject.Inject; 10 | import jakarta.transaction.Transactional; 11 | 12 | import java.util.Optional; 13 | 14 | @ApplicationScoped 15 | public class HostelReservationService { 16 | 17 | @Inject 18 | MonthValidator monthValidator; 19 | 20 | @Transactional 21 | public Reservation book(String name, int month, String userName) { 22 | monthValidator.validateMonth(month); 23 | System.out.println(FooBarUtils.isEmpty(userName)); 24 | if(Reservation.existsByUserNameAndMonthAndHostelName(userName, month, name)){ 25 | throw new UnavailableException("Hostel %s is already booked for month %s".formatted(name, month)); 26 | } 27 | 28 | Reservation reservation = new Reservation(userName,month); 29 | 30 | Optional hostel = Hostel.findByName(name); 31 | if (hostel.isEmpty()){ 32 | throw new UnknownEntityException("The hostel %s doesn't exist".formatted(name)); 33 | } 34 | reservation.setHostel(hostel.get()); 35 | return reservation; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/reservation/Reservation.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.reservation; 2 | 3 | 4 | import com.github.jtama.app.hostels.Hostel; 5 | import com.github.jtama.app.rocket.Rocket; 6 | import io.quarkus.hibernate.orm.panache.PanacheEntity; 7 | import io.quarkus.runtime.annotations.RegisterForReflection; 8 | import jakarta.persistence.Entity; 9 | import jakarta.persistence.JoinColumn; 10 | import jakarta.persistence.OneToOne; 11 | 12 | import java.util.Optional; 13 | 14 | @Entity 15 | @RegisterForReflection 16 | public class Reservation extends PanacheEntity { 17 | 18 | private String userName; 19 | 20 | private int month; 21 | 22 | @OneToOne 23 | @JoinColumn(name = "hostel_id") 24 | private Hostel hostel; 25 | 26 | @OneToOne 27 | @JoinColumn(name = "rocket_id") 28 | private Rocket rocket; 29 | 30 | public static Boolean existsByUserNameAndMonthAndHostelName(String user, int month, String name) { 31 | return count("userName = ?1 and month = ?2 and hostel.name = ?3", user, month, name) > 0; 32 | } 33 | 34 | public static Optional findByUserNameAndMonthAndHostelIsNotNull(String user, int month) { 35 | return find("userName = ?1 and month = ?2 and hostel is not null", user, month).firstResultOptional(); 36 | } 37 | 38 | public static Boolean existsByMonthAndRocketName(int month, String name) { 39 | return count("month = ?1 and rocket.name = ?2", month, name) > 0; 40 | } 41 | 42 | public Reservation() { 43 | } 44 | 45 | public Reservation(String userName, int month) { 46 | this.userName = userName; 47 | this.month = month; 48 | } 49 | 50 | public String getUserName() { 51 | return userName; 52 | } 53 | 54 | public void setUserName(String userName) { 55 | this.userName = userName; 56 | } 57 | 58 | public int getMonth() { 59 | return month; 60 | } 61 | 62 | public void setMonth(int month) { 63 | this.month = month; 64 | } 65 | 66 | public Hostel getHostel() { 67 | return hostel; 68 | } 69 | 70 | public void setHostel(Hostel house) { 71 | this.hostel = house; 72 | } 73 | 74 | public Rocket getRocket() { 75 | return rocket; 76 | } 77 | 78 | public void setRocket(Rocket rocket) { 79 | this.rocket = rocket; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/rocket/Rocket.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.rocket; 2 | 3 | 4 | import com.github.jtama.app.exception.DuplicateEntityException; 5 | import com.github.jtama.toxic.FooBarUtils; 6 | import io.quarkus.hibernate.orm.panache.PanacheEntity; 7 | import io.quarkus.runtime.annotations.RegisterForReflection; 8 | import jakarta.persistence.Entity; 9 | import jakarta.persistence.EnumType; 10 | import jakarta.persistence.Enumerated; 11 | import jakarta.validation.constraints.NotBlank; 12 | import jakarta.validation.constraints.Size; 13 | 14 | import java.util.Optional; 15 | 16 | @Entity 17 | @RegisterForReflection 18 | public class Rocket extends PanacheEntity { 19 | 20 | @NotBlank 21 | @Size(min = 1, max = 50) 22 | private String name; 23 | 24 | @Enumerated(EnumType.STRING) 25 | private RocketType type; 26 | 27 | public static Optional findByName(String name) { 28 | return find("name", name).firstResultOptional(); 29 | } 30 | 31 | public static Rocket persistIfNotExists(Rocket rocket) { 32 | if (find("name", rocket.name).count() > 0) { 33 | throw new DuplicateEntityException(new FooBarUtils().stringFormatted("Rocket named %s already exists", rocket.name)); 34 | } 35 | rocket.persist(); 36 | return rocket; 37 | } 38 | 39 | public void setName(String name) { 40 | this.name = name; 41 | } 42 | 43 | public void setType(RocketType type) { 44 | this.type = type; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public RocketType getType() { 52 | return type; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/rocket/RocketController.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.rocket; 2 | 3 | import com.github.jtama.app.reservation.Reservation; 4 | import jakarta.annotation.security.RolesAllowed; 5 | import jakarta.inject.Inject; 6 | import jakarta.transaction.Transactional; 7 | import jakarta.validation.Valid; 8 | import jakarta.ws.rs.Consumes; 9 | import jakarta.ws.rs.GET; 10 | import jakarta.ws.rs.POST; 11 | import jakarta.ws.rs.Path; 12 | import jakarta.ws.rs.PathParam; 13 | import jakarta.ws.rs.Produces; 14 | import jakarta.ws.rs.QueryParam; 15 | import jakarta.ws.rs.core.Context; 16 | import jakarta.ws.rs.core.MediaType; 17 | import jakarta.ws.rs.core.Response; 18 | import jakarta.ws.rs.core.SecurityContext; 19 | import org.jboss.resteasy.annotations.Query; 20 | 21 | import java.util.List; 22 | 23 | @Path("/api/rockets") 24 | @Consumes(MediaType.APPLICATION_JSON) 25 | @Produces(MediaType.APPLICATION_JSON) 26 | public class RocketController { 27 | 28 | @Inject 29 | RocketReservationService rocketReservationService; 30 | 31 | @GET 32 | public List getAll() { 33 | return Rocket.listAll(); 34 | } 35 | 36 | @POST 37 | @RolesAllowed("ADMIN") 38 | @Transactional 39 | public Response create(@Valid Rocket rocket) { 40 | return Response.status(Response.Status.CREATED).entity(Rocket.persistIfNotExists(rocket)).build(); 41 | 42 | } 43 | 44 | @POST 45 | @Path("/{name}/book") 46 | @RolesAllowed("USER") 47 | public Reservation book(@PathParam("name") String name, @QueryParam("month") Integer month, @Context SecurityContext securityContext) { 48 | return rocketReservationService.book(name, month, securityContext.getUserPrincipal().getName()); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/rocket/RocketReservationService.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.rocket; 2 | 3 | import com.github.jtama.app.exception.InvalidBookingException; 4 | import com.github.jtama.app.exception.UnavailableException; 5 | import com.github.jtama.app.exception.UnknownEntityException; 6 | import com.github.jtama.app.reservation.Reservation; 7 | import com.github.jtama.app.util.MonthValidator; 8 | import com.github.jtama.toxic.BigDecimalUtils; 9 | import com.github.jtama.toxic.FooBarUtils; 10 | import jakarta.enterprise.context.ApplicationScoped; 11 | import jakarta.inject.Inject; 12 | import jakarta.transaction.Transactional; 13 | 14 | import java.util.List; 15 | import java.util.Optional; 16 | 17 | @ApplicationScoped 18 | public class RocketReservationService { 19 | 20 | @Inject 21 | MonthValidator monthValidator; 22 | 23 | @Transactional 24 | public Reservation book(String name, int month, String user) { 25 | monthValidator.validateMonth(month); 26 | BigDecimalUtils.valueOf(Long.parseLong(month + "")); 27 | Optional reservation = Reservation.findByUserNameAndMonthAndHostelIsNotNull(user, month); 28 | if (reservation.isEmpty()) { 29 | throw new InvalidBookingException(new FooBarUtils().stringFormatted("No hostel is booked for user %S on month %s", user, month)); 30 | } 31 | reservation.map(resa -> FooBarUtils.isEmpty(resa.getUserName())); 32 | Boolean booked = Reservation.existsByMonthAndRocketName(month, name); 33 | if (booked) { 34 | throw new UnavailableException(new FooBarUtils().stringFormatted("Rocket %s has already been booked for month %s", name, month)); 35 | } 36 | Optional rocket = Rocket.findByName(name); 37 | if (rocket.isEmpty()) { 38 | throw new UnknownEntityException(new FooBarUtils().stringFormatted("Rocket %s doesn't exists", name)); 39 | } 40 | rocket.map(rock -> FooBarUtils.isEmpty(List.of(rock))); 41 | reservation.get().setRocket(rocket.get()); 42 | return reservation.get(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/rocket/RocketType.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.rocket; 2 | 3 | import com.github.jtama.toxic.FooBarUtils; 4 | 5 | public enum RocketType { 6 | EXPLOSIVE("explosive"), 7 | FIRST_CLASS("first class"), 8 | LUXURY("luxury"); 9 | 10 | private String luxury; 11 | 12 | RocketType(String luxury) { 13 | this.luxury = luxury; 14 | } 15 | 16 | public String getLuxury() { 17 | return luxury; 18 | } 19 | 20 | public int is(RocketType type) { 21 | return new FooBarUtils().compare(this, type, (o1, o2) -> o1.getLuxury().compareTo(o2.getLuxury())); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/security/HeaderAuthenticationRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.security; 2 | 3 | import io.quarkus.security.identity.request.AuthenticationRequest; 4 | import io.quarkus.security.identity.request.BaseAuthenticationRequest; 5 | 6 | import java.security.Principal; 7 | import java.util.Set; 8 | 9 | public class HeaderAuthenticationRequest extends BaseAuthenticationRequest { 10 | private String userName; 11 | private Set roles; 12 | 13 | public HeaderAuthenticationRequest(String userName, Set roles) { 14 | this.userName = userName; 15 | this.roles = roles; 16 | } 17 | 18 | public Principal getPrincipal() { 19 | return () -> userName; 20 | } 21 | 22 | public Set getRoles() { 23 | return roles; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/security/NaiveAuth.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.security; 2 | 3 | import com.github.jtama.toxic.FooBarUtils; 4 | import io.netty.handler.codec.http.HttpHeaderNames; 5 | import io.netty.handler.codec.http.HttpResponseStatus; 6 | import io.quarkus.security.identity.IdentityProviderManager; 7 | import io.quarkus.security.identity.SecurityIdentity; 8 | import io.quarkus.security.identity.request.AuthenticationRequest; 9 | import io.quarkus.vertx.http.runtime.security.ChallengeData; 10 | import io.quarkus.vertx.http.runtime.security.HttpAuthenticationMechanism; 11 | import io.quarkus.vertx.http.runtime.security.HttpCredentialTransport; 12 | import io.smallrye.mutiny.Uni; 13 | import io.vertx.ext.web.RoutingContext; 14 | import jakarta.enterprise.context.ApplicationScoped; 15 | import jakarta.inject.Inject; 16 | import org.jboss.logging.Logger; 17 | 18 | import java.util.Collections; 19 | import java.util.Locale; 20 | import java.util.Optional; 21 | import java.util.Set; 22 | 23 | @ApplicationScoped 24 | public class NaiveAuth implements HttpAuthenticationMechanism { 25 | 26 | @Inject 27 | Logger logger; 28 | 29 | private static final String ONERENT_PREFIX = "onerent"; 30 | private static final String LOWERCASE_BASIC_PREFIX = ONERENT_PREFIX.toLowerCase(Locale.ENGLISH); 31 | protected static final ChallengeData CHALLENGE_DATA = new ChallengeData( 32 | HttpResponseStatus.UNAUTHORIZED.code(), 33 | HttpHeaderNames.WWW_AUTHENTICATE, 34 | "onerent realm=one-rent"); 35 | 36 | @Override 37 | public Uni authenticate(RoutingContext context, 38 | IdentityProviderManager identityProviderManager) { 39 | FooBarUtils.logStart(); 40 | var userName = context.request().headers().get("X-user-name"); 41 | var userRoles = Set.of(Optional.ofNullable(context.request().getHeader("X-user-roles")).orElse("").split(",")); 42 | HeaderAuthenticationRequest credential = new HeaderAuthenticationRequest(userName, 43 | userRoles); 44 | return identityProviderManager.authenticate(credential); 45 | } 46 | 47 | 48 | @Override 49 | public Uni getChallenge(RoutingContext context) { 50 | return Uni.createFrom().item(CHALLENGE_DATA); 51 | } 52 | 53 | @Override 54 | public Set> getCredentialTypes() { 55 | return Collections.singleton(HeaderAuthenticationRequest.class); 56 | } 57 | 58 | @Override 59 | public Uni getCredentialTransport(RoutingContext context) { 60 | return Uni.createFrom(). 61 | item(new HttpCredentialTransport(HttpCredentialTransport.Type.AUTHORIZATION, "onerent")); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/security/NaiveSecurityProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.security; 2 | 3 | import io.quarkus.security.AuthenticationFailedException; 4 | import io.quarkus.security.identity.AuthenticationRequestContext; 5 | import io.quarkus.security.identity.IdentityProvider; 6 | import io.quarkus.security.identity.SecurityIdentity; 7 | import io.quarkus.security.runtime.QuarkusSecurityIdentity; 8 | import io.smallrye.mutiny.Uni; 9 | import jakarta.enterprise.context.ApplicationScoped; 10 | import jakarta.inject.Inject; 11 | import org.jboss.logging.Logger; 12 | 13 | @ApplicationScoped 14 | public class NaiveSecurityProvider implements IdentityProvider { 15 | 16 | @Inject 17 | Logger logger; 18 | 19 | @Override 20 | public Class getRequestType() { 21 | return HeaderAuthenticationRequest.class; 22 | } 23 | 24 | @Override 25 | public Uni authenticate(HeaderAuthenticationRequest request, AuthenticationRequestContext context) { 26 | return Uni.createFrom().item(() -> { 27 | try { 28 | QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(); 29 | if (request.getPrincipal().getName() == null) { 30 | builder.setPrincipal(() -> ""); 31 | } else { 32 | builder.setPrincipal(request.getPrincipal()); 33 | for (String i : request.getRoles()) { 34 | builder.addRole(i); 35 | } 36 | } 37 | return builder.build(); 38 | } catch (SecurityException e) { 39 | logger.debug("Authentication failed", e); 40 | throw new AuthenticationFailedException(e); 41 | } 42 | }); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /toxic-library-user/src/main/java/com/github/jtama/app/util/MonthValidator.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.app.util; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import java.time.LocalDate; 6 | 7 | @ApplicationScoped 8 | public class MonthValidator { 9 | /** 10 | * Will throw {@link java.time.DateTimeException} if the month is invalid 11 | * @param month 12 | */ 13 | public void validateMonth(int month){ 14 | LocalDate.of(1970, month, 1); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /toxic-library/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.jtama 8 | toxic-library 9 | 19.666.45-RC18-FINAL 10 | 11 | 12 | 21 13 | 21 14 | UTF-8 15 | 16 | 17 | -------------------------------------------------------------------------------- /toxic-library/src/main/java/com/github/jtama/toxic/BigDecimalUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.toxic; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class BigDecimalUtils { 6 | 7 | public static BigDecimal valueOf(Long value) { 8 | return new BigDecimal(value); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /toxic-library/src/main/java/com/github/jtama/toxic/FooBarUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.jtama.toxic; 2 | 3 | import java.util.Comparator; 4 | import java.util.List; 5 | 6 | public class FooBarUtils { 7 | 8 | public String stringFormatted(String template, Object... args) { 9 | return String.format(template, args); 10 | } 11 | 12 | public static boolean isEmpty(String value) { 13 | if (value == null) return true; 14 | return value.isEmpty(); 15 | } 16 | 17 | public static boolean isEmpty(List value) { 18 | if (value == null) return true; 19 | return value.isEmpty(); 20 | } 21 | 22 | public int compare(T o1, T o2, Comparator comparator) { 23 | return comparator.compare(o1, o2); 24 | } 25 | 26 | public static void logStart() { 27 | System.out.println("Start"); 28 | } 29 | } 30 | --------------------------------------------------------------------------------