├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── gradle-wrapper-validation.yml │ └── gradle.yml ├── .gitignore ├── .travis.yml ├── HEADER ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle ├── javadocStyleSheet.css ├── maven.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── pmd.xml ├── settings.gradle └── src ├── main └── java │ └── hu │ └── akarnokd │ └── rxjava3 │ └── interop │ ├── BackpressureHelper.java │ ├── CompletableV1ToCompletableV3.java │ ├── CompletableV1ToMaybeV3.java │ ├── CompletableV3ToCompletableV1.java │ ├── DisposableHelper.java │ ├── DisposableV3ToSubscriptionV1.java │ ├── FlowableV3ToObservableV1.java │ ├── MaybeV3ToCompletableV1.java │ ├── MaybeV3ToSingleV1.java │ ├── ObservableV1ToFlowableV3.java │ ├── ObservableV1ToObservableV3.java │ ├── ProcessorV3ToSubjectV1.java │ ├── RxJavaInterop.java │ ├── SchedulerV1ToSchedulerV3.java │ ├── SchedulerV3ToSchedulerV1.java │ ├── SingleV1ToMaybeV3.java │ ├── SingleV1ToSingleV3.java │ ├── SingleV3ToSingleV1.java │ ├── SubjectV1ToProcessorV3.java │ ├── SubjectV1ToSubjectV3.java │ ├── SubjectV3ToSubjectV1.java │ ├── SubscriptionHelper.java │ └── SubscriptionV1ToDisposableV3.java └── test └── java └── hu └── akarnokd └── rxjava3 └── interop ├── BackpressureHelperTest.java ├── DisposableHelperTest.java ├── RxJavaInteropTest.java ├── RxJavaInteropV1SchedulerToV3SchedulerTest.java ├── RxJavaInteropV3SchedulerToV1SchedulerTest.java ├── SubscriptionHelperTest.java ├── TestException.java └── TestHelper.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files we want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.java text 7 | *.groovy text 8 | *.scala text 9 | *.clj text 10 | *.txt text 11 | *.md text 12 | 13 | # Denote all files that are truly binary and should not be modified. 14 | *.png binary 15 | *.jpg binary 16 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 20 9 | ignore: 10 | - dependency-name: com.vanniktech:gradle-maven-publish-plugin 11 | versions: 12 | - 0.14.0 13 | - 0.14.1 14 | - 0.14.2 15 | - 0.15.0 16 | -------------------------------------------------------------------------------- /.github/workflows/gradle-wrapper-validation.yml: -------------------------------------------------------------------------------- 1 | name: "Validate Gradle Wrapper" 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | validation: 6 | name: "Validation" 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: gradle/wrapper-validation-action@v1 11 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: Java CI with Gradle 5 | 6 | on: 7 | push: 8 | branches: [ 3.x ] 9 | pull_request: 10 | branches: [ 3.x ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up JDK 1.8 20 | uses: actions/setup-java@v1 21 | with: 22 | java-version: 1.8 23 | - name: Cache Gradle packages 24 | uses: actions/cache@v2 25 | with: 26 | path: ~/.gradle/caches 27 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 28 | restore-keys: ${{ runner.os }}-gradle 29 | - name: Grant execute permission for gradlew 30 | run: chmod +x gradlew 31 | - name: Build with Gradle 32 | run: ./gradlew build --stacktrace 33 | - name: Upload to Codecov 34 | uses: codecov/codecov-action@v1 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Package Files # 4 | *.jar 5 | *.war 6 | *.ear 7 | /build/ 8 | 9 | .gradle 10 | .idea 11 | .m2 12 | /.nb-gradle/ 13 | /bin/ 14 | .settings/ 15 | .nb-gradle-properties 16 | .classpath 17 | .project 18 | .settings 19 | .metadata 20 | .checkstyle 21 | bin/ 22 | !/gradle/wrapper/gradle-wrapper.jar 23 | .pmd 24 | .ruleset 25 | local.properties 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - openjdk8 5 | 6 | after_success: 7 | - bash <(curl -s https://codecov.io/bash) 8 | 9 | # cache between builds 10 | cache: 11 | directories: 12 | - $HOME/.m2 13 | - $HOME/.gradle 14 | -------------------------------------------------------------------------------- /HEADER: -------------------------------------------------------------------------------- 1 | Copyright 2016-${year} David Karnok 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 | http://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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RxJavaInterop 2 | 3 | 4 | 5 | [![codecov.io](http://codecov.io/github/akarnokd/RxJavaInterop/coverage.svg?branch=3.x)](http://codecov.io/github/akarnokd/RxJavaInterop?branch=3.x) 6 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.akarnokd/rxjava3-interop/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.akarnokd/rxjava3-interop) 7 | 8 | RxJava 1.x: [![RxJava 1.x](https://maven-badges.herokuapp.com/maven-central/io.reactivex/rxjava/badge.svg)](https://maven-badges.herokuapp.com/maven-central/maven-central/io.reactivex/rxjava) 9 | RxJava 3.x: [![RxJava 3.x](https://maven-badges.herokuapp.com/maven-central/io.reactivex.rxjava3/rxjava/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.reactivex.rxjava3/rxjava) 10 | 11 | Library to convert between RxJava 1.x and 3.x reactive types. 12 | 13 | ### Interop between 2.x and 3.x 14 | 15 | Check out the [https://github.com/akarnokd/RxJavaBridge](https://github.com/akarnokd/RxJavaBridge#RxJavaBridge) project. 16 | 17 | # Releases 18 | 19 | 20 | **gradle** 21 | 22 | ``` 23 | dependencies { 24 | implementation "com.github.akarnokd:rxjava3-interop:3.0.2" 25 | } 26 | ``` 27 | 28 | 29 | Maven search: 30 | 31 | [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.github.akarnokd%22) 32 | 33 | # Usage 34 | 35 | ### Convert between the reactive base types 36 | 37 | ```java 38 | import hu.akarnokd.rxjava3.interop.RxJavaInterop; 39 | 40 | // convert from 1.x to 3.x 41 | 42 | io.reactivex.rxjava3.core.Flowable f3 = RxJavaInterop.toV3Flowable(rx.Observable); 43 | 44 | io.reactivex.rxjava3.core.Observable o3 = RxJavaInterop.toV3Observable(rx.Observable); 45 | 46 | io.reactivex.rxjava3.core.Single s3 = RxJavaInterop.toV3Single(rx.Single); 47 | 48 | io.reactivex.rxjava3.core.Completable c3 = RxJavaInterop.toV3Completable(rx.Completable); 49 | 50 | io.reactivex.rxjava3.core.Maybe m3s = RxJavaInterop.toV3Maybe(rx.Single); 51 | 52 | io.reactivex.rxjava3.core.Maybe m3c = RxJavaInterop.toV3Maybe(rx.Completable); 53 | 54 | // convert from 3.x to 1.x 55 | 56 | rx.Observable o1 = RxJavaInterop.toV1Observable(Publisher); 57 | 58 | rx.Observable q1 = RxJavaInterop.toV1Observable(ObservableSource, BackpressureStrategy); 59 | 60 | rx.Single s1 = RxJavaInterop.toV1Single(SingleSource); 61 | 62 | rx.Completable c1 = RxJavaInterop.toV1Completable(CompletableSource); 63 | 64 | rx.Single s1m = RxJavaInterop.toV1Single(MaybeSource); 65 | 66 | rx.Completable c1m = RxJavaInterop.toV1Completable(MaybeSource); 67 | ``` 68 | 69 | ### Convert between Subjects and Processors. 70 | 71 | Note that 3.x `Subject`s and `FlowableProcessor`s support only the same input and output types. 72 | 73 | ```java 74 | // convert from 1.x to 3.x 75 | 76 | io.reactivex.rxjava3.subjects.Subject sj3 = RxJavaInterop.toV3Subject(rx.subjects.Subject); 77 | 78 | io.reactivex.rxjava3.processors.FlowableProcessor fp3 = RxJavaInterop.toV3Processor(rx.subjects.Subject); 79 | 80 | // convert from 3.x to 1.x 81 | 82 | rx.subjects.Subject sj1 = RxJavaInterop.toV1Subject(io.reactivex.rxjava3.subjects.Subject); 83 | 84 | rx.subjects.Subject sj1b = RxJavaInterop.toV1Subject(io.reactivex.rxjava3.processors.FlowableProcessor); 85 | ``` 86 | 87 | ### Convert between 1.x `X.Transformer`s and 3.x `XTransformer`s. 88 | 89 | ```java 90 | // convert from 1.x to 3.x 91 | 92 | io.reactivex.rxjava3.core.FlowableTransformer ft3 = RxJavaInterop.toV3Transformer( 93 | rx.Observable.Transformer); 94 | 95 | io.reactivex.rxjava3.core.ObservableTransformer ot3 = RxJavaInterop.toV3Transformer( 96 | rx.Observable.Transformer, 97 | io.reactivex.rxjava3.core.BackpressureStrategy); 98 | 99 | io.reactivex.rxjava3.core.SingleTransformer st3 = RxJavaInterop.toV3Transformer( 100 | rx.Single.Transformer); 101 | 102 | io.reactivex.rxjava3.core.CompletableTransformer ct3 = RxJavaInterop.toV3Transformer( 103 | rx.Completable.Transformer); 104 | 105 | // convert from 3.x to 1.x 106 | 107 | rx.Observable.Transformer ft1 = RxJavaInterop.toV1Transformer( 108 | io.reactivex.rxjava3.core.FlowableTransformer); 109 | 110 | rx.Observable.Transformer ot1 = RxJavaInterop.toV1Transformer( 111 | io.reactivex.rxjava3.core.ObservableTransformer, 112 | io.reactivex.rxjava3.core.BackpressureStrategy); 113 | 114 | rx.Single.Transformer st1 = RxJavaInterop.toV1Transformer( 115 | io.reactivex.rxjava3.core.SingleTransformer); 116 | 117 | rx.Completable.Transformer ct1 = RxJavaInterop.toV1Transformer( 118 | io.reactivex.rxjava3.core.CompletableTransformer); 119 | ``` 120 | 121 | ### Convert between 1.x `Flowable.Operator` and 3.x `FlowableOperator` 122 | 123 | ```java 124 | // convert from 1.x to 3.x 125 | 126 | io.reactivex.rxjava3.core.FlowableOperator fo3 = RxJavaInterop.toV3Operator(rx.Observable.Operator); 127 | 128 | // convert from 3.x to 1.x 129 | 130 | rx.Observable.Operator fo1 = RxJavaInterop.toV1Operator(io.reactivex.rxjava3.core.FlowableOperator); 131 | ``` 132 | 133 | ### Convert between 1.x `Subscription` and 3.x `Disposable` 134 | 135 | ```java 136 | // convert from 1.x to 3.x 137 | 138 | io.reactivex.rxjava3.disposables.Disposable d3 = RxJavaInterop.toV3Disposable(rx.Subscription); 139 | 140 | // convert from 3.x to 1.x 141 | 142 | rx.Subscription s1 = RxJavaInterop.toV1Subscription(io.reactivex.rxjava3.disposables.Disposable); 143 | ``` 144 | 145 | 146 | ### Convert between 1.x `Scheduler`s and 3.x `Scheduler`s 147 | 148 | ```java 149 | // convert from 1.x to 3.x 150 | 151 | io.reactivex.rxjava3.core.Scheduler s3 = RxJavaInterop.toV3Scheduler(rx.Scheduler); 152 | 153 | // convert from 3.x to 1.x 154 | 155 | rx.Scheduler s1 = RxJavaInterop.toV1Scheduler(io.reactivex.rxjava3.core.Scheduler); 156 | ``` 157 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | maven { 5 | url "https://plugins.gradle.org/m2/" 6 | } 7 | } 8 | 9 | dependencies { 10 | classpath "gradle.plugin.com.hierynomus.gradle.plugins:license-gradle-plugin:0.16.1" 11 | classpath "me.champeau.gradle:jmh-gradle-plugin:0.5.3" 12 | classpath 'ru.vyarus:gradle-animalsniffer-plugin:1.6.0' 13 | classpath "biz.aQute.bnd:biz.aQute.bnd.gradle:6.4.0" 14 | classpath 'com.vanniktech:gradle-maven-publish-plugin:0.18.0' 15 | } 16 | } 17 | 18 | apply plugin: 'java-library' 19 | apply plugin: 'eclipse' 20 | apply plugin: "me.champeau.gradle.jmh" 21 | apply plugin: 'pmd' 22 | apply plugin: 'jacoco' 23 | apply plugin: 'ru.vyarus.animalsniffer' 24 | apply plugin: "com.github.hierynomus.license" 25 | 26 | sourceCompatibility = JavaVersion.VERSION_1_8 27 | targetCompatibility = JavaVersion.VERSION_1_8 28 | 29 | group = "com.github.akarnokd" 30 | ext.githubProjectName = 'rxjava3-interop' 31 | 32 | [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' 33 | 34 | if (!hasProperty('mainClass')) { 35 | ext.mainClass = '' 36 | } 37 | 38 | repositories { 39 | mavenCentral() 40 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } 41 | maven { url 'https://oss.sonatype.org/content/groups/public' } 42 | maven { url 'https://repo.spring.io/libs-snapshot' } 43 | } 44 | 45 | dependencies { 46 | signature 'org.codehaus.mojo.signature:java18:1.0@signature' 47 | 48 | api "org.reactivestreams:reactive-streams:1.0.4" 49 | api "io.reactivex:rxjava:1.3.8" 50 | api "io.reactivex.rxjava3:rxjava:3.1.6" 51 | 52 | testImplementation group: 'junit', name: 'junit', version: '4.13.2' 53 | testImplementation 'org.mockito:mockito-core:4.9.0' 54 | } 55 | 56 | apply plugin: 'biz.aQute.bnd.builder' 57 | 58 | jar { 59 | bnd ('Bundle-Name': 'rxjava3-interop', 60 | 'Bundle-Vendor': 'akarnokd', 61 | 'Bundle-Description': 'Library to convert between RxJava 1.x and 3.x reactive types, schedulers and resource handles.', 62 | 'Import-Package': '!org.junit,!junit.framework,!org.mockito.*,*', 63 | 'Bundle-DocURL': 'https://github.com/akarnokd/RxJavaInterop', 64 | 'Export-Package': 'hu.akarnokd.rxjava3.interop.*' 65 | ) 66 | } 67 | 68 | apply plugin: "com.vanniktech.maven.publish" 69 | 70 | jmh { 71 | jmhVersion = '1.21' 72 | humanOutputFile = null 73 | if (project.hasProperty('jmh')) { 74 | include = ".*" + project.jmh + ".*" 75 | } else { 76 | include = ".*" 77 | } 78 | } 79 | 80 | plugins.withType(EclipsePlugin) { 81 | project.eclipse.classpath.plusConfigurations += [ configurations.jmh ] 82 | } 83 | 84 | javadoc { 85 | failOnError = false 86 | 87 | options.links( 88 | "http://docs.oracle.com/javase/7/docs/api/", 89 | "http://reactivex.io/RxJava/1.x/javadoc", 90 | "http://reactivex.io/RxJava/3.x/javadoc" 91 | ) 92 | } 93 | 94 | test { 95 | maxHeapSize = "2g" 96 | testLogging { 97 | events "started", "failed" // "skipped", "passed" 98 | // showStandardStreams = true 99 | } 100 | } 101 | 102 | license { 103 | header rootProject.file('HEADER') 104 | ext.year = Calendar.getInstance().get(Calendar.YEAR) 105 | skipExistingHeaders true 106 | ignoreFailures true 107 | excludes(["**/*.md", "**/*.txt"]) 108 | } 109 | 110 | jacoco { 111 | toolVersion = '0.8.5' // See http://www.eclemma.org/jacoco/. 112 | } 113 | 114 | jacocoTestReport { 115 | reports { 116 | xml.enabled = true 117 | html.enabled = true 118 | } 119 | } 120 | 121 | build.dependsOn jacocoTestReport 122 | 123 | check.dependsOn jacocoTestReport 124 | 125 | pmd { 126 | toolVersion = '6.21.0' 127 | ignoreFailures = true 128 | sourceSets = [sourceSets.main] 129 | ruleSets = [] 130 | ruleSetFiles = files('pmd.xml') 131 | } 132 | 133 | pmdMain { 134 | reports { 135 | html.enabled = true 136 | xml.enabled = true 137 | } 138 | } 139 | 140 | task pmdPrint(dependsOn: 'pmdMain') doLast { 141 | File file = rootProject.file('build/reports/pmd/main.xml') 142 | if (file.exists()) { 143 | 144 | println("Listing first 100 PMD violations") 145 | 146 | file.eachLine { line, count -> 147 | if (count <= 100) { 148 | println(line) 149 | } 150 | } 151 | 152 | } else { 153 | println("PMD file not found.") 154 | } 155 | } 156 | 157 | build.dependsOn pmdPrint 158 | check.dependsOn pmdPrint 159 | 160 | animalsniffer { 161 | annotation = 'rx.internal.util.SuppressAnimalSniffer' 162 | } 163 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | GROUP=com.github.akarnokd 2 | VERSION_NAME=3.1.1 3 | version=3.1.1 4 | 5 | POM_ARTIFACT_ID=rxjava3-interop 6 | POM_NAME=Interop library between RxJava 1.x and 3.x 7 | POM_PACKAGING=jar 8 | 9 | POM_DESCRIPTION=Library to convert between RxJava 1.x and 3.x reactive types, schedulers and resource handles. 10 | POM_INCEPTION_YEAR=2019 11 | 12 | POM_URL=https://github.com/akarnokd/RxJavaInterop 13 | POM_SCM_URL=https://github.com/akarnokd/RxJavaInterop 14 | POM_SCM_CONNECTION=scm:git:git://github.com/akarnokd/RxJavaInterop.git 15 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/akarnokd/RxJavaInterop.git 16 | 17 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 18 | POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt 19 | POM_LICENCE_DIST=repo 20 | 21 | POM_DEVELOPER_ID=akarnokd 22 | POM_DEVELOPER_NAME=David Karnok 23 | -------------------------------------------------------------------------------- /gradle/javadocStyleSheet.css: -------------------------------------------------------------------------------- 1 | # originally from http://sensemaya.org/files/stylesheet.css and then modified 2 | # http://sensemaya.org/maya/2009/07/10/making-javadoc-more-legible 3 | 4 | /* Javadoc style sheet */ 5 | 6 | /* Define colors, fonts and other style attributes here to override the defaults */ 7 | 8 | /* Page background color */ 9 | body { background-color: #FFFFFF; color:#333; font-size: 100%; } 10 | 11 | body { font-size: 0.875em; line-height: 1.286em; font-family: "Helvetica", "Arial", sans-serif; } 12 | 13 | code { color: #777; line-height: 1.286em; font-family: "Consolas", "Lucida Console", "Droid Sans Mono", "Andale Mono", "Monaco", "Lucida Sans Typewriter"; } 14 | 15 | a { text-decoration: none; color: #16569A; /* also try #2E85ED, #0033FF, #6C93C6, #1D7BBE, #1D8DD2 */ } 16 | a:hover { text-decoration: underline; } 17 | 18 | 19 | table[border="1"] { border: 1px solid #ddd; } 20 | table[border="1"] td, table[border="1"] th { border: 1px solid #ddd; } 21 | table[cellpadding="3"] td { padding: 0.5em; } 22 | 23 | font[size="-1"] { font-size: 0.85em; line-height: 1.5em; } 24 | font[size="-2"] { font-size: 0.8em; } 25 | font[size="+2"] { font-size: 1.4em; line-height: 1.3em; padding: 0.4em 0; } 26 | 27 | /* Headings */ 28 | h1 { font-size: 1.5em; line-height: 1.286em;} 29 | h2.title { color: #c81f08; } 30 | 31 | /* Table colors */ 32 | .TableHeadingColor { background: #ccc; color:#444; } /* Dark mauve */ 33 | .TableSubHeadingColor { background: #ddd; color:#444; } /* Light mauve */ 34 | .TableRowColor { background: #FFFFFF; color:#666; font-size: 0.95em; } /* White */ 35 | .TableRowColor code { color:#000; } /* White */ 36 | 37 | /* Font used in left-hand frame lists */ 38 | .FrameTitleFont { font-size: 100%; } 39 | .FrameHeadingFont { font-size: 90%; } 40 | .FrameItemFont { font-size: 0.9em; line-height: 1.3em; 41 | } 42 | /* Java Interfaces */ 43 | .FrameItemFont a i { 44 | font-style: normal; color: #16569A; 45 | } 46 | .FrameItemFont a:hover i { 47 | text-decoration: underline; 48 | } 49 | 50 | 51 | /* Navigation bar fonts and colors */ 52 | .NavBarCell1 { background-color:#E0E6DF; } /* Light mauve */ 53 | .NavBarCell1Rev { background-color:#16569A; color:#FFFFFF} /* Dark Blue */ 54 | .NavBarFont1 { } 55 | .NavBarFont1Rev { color:#FFFFFF; } 56 | 57 | .NavBarCell2 { background-color:#FFFFFF; color:#000000} 58 | .NavBarCell3 { background-color:#FFFFFF; color:#000000} 59 | 60 | -------------------------------------------------------------------------------- /gradle/maven.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven' // Java plugin has to have been already applied for the conf2scope mappings to work 2 | apply plugin: 'signing' 3 | 4 | project.status = 'release' 5 | 6 | signing { 7 | required { gradle.taskGraph.hasTask(uploadMavenCentral) } 8 | sign configurations.archives 9 | } 10 | 11 | /** 12 | * Publishing to Maven Central example provided from http://jedicoder.blogspot.com/2011/11/automated-gradle-project-deployment-to.html 13 | * artifactory will execute uploadArchives to force generation of ivy.xml, and we don't want that to trigger an upload to maven 14 | * central, so using custom upload task. 15 | */ 16 | task uploadMavenCentral(type:Upload, dependsOn: signArchives) { 17 | configuration = configurations.archives 18 | onlyIf { ['release', 'snapshot'].contains(project.status) } 19 | repositories.mavenDeployer { 20 | beforeDeployment { signing.signPom(it) } 21 | 22 | // To test deployment locally, use the following instead of oss.sonatype.org 23 | //repository(url: "file://localhost/${rootProject.rootDir}/repo") 24 | 25 | def sonatypeUsername = rootProject.hasProperty('sonatypeUsername')?rootProject.sonatypeUsername:'' 26 | def sonatypePassword = rootProject.hasProperty('sonatypePassword')?rootProject.sonatypePassword:'' 27 | 28 | repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2') { 29 | authentication(userName: sonatypeUsername, password: sonatypePassword) 30 | } 31 | 32 | snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/') { 33 | authentication(userName: sonatypeUsername, password: sonatypePassword) 34 | } 35 | 36 | // Prevent datastamp from being appending to artifacts during deployment 37 | uniqueVersion = false 38 | 39 | // Closure to configure all the POM with extra info, common to all projects 40 | pom.project { 41 | name "${project.name}" 42 | description "${project.name} developed by David Karnok" 43 | developers { 44 | developer { 45 | id 'akarnokd' 46 | name 'David Karnok' 47 | email 'akarnokd@gmail.com' 48 | } 49 | } 50 | licenses { 51 | license { 52 | name 'The Apache Software License, Version 2.0' 53 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 54 | distribution 'repo' 55 | } 56 | } 57 | url "https://github.com/akarnokd/${rootProject.githubProjectName}" 58 | scm { 59 | connection "scm:git:git@github.com:akarnokd/${rootProject.githubProjectName}.git" 60 | url "scm:git:git@github.com:akarnokd/${rootProject.githubProjectName}.git" 61 | developerConnection "scm:git:git@github.com:akarnokd/${rootProject.githubProjectName}.git" 62 | } 63 | issueManagement { 64 | system 'github' 65 | url "https://github.com/akarnokd/${rootProject.githubProjectName}/issues" 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akarnokd/RxJavaInterop/be7a2799cde369ec1d5afec3ca8c3f11397758b7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=`expr $i + 1` 158 | done 159 | case $i in 160 | 0) set -- ;; 161 | 1) set -- "$args0" ;; 162 | 2) set -- "$args0" "$args1" ;; 163 | 3) set -- "$args0" "$args1" "$args2" ;; 164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=`save "$@"` 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | exec "$JAVACMD" "$@" 184 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /pmd.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | RxJava PMD ruleset 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'rxjava3-interop' 2 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/BackpressureHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import java.util.concurrent.atomic.AtomicLong; 20 | 21 | import io.reactivex.rxjava3.annotations.NonNull; 22 | import io.reactivex.rxjava3.plugins.RxJavaPlugins; 23 | 24 | /** 25 | * Utility class to help with backpressure-related operations such as request aggregation. 26 | */ 27 | final class BackpressureHelper { 28 | /** Utility class. */ 29 | private BackpressureHelper() { 30 | throw new IllegalStateException("No instances!"); 31 | } 32 | 33 | /** 34 | * Adds two long values and caps the sum at {@link Long#MAX_VALUE}. 35 | * @param a the first value 36 | * @param b the second value 37 | * @return the sum capped at {@link Long#MAX_VALUE} 38 | */ 39 | public static long addCap(long a, long b) { 40 | long u = a + b; 41 | if (u < 0L) { 42 | return Long.MAX_VALUE; 43 | } 44 | return u; 45 | } 46 | 47 | /** 48 | * Multiplies two long values and caps the product at {@link Long#MAX_VALUE}. 49 | * @param a the first value 50 | * @param b the second value 51 | * @return the product capped at {@link Long#MAX_VALUE} 52 | */ 53 | public static long multiplyCap(long a, long b) { 54 | long u = a * b; 55 | if (((a | b) >>> 31) != 0) { 56 | if (u / a != b) { 57 | return Long.MAX_VALUE; 58 | } 59 | } 60 | return u; 61 | } 62 | 63 | /** 64 | * Atomically adds the positive value n to the requested value in the {@link AtomicLong} and 65 | * caps the result at {@link Long#MAX_VALUE} and returns the previous value. 66 | * @param requested the {@code AtomicLong} holding the current requested value 67 | * @param n the value to add, must be positive (not verified) 68 | * @return the original value before the add 69 | */ 70 | public static long add(@NonNull AtomicLong requested, long n) { 71 | for (;;) { 72 | long r = requested.get(); 73 | if (r == Long.MAX_VALUE) { 74 | return Long.MAX_VALUE; 75 | } 76 | long u = addCap(r, n); 77 | if (requested.compareAndSet(r, u)) { 78 | return r; 79 | } 80 | } 81 | } 82 | 83 | /** 84 | * Atomically adds the positive value n to the requested value in the {@link AtomicLong} and 85 | * caps the result at {@link Long#MAX_VALUE} and returns the previous value and 86 | * considers {@link Long#MIN_VALUE} as a cancel indication (no addition then). 87 | * @param requested the {@code AtomicLong} holding the current requested value 88 | * @param n the value to add, must be positive (not verified) 89 | * @return the original value before the add 90 | */ 91 | public static long addCancel(@NonNull AtomicLong requested, long n) { 92 | for (;;) { 93 | long r = requested.get(); 94 | if (r == Long.MIN_VALUE) { 95 | return Long.MIN_VALUE; 96 | } 97 | if (r == Long.MAX_VALUE) { 98 | return Long.MAX_VALUE; 99 | } 100 | long u = addCap(r, n); 101 | if (requested.compareAndSet(r, u)) { 102 | return r; 103 | } 104 | } 105 | } 106 | 107 | /** 108 | * Atomically subtract the given number (positive, not validated) from the target field unless it contains {@link Long#MAX_VALUE}. 109 | * @param requested the target field holding the current requested amount 110 | * @param n the produced element count, positive (not validated) 111 | * @return the new amount 112 | */ 113 | public static long produced(@NonNull AtomicLong requested, long n) { 114 | for (;;) { 115 | long current = requested.get(); 116 | if (current == Long.MAX_VALUE) { 117 | return Long.MAX_VALUE; 118 | } 119 | long update = current - n; 120 | if (update < 0L) { 121 | RxJavaPlugins.onError(new IllegalStateException("More produced than requested: " + update)); 122 | update = 0L; 123 | } 124 | if (requested.compareAndSet(current, update)) { 125 | return update; 126 | } 127 | } 128 | } 129 | 130 | /** 131 | * Atomically subtract the given number (positive, not validated) from the target field if 132 | * it doesn't contain {@link Long#MIN_VALUE} (indicating some cancelled state) or {@link Long#MAX_VALUE} (unbounded mode). 133 | * @param requested the target field holding the current requested amount 134 | * @param n the produced element count, positive (not validated) 135 | * @return the new amount 136 | */ 137 | public static long producedCancel(@NonNull AtomicLong requested, long n) { 138 | for (;;) { 139 | long current = requested.get(); 140 | if (current == Long.MIN_VALUE) { 141 | return Long.MIN_VALUE; 142 | } 143 | if (current == Long.MAX_VALUE) { 144 | return Long.MAX_VALUE; 145 | } 146 | long update = current - n; 147 | if (update < 0L) { 148 | RxJavaPlugins.onError(new IllegalStateException("More produced than requested: " + update)); 149 | update = 0L; 150 | } 151 | if (requested.compareAndSet(current, update)) { 152 | return update; 153 | } 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/CompletableV1ToCompletableV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Convert a V1 Completable into a V3 Completable, composing cancellation. 21 | */ 22 | final class CompletableV1ToCompletableV3 extends io.reactivex.rxjava3.core.Completable { 23 | 24 | final rx.Completable source; 25 | 26 | CompletableV1ToCompletableV3(rx.Completable source) { 27 | this.source = source; 28 | } 29 | 30 | @Override 31 | protected void subscribeActual(io.reactivex.rxjava3.core.CompletableObserver observer) { 32 | source.subscribe(new SourceCompletableSubscriber(observer)); 33 | } 34 | 35 | static final class SourceCompletableSubscriber 36 | implements rx.CompletableSubscriber, io.reactivex.rxjava3.disposables.Disposable { 37 | 38 | final io.reactivex.rxjava3.core.CompletableObserver observer; 39 | 40 | rx.Subscription s; 41 | 42 | SourceCompletableSubscriber(io.reactivex.rxjava3.core.CompletableObserver observer) { 43 | this.observer = observer; 44 | } 45 | 46 | @Override 47 | public void onSubscribe(rx.Subscription d) { 48 | this.s = d; 49 | observer.onSubscribe(this); 50 | } 51 | 52 | @Override 53 | public void onCompleted() { 54 | observer.onComplete(); 55 | } 56 | 57 | @Override 58 | public void onError(Throwable error) { 59 | observer.onError(error); 60 | } 61 | 62 | @Override 63 | public void dispose() { 64 | s.unsubscribe(); 65 | } 66 | 67 | @Override 68 | public boolean isDisposed() { 69 | return s.isUnsubscribed(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/CompletableV1ToMaybeV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Convert a V1 Completable into a V+ Completable, composing cancellation. 21 | */ 22 | final class CompletableV1ToMaybeV3 extends io.reactivex.rxjava3.core.Maybe { 23 | 24 | final rx.Completable source; 25 | 26 | CompletableV1ToMaybeV3(rx.Completable source) { 27 | this.source = source; 28 | } 29 | 30 | @Override 31 | protected void subscribeActual(io.reactivex.rxjava3.core.MaybeObserver observer) { 32 | source.subscribe(new SourceCompletableSubscriber(observer)); 33 | } 34 | 35 | static final class SourceCompletableSubscriber 36 | implements rx.CompletableSubscriber, io.reactivex.rxjava3.disposables.Disposable { 37 | 38 | final io.reactivex.rxjava3.core.MaybeObserver observer; 39 | 40 | rx.Subscription s; 41 | 42 | SourceCompletableSubscriber(io.reactivex.rxjava3.core.MaybeObserver observer) { 43 | this.observer = observer; 44 | } 45 | 46 | @Override 47 | public void onSubscribe(rx.Subscription d) { 48 | this.s = d; 49 | observer.onSubscribe(this); 50 | } 51 | 52 | @Override 53 | public void onCompleted() { 54 | observer.onComplete(); 55 | } 56 | 57 | @Override 58 | public void onError(Throwable error) { 59 | observer.onError(error); 60 | } 61 | 62 | @Override 63 | public void dispose() { 64 | s.unsubscribe(); 65 | } 66 | 67 | @Override 68 | public boolean isDisposed() { 69 | return s.isUnsubscribed(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/CompletableV3ToCompletableV1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Convert a V3 Completable into a V1 Completable, composing cancellation. 21 | */ 22 | final class CompletableV3ToCompletableV1 implements rx.Completable.OnSubscribe { 23 | 24 | final io.reactivex.rxjava3.core.CompletableSource source; 25 | 26 | CompletableV3ToCompletableV1(io.reactivex.rxjava3.core.CompletableSource source) { 27 | this.source = source; 28 | } 29 | 30 | @Override 31 | public void call(rx.CompletableSubscriber observer) { 32 | source.subscribe(new SourceCompletableSubscriber(observer)); 33 | } 34 | 35 | static final class SourceCompletableSubscriber 36 | implements io.reactivex.rxjava3.core.CompletableObserver, rx.Subscription { 37 | 38 | final rx.CompletableSubscriber observer; 39 | 40 | io.reactivex.rxjava3.disposables.Disposable d; 41 | 42 | SourceCompletableSubscriber(rx.CompletableSubscriber observer) { 43 | this.observer = observer; 44 | } 45 | 46 | @Override 47 | public void onSubscribe(io.reactivex.rxjava3.disposables.Disposable d) { 48 | this.d = d; 49 | observer.onSubscribe(this); 50 | } 51 | 52 | @Override 53 | public void onComplete() { 54 | observer.onCompleted(); 55 | } 56 | 57 | @Override 58 | public void onError(Throwable error) { 59 | observer.onError(error); 60 | } 61 | 62 | @Override 63 | public void unsubscribe() { 64 | d.dispose(); 65 | } 66 | 67 | @Override 68 | public boolean isUnsubscribed() { 69 | return d.isDisposed(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/DisposableHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import java.util.Objects; 20 | import java.util.concurrent.atomic.AtomicReference; 21 | 22 | import io.reactivex.rxjava3.disposables.Disposable; 23 | import io.reactivex.rxjava3.exceptions.ProtocolViolationException; 24 | import io.reactivex.rxjava3.plugins.RxJavaPlugins; 25 | 26 | /** 27 | * Utility methods for working with Disposables atomically. 28 | */ 29 | enum DisposableHelper implements Disposable { 30 | /** 31 | * The singleton instance representing a terminal, disposed state, don't leak it. 32 | */ 33 | DISPOSED 34 | ; 35 | 36 | /** 37 | * Checks if the given Disposable is the common {@link #DISPOSED} enum value. 38 | * @param d the disposable to check 39 | * @return true if d is {@link #DISPOSED} 40 | */ 41 | public static boolean isDisposed(Disposable d) { 42 | return d == DISPOSED; 43 | } 44 | 45 | /** 46 | * Atomically sets the field to the given non-null Disposable and returns true 47 | * or returns false if the field is non-null. 48 | * If the target field contains the common DISPOSED instance, the supplied disposable 49 | * is disposed. If the field contains other non-null Disposable, an IllegalStateException 50 | * is signalled to the RxJavaPlugins.onError hook. 51 | * 52 | * @param field the target field 53 | * @param d the disposable to set, not null 54 | * @return true if the operation succeeded, false 55 | */ 56 | public static boolean setOnce(AtomicReference field, Disposable d) { 57 | Objects.requireNonNull(d, "d is null"); 58 | if (!field.compareAndSet(null, d)) { 59 | d.dispose(); 60 | if (field.get() != DISPOSED) { 61 | reportDisposableSet(); 62 | } 63 | return false; 64 | } 65 | return true; 66 | } 67 | 68 | /** 69 | * Atomically disposes the Disposable in the field if not already disposed. 70 | * @param field the target field 71 | * @return true if the current thread managed to dispose the Disposable 72 | */ 73 | public static boolean dispose(AtomicReference field) { 74 | Disposable current = field.get(); 75 | Disposable d = DISPOSED; 76 | if (current != d) { 77 | current = field.getAndSet(d); 78 | if (current != d) { 79 | if (current != null) { 80 | current.dispose(); 81 | } 82 | return true; 83 | } 84 | } 85 | return false; 86 | } 87 | 88 | /** 89 | * Verifies that current is null, next is not null, otherwise signals errors 90 | * to the RxJavaPlugins and returns false. 91 | * @param current the current Disposable, expected to be null 92 | * @param next the next Disposable, expected to be non-null 93 | * @return true if the validation succeeded 94 | */ 95 | public static boolean validate(Disposable current, Disposable next) { 96 | if (next == null) { 97 | RxJavaPlugins.onError(new NullPointerException("next is null")); 98 | return false; 99 | } 100 | if (current != null) { 101 | next.dispose(); 102 | reportDisposableSet(); 103 | return false; 104 | } 105 | return true; 106 | } 107 | 108 | /** 109 | * Reports that the disposable is already set to the RxJavaPlugins error handler. 110 | */ 111 | public static void reportDisposableSet() { 112 | RxJavaPlugins.onError(new ProtocolViolationException("Disposable already set!")); 113 | } 114 | 115 | /** 116 | * Atomically tries to set the given Disposable on the field if it is null or disposes it if 117 | * the field contains {@link #DISPOSED}. 118 | * @param field the target field 119 | * @param d the disposable to set 120 | * @return true if successful, false otherwise 121 | */ 122 | public static boolean trySet(AtomicReference field, Disposable d) { 123 | if (!field.compareAndSet(null, d)) { 124 | if (field.get() == DISPOSED) { 125 | d.dispose(); 126 | } 127 | return false; 128 | } 129 | return true; 130 | } 131 | 132 | @Override 133 | public void dispose() { 134 | // deliberately no-op 135 | } 136 | 137 | @Override 138 | public boolean isDisposed() { 139 | return true; 140 | } 141 | } -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/DisposableV3ToSubscriptionV1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import io.reactivex.rxjava3.disposables.Disposable; 20 | import rx.Subscription; 21 | 22 | /** 23 | * Wraps a v3 Disposable and exposes it as a v1 Subscription. 24 | * @since 0.11.0 25 | * @author Artem Zinnatulin 26 | */ 27 | final class DisposableV3ToSubscriptionV1 implements Subscription { 28 | 29 | private final Disposable disposable; 30 | 31 | DisposableV3ToSubscriptionV1(Disposable disposable) { 32 | this.disposable = disposable; 33 | } 34 | 35 | @Override 36 | public void unsubscribe() { 37 | disposable.dispose(); 38 | } 39 | 40 | @Override 41 | public boolean isUnsubscribed() { 42 | return disposable.isDisposed(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/FlowableV3ToObservableV1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package hu.akarnokd.rxjava3.interop; 17 | 18 | import java.util.concurrent.atomic.*; 19 | 20 | /** 21 | * Convert a V3 Flowable into a V1 Observable, composing backpressure and cancellation. 22 | * 23 | * @param the value type 24 | */ 25 | final class FlowableV3ToObservableV1 implements rx.Observable.OnSubscribe { 26 | 27 | final org.reactivestreams.Publisher source; 28 | 29 | FlowableV3ToObservableV1(org.reactivestreams.Publisher source) { 30 | this.source = source; 31 | } 32 | 33 | @Override 34 | public void call(rx.Subscriber t) { 35 | SourceSubscriber parent = new SourceSubscriber<>(t); 36 | 37 | t.add(parent); 38 | t.setProducer(parent); 39 | 40 | source.subscribe(parent); 41 | } 42 | 43 | static final class SourceSubscriber 44 | extends AtomicReference 45 | implements io.reactivex.rxjava3.core.FlowableSubscriber, rx.Subscription, rx.Producer { 46 | 47 | private static final long serialVersionUID = -6567012932544037069L; 48 | 49 | final rx.Subscriber actual; 50 | 51 | final AtomicLong requested; 52 | 53 | SourceSubscriber(rx.Subscriber actual) { 54 | this.actual = actual; 55 | this.requested = new AtomicLong(); 56 | } 57 | 58 | @Override 59 | public void request(long n) { 60 | if (n != 0L) { 61 | SubscriptionHelper.deferredRequest(this, requested, n); 62 | } 63 | } 64 | 65 | @Override 66 | public void unsubscribe() { 67 | SubscriptionHelper.cancel(this); 68 | } 69 | 70 | @Override 71 | public boolean isUnsubscribed() { 72 | return SubscriptionHelper.CANCELLED == get(); 73 | } 74 | 75 | @Override 76 | public void onSubscribe(org.reactivestreams.Subscription s) { 77 | SubscriptionHelper.deferredSetOnce(this, requested, s); 78 | } 79 | 80 | @Override 81 | public void onNext(T t) { 82 | actual.onNext(t); 83 | } 84 | 85 | @Override 86 | public void onError(Throwable t) { 87 | actual.onError(t); 88 | } 89 | 90 | @Override 91 | public void onComplete() { 92 | actual.onCompleted(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/MaybeV3ToCompletableV1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import java.util.concurrent.atomic.AtomicReference; 20 | 21 | /** 22 | * Converts a V3 Maybe into a V1 Complete where an onSuccess value triggers onCompleted. 23 | * 24 | * @param the value type 25 | */ 26 | final class MaybeV3ToCompletableV1 implements rx.Completable.OnSubscribe { 27 | 28 | final io.reactivex.rxjava3.core.MaybeSource source; 29 | 30 | MaybeV3ToCompletableV1(io.reactivex.rxjava3.core.MaybeSource source) { 31 | this.source = source; 32 | } 33 | 34 | @Override 35 | public void call(rx.CompletableSubscriber t) { 36 | MaybeV3Observer parent = new MaybeV3Observer<>(t); 37 | t.onSubscribe(parent); 38 | source.subscribe(parent); 39 | } 40 | 41 | static final class MaybeV3Observer 42 | extends AtomicReference 43 | implements io.reactivex.rxjava3.core.MaybeObserver, rx.Subscription { 44 | 45 | private static final long serialVersionUID = 5045507662443540605L; 46 | 47 | final rx.CompletableSubscriber actual; 48 | 49 | MaybeV3Observer(rx.CompletableSubscriber actual) { 50 | this.actual = actual; 51 | } 52 | 53 | @Override 54 | public void unsubscribe() { 55 | DisposableHelper.dispose(this); 56 | } 57 | 58 | @Override 59 | public boolean isUnsubscribed() { 60 | return DisposableHelper.isDisposed(get()); 61 | } 62 | 63 | @Override 64 | public void onSubscribe(io.reactivex.rxjava3.disposables.Disposable d) { 65 | DisposableHelper.setOnce(this, d); 66 | } 67 | 68 | @Override 69 | public void onSuccess(T value) { 70 | actual.onCompleted(); 71 | } 72 | 73 | @Override 74 | public void onError(Throwable e) { 75 | actual.onError(e); 76 | } 77 | 78 | @Override 79 | public void onComplete() { 80 | actual.onCompleted(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/MaybeV3ToSingleV1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import java.util.NoSuchElementException; 20 | import java.util.concurrent.atomic.AtomicReference; 21 | 22 | /** 23 | * Converts a V3 Maybe into a V1 Single where an onComplete triggers a NoSuchElementException. 24 | * 25 | * @param the value type 26 | */ 27 | final class MaybeV3ToSingleV1 implements rx.Single.OnSubscribe { 28 | 29 | final io.reactivex.rxjava3.core.MaybeSource source; 30 | 31 | MaybeV3ToSingleV1(io.reactivex.rxjava3.core.MaybeSource source) { 32 | this.source = source; 33 | } 34 | 35 | @Override 36 | public void call(rx.SingleSubscriber t) { 37 | MaybeV3Observer parent = new MaybeV3Observer<>(t); 38 | t.add(parent); 39 | source.subscribe(parent); 40 | } 41 | 42 | static final class MaybeV3Observer 43 | extends AtomicReference 44 | implements io.reactivex.rxjava3.core.MaybeObserver, rx.Subscription { 45 | 46 | private static final long serialVersionUID = 5045507662443540605L; 47 | 48 | final rx.SingleSubscriber actual; 49 | 50 | MaybeV3Observer(rx.SingleSubscriber actual) { 51 | this.actual = actual; 52 | } 53 | 54 | @Override 55 | public void unsubscribe() { 56 | DisposableHelper.dispose(this); 57 | } 58 | 59 | @Override 60 | public boolean isUnsubscribed() { 61 | return DisposableHelper.isDisposed(get()); 62 | } 63 | 64 | @Override 65 | public void onSubscribe(io.reactivex.rxjava3.disposables.Disposable d) { 66 | DisposableHelper.setOnce(this, d); 67 | } 68 | 69 | @Override 70 | public void onSuccess(T value) { 71 | actual.onSuccess(value); 72 | } 73 | 74 | @Override 75 | public void onError(Throwable e) { 76 | actual.onError(e); 77 | } 78 | 79 | @Override 80 | public void onComplete() { 81 | actual.onError(new NoSuchElementException("The source Maybe was empty.")); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/ObservableV1ToFlowableV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Convert a V1 Observable into a V3 Flowable, composing backpressure and cancellation. 21 | * 22 | * @param the value type 23 | */ 24 | final class ObservableV1ToFlowableV3 extends io.reactivex.rxjava3.core.Flowable { 25 | 26 | final rx.Observable source; 27 | 28 | ObservableV1ToFlowableV3(rx.Observable source) { 29 | this.source = source; 30 | } 31 | 32 | @Override 33 | protected void subscribeActual(org.reactivestreams.Subscriber s) { 34 | ObservableSubscriber parent = new ObservableSubscriber<>(s); 35 | ObservableSubscriberSubscription parentSubscription = new ObservableSubscriberSubscription(parent); 36 | s.onSubscribe(parentSubscription); 37 | 38 | source.unsafeSubscribe(parent); 39 | } 40 | 41 | static final class ObservableSubscriber extends rx.Subscriber { 42 | 43 | final org.reactivestreams.Subscriber actual; 44 | 45 | boolean done; 46 | 47 | ObservableSubscriber(org.reactivestreams.Subscriber actual) { 48 | this.actual = actual; 49 | this.request(0L); // suppress starting out with Long.MAX_VALUE 50 | } 51 | 52 | @Override 53 | public void onNext(T t) { 54 | if (done) { 55 | return; 56 | } 57 | if (t == null) { 58 | unsubscribe(); 59 | onError(new NullPointerException( 60 | "The upstream 1.x Observable signalled a null value which is not supported in 3.x")); 61 | } else { 62 | actual.onNext(t); 63 | } 64 | } 65 | 66 | @Override 67 | public void onError(Throwable e) { 68 | if (done) { 69 | io.reactivex.rxjava3.plugins.RxJavaPlugins.onError(e); 70 | return; 71 | } 72 | done = true; 73 | actual.onError(e); 74 | unsubscribe(); // v1 expects an unsubscribe call when terminated 75 | } 76 | 77 | @Override 78 | public void onCompleted() { 79 | if (done) { 80 | return; 81 | } 82 | done = true; 83 | actual.onComplete(); 84 | unsubscribe(); // v1 expects an unsubscribe call when terminated 85 | } 86 | 87 | void requestMore(long n) { 88 | request(n); 89 | } 90 | } 91 | 92 | static final class ObservableSubscriberSubscription implements org.reactivestreams.Subscription { 93 | 94 | final ObservableSubscriber parent; 95 | 96 | ObservableSubscriberSubscription(ObservableSubscriber parent) { 97 | this.parent = parent; 98 | } 99 | 100 | @Override 101 | public void request(long n) { 102 | parent.requestMore(n); 103 | } 104 | 105 | @Override 106 | public void cancel() { 107 | parent.unsubscribe(); 108 | } 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/ObservableV1ToObservableV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Convert a V1 Observable into a V3 Observable, composing cancellation. 21 | * 22 | * @param the value type 23 | */ 24 | final class ObservableV1ToObservableV3 extends io.reactivex.rxjava3.core.Observable { 25 | 26 | final rx.Observable source; 27 | 28 | ObservableV1ToObservableV3(rx.Observable source) { 29 | this.source = source; 30 | } 31 | 32 | @Override 33 | protected void subscribeActual(io.reactivex.rxjava3.core.Observer s) { 34 | ObservableSubscriber parent = new ObservableSubscriber<>(s); 35 | s.onSubscribe(parent); 36 | 37 | source.unsafeSubscribe(parent); 38 | } 39 | 40 | static final class ObservableSubscriber extends rx.Subscriber 41 | implements io.reactivex.rxjava3.disposables.Disposable { 42 | 43 | final io.reactivex.rxjava3.core.Observer actual; 44 | 45 | boolean done; 46 | 47 | ObservableSubscriber(io.reactivex.rxjava3.core.Observer actual) { 48 | this.actual = actual; 49 | } 50 | 51 | @Override 52 | public void onNext(T t) { 53 | if (done) { 54 | return; 55 | } 56 | if (t == null) { 57 | unsubscribe(); 58 | onError(new NullPointerException( 59 | "The upstream 1.x Observable signalled a null value which is not supported in 3.x")); 60 | } else { 61 | actual.onNext(t); 62 | } 63 | } 64 | 65 | @Override 66 | public void onError(Throwable e) { 67 | if (done) { 68 | io.reactivex.rxjava3.plugins.RxJavaPlugins.onError(e); 69 | return; 70 | } 71 | done = true; 72 | actual.onError(e); 73 | unsubscribe(); // v1 expects an unsubscribe call when terminated 74 | } 75 | 76 | @Override 77 | public void onCompleted() { 78 | if (done) { 79 | return; 80 | } 81 | done = true; 82 | actual.onComplete(); 83 | unsubscribe(); // v1 expects an unsubscribe call when terminated 84 | } 85 | 86 | @Override 87 | public void dispose() { 88 | unsubscribe(); 89 | } 90 | 91 | @Override 92 | public boolean isDisposed() { 93 | return isUnsubscribed(); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/ProcessorV3ToSubjectV1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Wrap a 3.x FlowableProcessor into a 1.x Subject. 21 | * @param the input and output value type 22 | * @since 0.9.0 23 | */ 24 | final class ProcessorV3ToSubjectV1 extends rx.subjects.Subject { 25 | 26 | static rx.subjects.Subject createWith(io.reactivex.rxjava3.processors.FlowableProcessor processor) { 27 | State state = new State<>(processor); 28 | return new ProcessorV3ToSubjectV1<>(state); 29 | } 30 | 31 | final State state; 32 | 33 | private ProcessorV3ToSubjectV1(State state) { 34 | super(state); 35 | this.state = state; 36 | } 37 | 38 | @Override 39 | public void onNext(T t) { 40 | state.onNext(t); 41 | } 42 | 43 | @Override 44 | public void onError(Throwable e) { 45 | state.onError(e); 46 | } 47 | 48 | @Override 49 | public void onCompleted() { 50 | state.onCompleted(); 51 | } 52 | 53 | @Override 54 | public boolean hasObservers() { 55 | return state.hasObservers(); 56 | } 57 | 58 | static final class State 59 | implements rx.Observable.OnSubscribe { 60 | 61 | final io.reactivex.rxjava3.processors.FlowableProcessor processor; 62 | 63 | State(io.reactivex.rxjava3.processors.FlowableProcessor processor) { 64 | this.processor = processor; 65 | } 66 | 67 | @Override 68 | public void call(rx.Subscriber t) { 69 | hu.akarnokd.rxjava3.interop.FlowableV3ToObservableV1.SourceSubscriber parent = 70 | new hu.akarnokd.rxjava3.interop.FlowableV3ToObservableV1.SourceSubscriber<>(t); 71 | 72 | t.add(parent); 73 | t.setProducer(parent); 74 | 75 | processor.subscribe(parent); 76 | } 77 | 78 | void onNext(T t) { 79 | processor.onNext(t); 80 | } 81 | 82 | void onError(Throwable e) { 83 | processor.onError(e); 84 | } 85 | 86 | void onCompleted() { 87 | processor.onComplete(); 88 | } 89 | 90 | boolean hasObservers() { 91 | return processor.hasSubscribers(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/RxJavaInterop.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Conversion methods for converting between 1.x and 3.x reactive types, composing backpressure 21 | * and cancellation through. 22 | */ 23 | public final class RxJavaInterop { 24 | /** Utility class. */ 25 | private RxJavaInterop() { 26 | throw new IllegalStateException("No instances!"); 27 | } 28 | 29 | // ----------------------------------------------------------------------------------------- 30 | // Conversions to 3.x 31 | // ----------------------------------------------------------------------------------------- 32 | 33 | /** 34 | * Converts an 1.x Observable into a 3.x Flowable, composing the backpressure and 35 | * cancellation (unsubscription) through. 36 | *

37 | * Note that in 1.x Observable's backpressure somewhat optional; you may need to apply 38 | * one of the onBackpressureXXX operators on the source Observable or the resulting Flowable. 39 | *

40 | *
Backpressure:
41 | *
The operator doesn't interfere with backpressure which is determined by the 42 | * source 1.x {@code Observable}'s backpressure behavior.
43 | *
Scheduler:
44 | *
The method does not operate by default on a particular {@code Scheduler}.
45 | *
46 | * @param the value type 47 | * @param source the source 1.x Observable instance, not null 48 | * @return the new 3.x Flowable instance 49 | * @throws NullPointerException if {@code source} is null 50 | */ 51 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 52 | public static io.reactivex.rxjava3.core.Flowable toV3Flowable(rx.Observable source) { 53 | java.util.Objects.requireNonNull(source, "source is null"); 54 | return new ObservableV1ToFlowableV3<>(source); 55 | } 56 | 57 | /** 58 | * Converts an 1.x Observable into a 3.x Observable, cancellation (unsubscription) through. 59 | *
60 | *
Backpressure:
61 | *
The operator consumes the source 1.x {@code Observable} in an 62 | * unbounded manner (without applying backpressure).
63 | *
Scheduler:
64 | *
The method does not operate by default on a particular {@code Scheduler}.
65 | *
66 | * @param the value type 67 | * @param source the source 1.x Observable instance, not null 68 | * @return the new 3.x Observable instance 69 | * @throws NullPointerException if {@code source} is null 70 | */ 71 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 72 | public static io.reactivex.rxjava3.core.Observable toV3Observable(rx.Observable source) { 73 | java.util.Objects.requireNonNull(source, "source is null"); 74 | return new ObservableV1ToObservableV3<>(source); 75 | } 76 | 77 | /** 78 | * Converts an 1.x Completable into a 3.x Maybe, composing cancellation (unsubscription) through. 79 | *
80 | *
Scheduler:
81 | *
The method does not operate by default on a particular {@code Scheduler}.
82 | *
83 | * @param the value type 84 | * @param source the source 1.x Completable instance, not null 85 | * @return the new 3.x Maybe instance 86 | * @throws NullPointerException if {@code source} is null 87 | */ 88 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 89 | public static io.reactivex.rxjava3.core.Maybe toV3Maybe(rx.Completable source) { 90 | java.util.Objects.requireNonNull(source, "source is null"); 91 | return new CompletableV1ToMaybeV3<>(source); 92 | } 93 | 94 | /** 95 | * Converts an 1.x Single into a 3.x Maybe, composing cancellation (unsubscription) through. 96 | *
97 | *
Scheduler:
98 | *
The method does not operate by default on a particular {@code Scheduler}.
99 | *
100 | * @param the value type 101 | * @param source the source 1.x Single instance, not null 102 | * @return the new 3.x Maybe instance 103 | * @throws NullPointerException if {@code source} is null 104 | */ 105 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 106 | public static io.reactivex.rxjava3.core.Maybe toV3Maybe(rx.Single source) { 107 | java.util.Objects.requireNonNull(source, "source is null"); 108 | return new SingleV1ToMaybeV3<>(source); 109 | } 110 | 111 | /** 112 | * Converts an 1.x Single into a 3.x Single, composing cancellation (unsubscription) through. 113 | *
114 | *
Scheduler:
115 | *
The method does not operate by default on a particular {@code Scheduler}.
116 | *
117 | * @param the value type 118 | * @param source the source 1.x Single instance, not null 119 | * @return the new 3.x Single instance 120 | * @throws NullPointerException if {@code source} is null 121 | */ 122 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 123 | public static io.reactivex.rxjava3.core.Single toV3Single(rx.Single source) { 124 | java.util.Objects.requireNonNull(source, "source is null"); 125 | return new SingleV1ToSingleV3<>(source); 126 | } 127 | 128 | /** 129 | * Converts an 1.x Completable into a 3.x Completable, composing cancellation (unsubscription) through. 130 | *
131 | *
Scheduler:
132 | *
The method does not operate by default on a particular {@code Scheduler}.
133 | *
134 | * @param source the source 1.x Completable instance, not null 135 | * @return the new 3.x Completable instance 136 | * @throws NullPointerException if {@code source} is null 137 | */ 138 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 139 | public static io.reactivex.rxjava3.core.Completable toV3Completable(rx.Completable source) { 140 | java.util.Objects.requireNonNull(source, "source is null"); 141 | return new CompletableV1ToCompletableV3(source); 142 | } 143 | 144 | /** 145 | * Wraps a 1.x Subject into a 3.x Subject. 146 | *
147 | *
Scheduler:
148 | *
The method does not operate by default on a particular {@code Scheduler}.
149 | *
150 | * @param the input and output value type of the Subjects 151 | * @param subject the subject to wrap with the same input and output type; 152 | * 3.x Subject supports only the same input and output type 153 | * @return the new 3.x Subject instance 154 | * @throws NullPointerException if {@code source} is null 155 | * @since 0.9.0 156 | */ 157 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 158 | public static io.reactivex.rxjava3.subjects.Subject toV3Subject(rx.subjects.Subject subject) { 159 | java.util.Objects.requireNonNull(subject, "subject is null"); 160 | return new SubjectV1ToSubjectV3<>(subject); 161 | } 162 | 163 | /** 164 | * Wraps a 1.x Subject into a 3.x FlowableProcessor. 165 | *
166 | *
Backpressure:
167 | *
The operator doesn't interfere with backpressure which is determined by the 168 | * source 1.x {@code Subject}'s backpressure behavior.
169 | *
Scheduler:
170 | *
The method does not operate by default on a particular {@code Scheduler}.
171 | *
172 | * @param the input and output value type of the Subjects 173 | * @param subject the subject to wrap with the same input and output type; 174 | * 3.x FlowableProcessor supports only the same input and output type 175 | * @return the new 3.x FlowableProcessor instance 176 | * @throws NullPointerException if {@code source} is null 177 | * @since 0.9.0 178 | */ 179 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 180 | public static io.reactivex.rxjava3.processors.FlowableProcessor toV3Processor(rx.subjects.Subject subject) { 181 | java.util.Objects.requireNonNull(subject, "subject is null"); 182 | return new SubjectV1ToProcessorV3<>(subject); 183 | } 184 | 185 | /** 186 | * Convert the 1.x Observable.Transformer into a 3.x FlowableTransformer. 187 | *
188 | *
Backpressure:
189 | *
The operator doesn't interfere with backpressure which is determined by the 190 | * 1.x Observable returned by the 1.x Transformer.
191 | *
Scheduler:
192 | *
The method does not operate by default on a particular {@code Scheduler}.
193 | *
194 | * @param the input value type 195 | * @param the output value type 196 | * @param transformer the 1.x Observable.Transformer to convert 197 | * @return the new FlowableTransformer instance 198 | * @since 0.9.0 199 | */ 200 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 201 | public static io.reactivex.rxjava3.core.FlowableTransformer toV3Transformer(final rx.Observable.Transformer transformer) { 202 | java.util.Objects.requireNonNull(transformer, "transformer is null"); 203 | return new io.reactivex.rxjava3.core.FlowableTransformer() { 204 | @Override 205 | public org.reactivestreams.Publisher apply(io.reactivex.rxjava3.core.Flowable f) { 206 | return toV3Flowable(transformer.call(toV1Observable(f))); 207 | } 208 | }; 209 | } 210 | 211 | /** 212 | * Convert the 1.x Observable.Transformer into a 3.x ObservableTransformer. 213 | *
214 | *
Scheduler:
215 | *
The method does not operate by default on a particular {@code Scheduler}.
216 | *
217 | * @param the input value type 218 | * @param the output value type 219 | * @param strategy the backpressure strategy to apply: BUFFER, DROP or LATEST. 220 | * @param transformer the 1.x Observable.Transformer to convert 221 | * @return the new ObservableTransformer instance 222 | * @since 0.12.0 223 | */ 224 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 225 | public static io.reactivex.rxjava3.core.ObservableTransformer toV3Transformer(final rx.Observable.Transformer transformer, 226 | final io.reactivex.rxjava3.core.BackpressureStrategy strategy) { 227 | java.util.Objects.requireNonNull(transformer, "transformer is null"); 228 | return new io.reactivex.rxjava3.core.ObservableTransformer() { 229 | @Override 230 | public io.reactivex.rxjava3.core.ObservableSource apply(io.reactivex.rxjava3.core.Observable obs) { 231 | return toV3Observable(transformer.call(toV1Observable(obs, strategy))); 232 | } 233 | }; 234 | } 235 | 236 | /** 237 | * Convert the 1.x Single.Transformer into a 3.x SingleTransformer. 238 | *
239 | *
Scheduler:
240 | *
The method does not operate by default on a particular {@code Scheduler}.
241 | *
242 | * @param the input value type 243 | * @param the output value type 244 | * @param transformer the 1.x Single.Transformer to convert 245 | * @return the new SingleTransformer instance 246 | * @since 0.9.0 247 | */ 248 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 249 | public static io.reactivex.rxjava3.core.SingleTransformer toV3Transformer(final rx.Single.Transformer transformer) { 250 | java.util.Objects.requireNonNull(transformer, "transformer is null"); 251 | return new io.reactivex.rxjava3.core.SingleTransformer() { 252 | @Override 253 | public io.reactivex.rxjava3.core.Single apply(io.reactivex.rxjava3.core.Single f) { 254 | return toV3Single(transformer.call(toV1Single(f))); 255 | } 256 | }; 257 | } 258 | 259 | /** 260 | * Convert the 1.x Completable.Transformer into a 3.x CompletableTransformer. 261 | *
262 | *
Scheduler:
263 | *
The method does not operate by default on a particular {@code Scheduler}.
264 | *
265 | * @param transformer the 1.x Completable.Transformer to convert 266 | * @return the new CompletableTransformer instance 267 | * @since 0.9.0 268 | */ 269 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 270 | public static io.reactivex.rxjava3.core.CompletableTransformer toV3Transformer(final rx.Completable.Transformer transformer) { 271 | java.util.Objects.requireNonNull(transformer, "transformer is null"); 272 | return new io.reactivex.rxjava3.core.CompletableTransformer() { 273 | @Override 274 | public io.reactivex.rxjava3.core.Completable apply(io.reactivex.rxjava3.core.Completable f) { 275 | return toV3Completable(transformer.call(toV1Completable(f))); 276 | } 277 | }; 278 | } 279 | 280 | /** 281 | * Convert the 1.x Observable.Operator into a 3.x FlowableOperator. 282 | *
283 | *
Backpressure:
284 | *
The operator doesn't interfere with backpressure which is determined by the 285 | * 1.x Subscriber returned by the 1.x Operator.
286 | *
Scheduler:
287 | *
The method does not operate by default on a particular {@code Scheduler}.
288 | *
289 | * @param the input value type 290 | * @param the output value type 291 | * @param operator the 1.x Observable.Operator to convert 292 | * @return the new FlowableOperator instance 293 | * @since 0.9.0 294 | */ 295 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 296 | public static io.reactivex.rxjava3.core.FlowableOperator toV3Operator(final rx.Observable.Operator operator) { 297 | java.util.Objects.requireNonNull(operator, "operator is null"); 298 | return new io.reactivex.rxjava3.core.FlowableOperator() { 299 | @Override 300 | public org.reactivestreams.Subscriber apply(org.reactivestreams.Subscriber s) throws Exception { 301 | hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriber parent = new hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriber<>(s); 302 | hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriberSubscription parentSubscription = new hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriberSubscription(parent); 303 | s.onSubscribe(parentSubscription); 304 | 305 | rx.Subscriber t; 306 | 307 | try { 308 | t = java.util.Objects.requireNonNull(operator.call(parent), "The operator returned a null rx.Subscriber"); 309 | } catch (Throwable ex) { 310 | io.reactivex.rxjava3.exceptions.Exceptions.throwIfFatal(ex); 311 | rx.exceptions.Exceptions.throwIfFatal(ex); 312 | s.onError(ex); 313 | t = rx.observers.Subscribers.empty(); 314 | t.unsubscribe(); 315 | } 316 | 317 | hu.akarnokd.rxjava3.interop.FlowableV3ToObservableV1.SourceSubscriber z = new hu.akarnokd.rxjava3.interop.FlowableV3ToObservableV1.SourceSubscriber<>(t); 318 | 319 | t.add(z); 320 | t.setProducer(z); 321 | 322 | return z; 323 | } 324 | }; 325 | } 326 | 327 | /** 328 | * Convert the 1.x {@link rx.Subscription} into a 3.x {@link io.reactivex.rxjava3.disposables.Disposable}. 329 | * @param subscription the 1.x Subscription to convert 330 | * @return the new Disposable instance 331 | * @since 0.11.0 332 | */ 333 | public static io.reactivex.rxjava3.disposables.Disposable toV3Disposable(final rx.Subscription subscription) { 334 | java.util.Objects.requireNonNull(subscription, "subscription is null"); 335 | return new SubscriptionV1ToDisposableV3(subscription); 336 | } 337 | 338 | // ----------------------------------------------------------------------------------------- 339 | // Conversions to 1.x 340 | // ----------------------------------------------------------------------------------------- 341 | 342 | /** 343 | * Converts a Reactive-Streams Publisher of any kind (the base type of 3.x Flowable) 344 | * into an 1.x Observable, composing the backpressure and cancellation 345 | * (unsubscription) through. 346 | *

347 | * Note that this method can convert any Reactive-Streams compliant 348 | * source into an 1.x Observable, not just the 3.x Flowable. 349 | *

350 | *
Backpressure:
351 | *
The operator doesn't interfere with backpressure which is determined by the 352 | * source {@code Publisher}'s backpressure behavior.
353 | *
Scheduler:
354 | *
The method does not operate by default on a particular {@code Scheduler}.
355 | *
356 | * @param the value type 357 | * @param source the source Reactive-Streams Publisher instance, not null 358 | * @return the new 1.x Observable instance 359 | * @throws NullPointerException if {@code source} is null 360 | */ 361 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 362 | public static rx.Observable toV1Observable(org.reactivestreams.Publisher source) { 363 | java.util.Objects.requireNonNull(source, "source is null"); 364 | return rx.Observable.unsafeCreate(new FlowableV3ToObservableV1<>(source)); 365 | } 366 | 367 | /** 368 | * Converts a 3.x ObservableSource (the base type of 3.x Observable) into an 1.x 369 | * Observable instance, applying the specified backpressure strategy and composing 370 | * the cancellation (unsubscription) through. 371 | *
372 | *
Backpressure:
373 | *
The operator applies the backpressure strategy you specify.
374 | *
Scheduler:
375 | *
The method does not operate by default on a particular {@code Scheduler}.
376 | *
377 | * @param the value type 378 | * @param source the source ObservableSource instance, not null 379 | * @param strategy the backpressure strategy to apply: BUFFER, DROP or LATEST. 380 | * @return the new 1.x Observable instance 381 | * @throws NullPointerException if {@code source} is null 382 | */ 383 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 384 | public static rx.Observable toV1Observable(io.reactivex.rxjava3.core.ObservableSource source, io.reactivex.rxjava3.core.BackpressureStrategy strategy) { 385 | java.util.Objects.requireNonNull(source, "source is null"); 386 | java.util.Objects.requireNonNull(strategy, "strategy is null"); 387 | return toV1Observable(io.reactivex.rxjava3.core.Observable.wrap(source).toFlowable(strategy)); 388 | } 389 | 390 | /** 391 | * Converts an 3.x SingleSource (the base type of 3.x Single) into a 392 | * 1.x Single, composing cancellation (unsubscription) through. 393 | *
394 | *
Scheduler:
395 | *
The method does not operate by default on a particular {@code Scheduler}.
396 | *
397 | * @param the value type 398 | * @param source the source 3.x SingleSource instance, not null 399 | * @return the new 1.x Single instance 400 | * @throws NullPointerException if {@code source} is null 401 | */ 402 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 403 | public static rx.Single toV1Single(io.reactivex.rxjava3.core.SingleSource source) { 404 | java.util.Objects.requireNonNull(source, "source is null"); 405 | return rx.Single.create(new SingleV3ToSingleV1<>(source)); 406 | } 407 | 408 | /** 409 | * Converts an 3.x CompletableSource (the base type of 3.x Completable) into a 410 | * 1.x Completable, composing cancellation (unsubscription) through. 411 | *
412 | *
Scheduler:
413 | *
The method does not operate by default on a particular {@code Scheduler}.
414 | *
415 | * @param source the source 3.x CompletableSource instance, not null 416 | * @return the new 1.x Completable instance 417 | * @throws NullPointerException if {@code source} is null 418 | */ 419 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 420 | public static rx.Completable toV1Completable(io.reactivex.rxjava3.core.CompletableSource source) { 421 | java.util.Objects.requireNonNull(source, "source is null"); 422 | return rx.Completable.create(new CompletableV3ToCompletableV1(source)); 423 | } 424 | 425 | /** 426 | * Converts an 3.x MaybeSource (the base type of 3.x Maybe) into a 427 | * 1.x Single, composing cancellation (unsubscription) through and 428 | * signalling NoSuchElementException if the MaybeSource is empty. 429 | *
430 | *
Scheduler:
431 | *
The method does not operate by default on a particular {@code Scheduler}.
432 | *
433 | * @param the source's value type 434 | * @param source the source 3.x MaybeSource instance, not null 435 | * @return the new 1.x Single instance 436 | * @throws NullPointerException if {@code source} is null 437 | */ 438 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 439 | public static rx.Single toV1Single(io.reactivex.rxjava3.core.MaybeSource source) { 440 | java.util.Objects.requireNonNull(source, "source is null"); 441 | return rx.Single.create(new MaybeV3ToSingleV1<>(source)); 442 | } 443 | 444 | /** 445 | * Converts an 3.x MaybeSource (the base type of 3.x Maybe) into a 446 | * 1.x Completable, composing cancellation (unsubscription) through 447 | * and ignoring the success value. 448 | *
449 | *
Scheduler:
450 | *
The method does not operate by default on a particular {@code Scheduler}.
451 | *
452 | * @param the source's value type 453 | * @param source the source 3.x MaybeSource instance, not null 454 | * @return the new 1.x Completable instance 455 | * @throws NullPointerException if {@code source} is null 456 | */ 457 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 458 | public static rx.Completable toV1Completable(io.reactivex.rxjava3.core.MaybeSource source) { 459 | java.util.Objects.requireNonNull(source, "source is null"); 460 | return rx.Completable.create(new MaybeV3ToCompletableV1<>(source)); 461 | } 462 | 463 | /** 464 | * Wraps a 3.x Subject into a 1.x Subject. 465 | *
466 | *
Scheduler:
467 | *
The method does not operate by default on a particular {@code Scheduler}.
468 | *
469 | * @param the input and output value type of the Subjects 470 | * @param subject the subject to wrap with the same input and output type; 471 | * 3.x Subject supports only the same input and output type 472 | * @return the new 1.x Subject instance 473 | * @throws NullPointerException if {@code source} is null 474 | * @since 0.9.0 475 | */ 476 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 477 | public static rx.subjects.Subject toV1Subject(io.reactivex.rxjava3.subjects.Subject subject) { 478 | java.util.Objects.requireNonNull(subject, "subject is null"); 479 | return SubjectV3ToSubjectV1.createWith(subject); 480 | } 481 | 482 | /** 483 | * Wraps a 3.x FlowableProcessor into a 1.x Subject. 484 | *
485 | *
Backpressure:
486 | *
The operator doesn't interfere with backpressure which is determined by the 487 | * source {@code FlowableProcessor}'s backpressure behavior.
488 | *
Scheduler:
489 | *
The method does not operate by default on a particular {@code Scheduler}.
490 | *
491 | * @param the input and output value type of the Subjects 492 | * @param processor the flowable-processor to wrap with the same input and output type; 493 | * 3.x FlowableProcessor supports only the same input and output type 494 | * @return the new 1.x Subject instance 495 | * @throws NullPointerException if {@code source} is null 496 | * @since 0.9.0 497 | */ 498 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 499 | public static rx.subjects.Subject toV1Subject(io.reactivex.rxjava3.processors.FlowableProcessor processor) { 500 | java.util.Objects.requireNonNull(processor, "processor is null"); 501 | return ProcessorV3ToSubjectV1.createWith(processor); 502 | } 503 | 504 | /** 505 | * Convert the 3.x FlowableTransformer into a 1.x Observable.Transformer. 506 | *
507 | *
Backpressure:
508 | *
The operator doesn't interfere with backpressure which is determined by the 509 | * 3.x Flowable returned by the 3.x FlowableTransformer.
510 | *
Scheduler:
511 | *
The method does not operate by default on a particular {@code Scheduler}.
512 | *
513 | * @param the input value type 514 | * @param the output value type 515 | * @param transformer the 3.x FlowableTransformer to convert 516 | * @return the new Observable.Transformer instance 517 | * @since 0.9.0 518 | */ 519 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 520 | public static rx.Observable.Transformer toV1Transformer(final io.reactivex.rxjava3.core.FlowableTransformer transformer) { 521 | java.util.Objects.requireNonNull(transformer, "transformer is null"); 522 | return new rx.Observable.Transformer() { 523 | @Override 524 | public rx.Observable call(rx.Observable f) { 525 | return toV1Observable(transformer.apply(toV3Flowable(f))); 526 | } 527 | }; 528 | } 529 | 530 | /** 531 | * Convert the 3.x ObservableTransformer into a 1.x Observable.Transformer. 532 | *
533 | *
Scheduler:
534 | *
The method does not operate by default on a particular {@code Scheduler}.
535 | *
536 | * @param the input value type 537 | * @param the output value type 538 | * @param transformer the 3.x ObservableTransformer to convert 539 | * @param strategy the backpressure strategy to apply: BUFFER, DROP or LATEST. 540 | * @return the new Observable.Transformer instance 541 | * @since 0.12.0 542 | */ 543 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 544 | public static rx.Observable.Transformer toV1Transformer(final io.reactivex.rxjava3.core.ObservableTransformer transformer, 545 | final io.reactivex.rxjava3.core.BackpressureStrategy strategy) { 546 | java.util.Objects.requireNonNull(transformer, "transformer is null"); 547 | return new rx.Observable.Transformer() { 548 | @Override 549 | public rx.Observable call(rx.Observable obs) { 550 | return toV1Observable(transformer.apply(toV3Observable(obs)), strategy); 551 | } 552 | }; 553 | } 554 | 555 | /** 556 | * Convert the 3.x SingleTransformer into a 1.x Single.Transformer. 557 | *
558 | *
Scheduler:
559 | *
The method does not operate by default on a particular {@code Scheduler}.
560 | *
561 | * @param the input value type 562 | * @param the output value type 563 | * @param transformer the 3.x SingleTransformer to convert 564 | * @return the new Single.Transformer instance 565 | * @since 0.9.0 566 | */ 567 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 568 | public static rx.Single.Transformer toV1Transformer(final io.reactivex.rxjava3.core.SingleTransformer transformer) { 569 | java.util.Objects.requireNonNull(transformer, "transformer is null"); 570 | return new rx.Single.Transformer() { 571 | @Override 572 | public rx.Single call(rx.Single f) { 573 | return toV1Single(transformer.apply(toV3Single(f))); 574 | } 575 | }; 576 | } 577 | 578 | /** 579 | * Convert the 3.x CompletableTransformer into a 1.x Completable.Transformer. 580 | *
581 | *
Scheduler:
582 | *
The method does not operate by default on a particular {@code Scheduler}.
583 | *
584 | * @param transformer the 3.x CompletableTransformer to convert 585 | * @return the new Completable.Transformer instance 586 | * @since 0.9.0 587 | */ 588 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 589 | public static rx.Completable.Transformer toV1Transformer(final io.reactivex.rxjava3.core.CompletableTransformer transformer) { 590 | java.util.Objects.requireNonNull(transformer, "transformer is null"); 591 | return new rx.Completable.Transformer() { 592 | @Override 593 | public rx.Completable call(rx.Completable f) { 594 | return toV1Completable(transformer.apply(toV3Completable(f))); 595 | } 596 | }; 597 | } 598 | 599 | /** 600 | * Convert the 3.x FlowableOperator into a 1.x Observable.Operator. 601 | *
602 | *
Backpressure:
603 | *
The operator doesn't interfere with backpressure which is determined by the 604 | * 3.x Subscriber returned by the 3.x FlowableOperator.
605 | *
Scheduler:
606 | *
The method does not operate by default on a particular {@code Scheduler}.
607 | *
608 | * @param the input value type 609 | * @param the output value type 610 | * @param operator the 3.x FlowableOperator to convert 611 | * @return the new Observable.Operator instance 612 | * @since 0.9.0 613 | */ 614 | @io.reactivex.rxjava3.annotations.SchedulerSupport(io.reactivex.rxjava3.annotations.SchedulerSupport.NONE) 615 | public static rx.Observable.Operator toV1Operator(final io.reactivex.rxjava3.core.FlowableOperator operator) { 616 | java.util.Objects.requireNonNull(operator, "operator is null"); 617 | return new rx.Observable.Operator() { 618 | @Override 619 | public rx.Subscriber call(rx.Subscriber t) { 620 | hu.akarnokd.rxjava3.interop.FlowableV3ToObservableV1.SourceSubscriber z = new hu.akarnokd.rxjava3.interop.FlowableV3ToObservableV1.SourceSubscriber<>(t); 621 | 622 | t.add(z); 623 | t.setProducer(z); 624 | 625 | org.reactivestreams.Subscriber s; 626 | 627 | try { 628 | s = java.util.Objects.requireNonNull(operator.apply(z), "The operator returned a null Subscriber"); 629 | } catch (Throwable ex) { 630 | io.reactivex.rxjava3.exceptions.Exceptions.throwIfFatal(ex); 631 | rx.exceptions.Exceptions.throwIfFatal(ex); 632 | t.onError(ex); 633 | rx.Subscriber r = rx.observers.Subscribers.empty(); 634 | r.unsubscribe(); 635 | return r; 636 | } 637 | 638 | hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriber parent = new hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriber<>(s); 639 | hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriberSubscription parentSubscription = new hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriberSubscription(parent); 640 | s.onSubscribe(parentSubscription); 641 | 642 | return parent; 643 | } 644 | }; 645 | } 646 | 647 | /** 648 | * Convert the 3.x {@link io.reactivex.rxjava3.disposables.Disposable} into a 1.x {@link rx.Subscription}. 649 | * @param disposable the 3.x Disposable to convert 650 | * @return the new Subscription instance 651 | * @since 0.11.0 652 | */ 653 | public static rx.Subscription toV1Subscription(final io.reactivex.rxjava3.disposables.Disposable disposable) { 654 | java.util.Objects.requireNonNull(disposable, "disposable is null"); 655 | return new DisposableV3ToSubscriptionV1(disposable); 656 | } 657 | 658 | /** 659 | * Convert the 3.x {@link io.reactivex.rxjava3.core.Scheduler} into a 1.x {@link rx.Scheduler}. 660 | * @param scheduler the 3.x Scheduler to convert 661 | * @return the new 1.x Scheduler instance 662 | * @since 0.12.0 663 | */ 664 | public static rx.Scheduler toV1Scheduler(io.reactivex.rxjava3.core.Scheduler scheduler) { 665 | java.util.Objects.requireNonNull(scheduler, "scheduler is null"); 666 | return new SchedulerV3ToSchedulerV1(scheduler); 667 | } 668 | 669 | /** 670 | * Convert the 3.x {@link io.reactivex.rxjava3.core.Scheduler} into a 1.x {@link rx.Scheduler}. 671 | * @param scheduler the 1.x Scheduler to convert 672 | * @return the new 3.x Scheduler instance 673 | * @since 0.12.0 674 | */ 675 | public static io.reactivex.rxjava3.core.Scheduler toV3Scheduler(rx.Scheduler scheduler) { 676 | java.util.Objects.requireNonNull(scheduler, "scheduler is null"); 677 | return new SchedulerV1ToSchedulerV3(scheduler); 678 | } 679 | } 680 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SchedulerV1ToSchedulerV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import java.util.concurrent.TimeUnit; 20 | 21 | /** 22 | * Wraps a 1.x {@link rx.Scheduler} and exposes it as a 23 | * 3.x {@link io.reactivex.rxjava3.core.Scheduler}. 24 | * @since 0.12.0 25 | */ 26 | final class SchedulerV1ToSchedulerV3 extends io.reactivex.rxjava3.core.Scheduler { 27 | 28 | final rx.Scheduler source; 29 | 30 | SchedulerV1ToSchedulerV3(rx.Scheduler source) { 31 | this.source = source; 32 | } 33 | 34 | @Override 35 | public long now(TimeUnit unit) { 36 | return unit.convert(source.now(), TimeUnit.MILLISECONDS); 37 | } 38 | 39 | @Override 40 | public void start() { 41 | if (source instanceof rx.internal.schedulers.SchedulerLifecycle) { 42 | ((rx.internal.schedulers.SchedulerLifecycle)source).start(); 43 | } 44 | } 45 | 46 | @Override 47 | public void shutdown() { 48 | if (source instanceof rx.internal.schedulers.SchedulerLifecycle) { 49 | ((rx.internal.schedulers.SchedulerLifecycle)source).shutdown(); 50 | } 51 | } 52 | 53 | @Override 54 | public Worker createWorker() { 55 | return new WorkerV1ToWorkerV3(source.createWorker()); 56 | } 57 | 58 | static final class WorkerV1ToWorkerV3 extends io.reactivex.rxjava3.core.Scheduler.Worker { 59 | 60 | final rx.Scheduler.Worker v1Worker; 61 | 62 | WorkerV1ToWorkerV3(rx.Scheduler.Worker v1Worker) { 63 | this.v1Worker = v1Worker; 64 | } 65 | 66 | @Override 67 | public io.reactivex.rxjava3.disposables.Disposable schedule(Runnable action) { 68 | final RunnableToV1Action0 runnable = new RunnableToV1Action0(action); 69 | return RxJavaInterop.toV3Disposable(v1Worker.schedule(runnable)); 70 | } 71 | 72 | @Override 73 | public io.reactivex.rxjava3.disposables.Disposable schedule(Runnable action, long delayTime, TimeUnit unit) { 74 | final RunnableToV1Action0 runnable = new RunnableToV1Action0(action); 75 | return RxJavaInterop.toV3Disposable(v1Worker.schedule(runnable, delayTime, unit)); 76 | } 77 | 78 | @Override 79 | public io.reactivex.rxjava3.disposables.Disposable schedulePeriodically(Runnable action, long initialDelay, long period, TimeUnit unit) { 80 | final RunnableToV1Action0 runnable = new RunnableToV1Action0(action); 81 | return RxJavaInterop.toV3Disposable(v1Worker.schedulePeriodically(runnable, initialDelay, period, unit)); 82 | } 83 | 84 | @Override 85 | public long now(TimeUnit unit) { 86 | return unit.convert(v1Worker.now(), TimeUnit.MILLISECONDS); 87 | } 88 | 89 | @Override 90 | public void dispose() { 91 | v1Worker.unsubscribe(); 92 | } 93 | 94 | @Override 95 | public boolean isDisposed() { 96 | return v1Worker.isUnsubscribed(); 97 | } 98 | } 99 | 100 | static final class RunnableToV1Action0 implements rx.functions.Action0 { 101 | 102 | final Runnable source; 103 | 104 | RunnableToV1Action0(Runnable source) { 105 | java.util.Objects.requireNonNull(source, "Source 3.x Runnable is null"); 106 | this.source = source; 107 | } 108 | 109 | @Override 110 | public void call() { 111 | source.run(); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SchedulerV3ToSchedulerV1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import java.util.concurrent.TimeUnit; 20 | 21 | import static java.util.concurrent.TimeUnit.MILLISECONDS; 22 | 23 | /** 24 | * Wraps a 3.x {@link io.reactivex.rxjava3.core.Scheduler} and exposes it as a 25 | * 1.x {@link rx.Scheduler}. 26 | * @author Artem Zinnatulin 27 | * @since 0.12.0 28 | */ 29 | final class SchedulerV3ToSchedulerV1 extends rx.Scheduler implements rx.internal.schedulers.SchedulerLifecycle { 30 | 31 | final io.reactivex.rxjava3.core.Scheduler source; 32 | 33 | SchedulerV3ToSchedulerV1(io.reactivex.rxjava3.core.Scheduler source) { 34 | this.source = source; 35 | } 36 | 37 | @Override 38 | public long now() { 39 | return source.now(MILLISECONDS); 40 | } 41 | 42 | @Override 43 | public void start() { 44 | source.start(); 45 | } 46 | 47 | @Override 48 | public void shutdown() { 49 | source.shutdown(); 50 | } 51 | 52 | @Override 53 | public Worker createWorker() { 54 | return new WorkerV3ToWorkerV1(source.createWorker()); 55 | } 56 | 57 | static final class WorkerV3ToWorkerV1 extends rx.Scheduler.Worker { 58 | 59 | final io.reactivex.rxjava3.core.Scheduler.Worker v3Worker; 60 | 61 | WorkerV3ToWorkerV1(io.reactivex.rxjava3.core.Scheduler.Worker v3Worker) { 62 | this.v3Worker = v3Worker; 63 | } 64 | 65 | @Override 66 | public rx.Subscription schedule(rx.functions.Action0 action) { 67 | final Action0V1ToRunnable runnable = new Action0V1ToRunnable(action); 68 | return RxJavaInterop.toV1Subscription(v3Worker.schedule(runnable)); 69 | } 70 | 71 | @Override 72 | public rx.Subscription schedule(rx.functions.Action0 action, long delayTime, TimeUnit unit) { 73 | final Action0V1ToRunnable runnable = new Action0V1ToRunnable(action); 74 | return RxJavaInterop.toV1Subscription(v3Worker.schedule(runnable, delayTime, unit)); 75 | } 76 | 77 | @Override 78 | public rx.Subscription schedulePeriodically(rx.functions.Action0 action, long initialDelay, long period, TimeUnit unit) { 79 | final Action0V1ToRunnable runnable = new Action0V1ToRunnable(action); 80 | return RxJavaInterop.toV1Subscription(v3Worker.schedulePeriodically(runnable, initialDelay, period, unit)); 81 | } 82 | 83 | @Override 84 | public long now() { 85 | return v3Worker.now(MILLISECONDS); 86 | } 87 | 88 | @Override 89 | public void unsubscribe() { 90 | v3Worker.dispose(); 91 | } 92 | 93 | @Override 94 | public boolean isUnsubscribed() { 95 | return v3Worker.isDisposed(); 96 | } 97 | } 98 | 99 | static final class Action0V1ToRunnable implements Runnable { 100 | 101 | final rx.functions.Action0 source; 102 | 103 | Action0V1ToRunnable(rx.functions.Action0 source) { 104 | java.util.Objects.requireNonNull(source, "Source 1.x Action0 is null"); 105 | this.source = source; 106 | } 107 | 108 | @Override 109 | public void run() { 110 | source.call(); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SingleV1ToMaybeV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Convert a V1 Single into a V3 Maybe, composing cancellation. 21 | * 22 | * @param the value type 23 | */ 24 | final class SingleV1ToMaybeV3 extends io.reactivex.rxjava3.core.Maybe { 25 | 26 | final rx.Single source; 27 | 28 | SingleV1ToMaybeV3(rx.Single source) { 29 | this.source = source; 30 | } 31 | 32 | @Override 33 | protected void subscribeActual(io.reactivex.rxjava3.core.MaybeObserver observer) { 34 | SourceSingleSubscriber parent = new SourceSingleSubscriber<>(observer); 35 | observer.onSubscribe(parent); 36 | source.subscribe(parent); 37 | } 38 | 39 | static final class SourceSingleSubscriber extends rx.SingleSubscriber 40 | implements io.reactivex.rxjava3.disposables.Disposable { 41 | 42 | final io.reactivex.rxjava3.core.MaybeObserver observer; 43 | 44 | SourceSingleSubscriber(io.reactivex.rxjava3.core.MaybeObserver observer) { 45 | this.observer = observer; 46 | } 47 | 48 | @Override 49 | public void onSuccess(T value) { 50 | if (value == null) { 51 | observer.onError(new NullPointerException( 52 | "The upstream 1.x Single signalled a null value which is not supported in 3.x")); 53 | } else { 54 | observer.onSuccess(value); 55 | } 56 | } 57 | 58 | @Override 59 | public void onError(Throwable error) { 60 | observer.onError(error); 61 | } 62 | 63 | @Override 64 | public void dispose() { 65 | unsubscribe(); 66 | } 67 | 68 | @Override 69 | public boolean isDisposed() { 70 | return isUnsubscribed(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SingleV1ToSingleV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Convert a V1 Single into a V3 Single, composing cancellation. 21 | * 22 | * @param the value type 23 | */ 24 | final class SingleV1ToSingleV3 extends io.reactivex.rxjava3.core.Single { 25 | 26 | final rx.Single source; 27 | 28 | SingleV1ToSingleV3(rx.Single source) { 29 | this.source = source; 30 | } 31 | 32 | @Override 33 | protected void subscribeActual(io.reactivex.rxjava3.core.SingleObserver observer) { 34 | SourceSingleSubscriber parent = new SourceSingleSubscriber<>(observer); 35 | observer.onSubscribe(parent); 36 | source.subscribe(parent); 37 | } 38 | 39 | static final class SourceSingleSubscriber extends rx.SingleSubscriber 40 | implements io.reactivex.rxjava3.disposables.Disposable { 41 | 42 | final io.reactivex.rxjava3.core.SingleObserver observer; 43 | 44 | SourceSingleSubscriber(io.reactivex.rxjava3.core.SingleObserver observer) { 45 | this.observer = observer; 46 | } 47 | 48 | @Override 49 | public void onSuccess(T value) { 50 | if (value == null) { 51 | observer.onError(new NullPointerException( 52 | "The upstream 1.x Single signalled a null value which is not supported in 3.x")); 53 | } else { 54 | observer.onSuccess(value); 55 | } 56 | } 57 | 58 | @Override 59 | public void onError(Throwable error) { 60 | observer.onError(error); 61 | } 62 | 63 | @Override 64 | public void dispose() { 65 | unsubscribe(); 66 | } 67 | 68 | @Override 69 | public boolean isDisposed() { 70 | return isUnsubscribed(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SingleV3ToSingleV1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import java.util.concurrent.atomic.AtomicReference; 20 | 21 | /** 22 | * Convert a V3 Single into a V1 Single, composing cancellation. 23 | * 24 | * @param the value type 25 | */ 26 | final class SingleV3ToSingleV1 implements rx.Single.OnSubscribe { 27 | 28 | final io.reactivex.rxjava3.core.SingleSource source; 29 | 30 | SingleV3ToSingleV1(io.reactivex.rxjava3.core.SingleSource source) { 31 | this.source = source; 32 | } 33 | 34 | @Override 35 | public void call(rx.SingleSubscriber t) { 36 | SourceSingleObserver parent = new SourceSingleObserver<>(t); 37 | t.add(parent); 38 | source.subscribe(parent); 39 | } 40 | 41 | static final class SourceSingleObserver 42 | extends AtomicReference 43 | implements io.reactivex.rxjava3.core.SingleObserver, rx.Subscription { 44 | 45 | private static final long serialVersionUID = 4758098209431016997L; 46 | 47 | final rx.SingleSubscriber actual; 48 | 49 | SourceSingleObserver(rx.SingleSubscriber actual) { 50 | this.actual = actual; 51 | } 52 | 53 | @Override 54 | public void unsubscribe() { 55 | DisposableHelper.dispose(this); 56 | } 57 | 58 | @Override 59 | public boolean isUnsubscribed() { 60 | return DisposableHelper.isDisposed(get()); 61 | } 62 | 63 | @Override 64 | public void onSubscribe(io.reactivex.rxjava3.disposables.Disposable d) { 65 | DisposableHelper.setOnce(this, d); 66 | } 67 | 68 | @Override 69 | public void onSuccess(T value) { 70 | actual.onSuccess(value); 71 | } 72 | 73 | @Override 74 | public void onError(Throwable e) { 75 | actual.onError(e); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SubjectV1ToProcessorV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Wrap a V1 Subject and expose it as a V3 FlowableProcessor. 21 | * @param the input/output value type 22 | * @since 0.9.0 23 | */ 24 | final class SubjectV1ToProcessorV3 extends io.reactivex.rxjava3.processors.FlowableProcessor { 25 | 26 | final rx.subjects.Subject source; 27 | 28 | volatile boolean terminated; 29 | Throwable error; 30 | 31 | SubjectV1ToProcessorV3(rx.subjects.Subject source) { 32 | this.source = source; 33 | } 34 | 35 | @Override 36 | public void onSubscribe(org.reactivestreams.Subscription s) { 37 | if (terminated) { 38 | s.cancel(); 39 | } else { 40 | s.request(Long.MAX_VALUE); 41 | } 42 | } 43 | 44 | @Override 45 | public void onNext(T t) { 46 | if (!terminated) { 47 | if (t == null) { 48 | onError(new NullPointerException()); 49 | } else { 50 | source.onNext(t); 51 | } 52 | } 53 | } 54 | 55 | @Override 56 | public void onError(Throwable e) { 57 | if (!terminated) { 58 | if (e == null) { 59 | e = new NullPointerException("Throwable was null"); 60 | } 61 | error = e; 62 | terminated = true; 63 | source.onError(e); 64 | } else { 65 | io.reactivex.rxjava3.plugins.RxJavaPlugins.onError(e); 66 | } 67 | } 68 | 69 | @Override 70 | public void onComplete() { 71 | if (!terminated) { 72 | terminated = true; 73 | source.onCompleted(); 74 | } 75 | } 76 | 77 | @Override 78 | protected void subscribeActual(org.reactivestreams.Subscriber s) { 79 | hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriber parent = 80 | new hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriber<>(s); 81 | hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriberSubscription parentSubscription = 82 | new hu.akarnokd.rxjava3.interop.ObservableV1ToFlowableV3.ObservableSubscriberSubscription(parent); 83 | s.onSubscribe(parentSubscription); 84 | 85 | source.unsafeSubscribe(parent); 86 | } 87 | 88 | @Override 89 | public boolean hasSubscribers() { 90 | return source.hasObservers(); 91 | } 92 | 93 | @Override 94 | public boolean hasComplete() { 95 | return terminated && error == null; 96 | } 97 | 98 | @Override 99 | public boolean hasThrowable() { 100 | return terminated && error != null; 101 | } 102 | 103 | @Override 104 | public Throwable getThrowable() { 105 | return terminated ? error : null; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SubjectV1ToSubjectV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Wrap a V1 Subject and expose it as a V3 Subject. 21 | * @param the input/output value type 22 | * @since 0.9.0 23 | */ 24 | final class SubjectV1ToSubjectV3 extends io.reactivex.rxjava3.subjects.Subject { 25 | 26 | final rx.subjects.Subject source; 27 | 28 | volatile boolean terminated; 29 | Throwable error; 30 | 31 | SubjectV1ToSubjectV3(rx.subjects.Subject source) { 32 | this.source = source; 33 | } 34 | 35 | @Override 36 | public void onSubscribe(io.reactivex.rxjava3.disposables.Disposable d) { 37 | if (terminated) { 38 | d.dispose(); 39 | } 40 | } 41 | 42 | @Override 43 | public void onNext(T t) { 44 | if (!terminated) { 45 | if (t == null) { 46 | onError(new NullPointerException()); 47 | } else { 48 | source.onNext(t); 49 | } 50 | } 51 | } 52 | 53 | @Override 54 | public void onError(Throwable e) { 55 | if (!terminated) { 56 | if (e == null) { 57 | e = new NullPointerException("Throwable was null"); 58 | } 59 | error = e; 60 | terminated = true; 61 | source.onError(e); 62 | } else { 63 | io.reactivex.rxjava3.plugins.RxJavaPlugins.onError(e); 64 | } 65 | } 66 | 67 | @Override 68 | public void onComplete() { 69 | if (!terminated) { 70 | terminated = true; 71 | source.onCompleted(); 72 | } 73 | } 74 | 75 | @Override 76 | protected void subscribeActual(io.reactivex.rxjava3.core.Observer observer) { 77 | hu.akarnokd.rxjava3.interop.ObservableV1ToObservableV3.ObservableSubscriber parent = 78 | new hu.akarnokd.rxjava3.interop.ObservableV1ToObservableV3.ObservableSubscriber<>(observer); 79 | observer.onSubscribe(parent); 80 | 81 | source.unsafeSubscribe(parent); 82 | } 83 | 84 | @Override 85 | public boolean hasObservers() { 86 | return source.hasObservers(); 87 | } 88 | 89 | @Override 90 | public boolean hasComplete() { 91 | return terminated && error == null; 92 | } 93 | 94 | @Override 95 | public boolean hasThrowable() { 96 | return terminated && error != null; 97 | } 98 | 99 | @Override 100 | public Throwable getThrowable() { 101 | return terminated ? error : null; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SubjectV3ToSubjectV1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import java.util.concurrent.atomic.*; 20 | 21 | /** 22 | * Wrap a 3.x Subject into a 1.x Subject. 23 | * @param the input and output value type 24 | * @since 0.9.0 25 | */ 26 | final class SubjectV3ToSubjectV1 extends rx.subjects.Subject { 27 | 28 | static rx.subjects.Subject createWith(io.reactivex.rxjava3.subjects.Subject subject) { 29 | State state = new State<>(subject); 30 | return new SubjectV3ToSubjectV1<>(state); 31 | } 32 | 33 | final State state; 34 | 35 | private SubjectV3ToSubjectV1(State state) { 36 | super(state); 37 | this.state = state; 38 | } 39 | 40 | @Override 41 | public void onNext(T t) { 42 | state.onNext(t); 43 | } 44 | 45 | @Override 46 | public void onError(Throwable e) { 47 | state.onError(e); 48 | } 49 | 50 | @Override 51 | public void onCompleted() { 52 | state.onCompleted(); 53 | } 54 | 55 | @Override 56 | public boolean hasObservers() { 57 | return state.hasObservers(); 58 | } 59 | 60 | static final class State 61 | implements rx.Observable.OnSubscribe { 62 | 63 | final io.reactivex.rxjava3.subjects.Subject subject; 64 | 65 | State(io.reactivex.rxjava3.subjects.Subject subject) { 66 | this.subject = subject; 67 | } 68 | 69 | @Override 70 | public void call(rx.Subscriber t) { 71 | SourceObserver parent = new SourceObserver<>(t); 72 | 73 | t.add(parent); 74 | t.setProducer(parent); 75 | 76 | subject.subscribe(parent); 77 | } 78 | 79 | void onNext(T t) { 80 | subject.onNext(t); 81 | } 82 | 83 | void onError(Throwable e) { 84 | subject.onError(e); 85 | } 86 | 87 | void onCompleted() { 88 | subject.onComplete(); 89 | } 90 | 91 | boolean hasObservers() { 92 | return subject.hasObservers(); 93 | } 94 | } 95 | 96 | static final class SourceObserver 97 | extends AtomicReference 98 | implements io.reactivex.rxjava3.core.Observer, rx.Subscription, rx.Producer { 99 | 100 | private static final long serialVersionUID = -6567012932544037069L; 101 | 102 | final rx.Subscriber actual; 103 | 104 | final AtomicLong requested; 105 | 106 | SourceObserver(rx.Subscriber actual) { 107 | this.actual = actual; 108 | this.requested = new AtomicLong(); 109 | } 110 | 111 | @Override 112 | public void request(long n) { 113 | if (n > 0L) { 114 | BackpressureHelper.add(requested, n); 115 | } 116 | } 117 | 118 | @Override 119 | public void unsubscribe() { 120 | DisposableHelper.dispose(this); 121 | } 122 | 123 | @Override 124 | public boolean isUnsubscribed() { 125 | return DisposableHelper.isDisposed(get()); 126 | } 127 | 128 | @Override 129 | public void onSubscribe(io.reactivex.rxjava3.disposables.Disposable d) { 130 | DisposableHelper.setOnce(this, d); 131 | } 132 | 133 | @Override 134 | public void onNext(T t) { 135 | if (requested.get() != 0) { 136 | actual.onNext(t); 137 | BackpressureHelper.produced(requested, 1); 138 | } else { 139 | unsubscribe(); 140 | actual.onError(new rx.exceptions.MissingBackpressureException()); 141 | } 142 | } 143 | 144 | @Override 145 | public void onError(Throwable t) { 146 | lazySet(DisposableHelper.DISPOSED); 147 | actual.onError(t); 148 | } 149 | 150 | @Override 151 | public void onComplete() { 152 | lazySet(DisposableHelper.DISPOSED); 153 | actual.onCompleted(); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SubscriptionHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import java.util.Objects; 20 | import java.util.concurrent.atomic.*; 21 | 22 | import org.reactivestreams.Subscription; 23 | 24 | import io.reactivex.rxjava3.exceptions.ProtocolViolationException; 25 | import io.reactivex.rxjava3.plugins.RxJavaPlugins; 26 | 27 | /** 28 | * Utility methods to validate Subscriptions in the various onSubscribe calls. 29 | */ 30 | enum SubscriptionHelper implements Subscription { 31 | /** 32 | * Represents a cancelled Subscription. 33 | *

Don't leak this instance! 34 | */ 35 | CANCELLED 36 | ; 37 | 38 | @Override 39 | public void request(long n) { 40 | // deliberately ignored 41 | } 42 | 43 | @Override 44 | public void cancel() { 45 | // deliberately ignored 46 | } 47 | 48 | /** 49 | * Verifies that current is null, next is not null, otherwise signals errors 50 | * to the RxJavaPlugins and returns false. 51 | * @param current the current Subscription, expected to be null 52 | * @param next the next Subscription, expected to be non-null 53 | * @return true if the validation succeeded 54 | */ 55 | public static boolean validate(Subscription current, Subscription next) { 56 | if (next == null) { 57 | RxJavaPlugins.onError(new NullPointerException("next is null")); 58 | return false; 59 | } 60 | if (current != null) { 61 | next.cancel(); 62 | reportSubscriptionSet(); 63 | return false; 64 | } 65 | return true; 66 | } 67 | 68 | /** 69 | * Reports that the subscription is already set to the RxJavaPlugins error handler, 70 | * which is an indication of a onSubscribe management bug. 71 | */ 72 | public static void reportSubscriptionSet() { 73 | RxJavaPlugins.onError(new ProtocolViolationException("Subscription already set!")); 74 | } 75 | 76 | /** 77 | * Validates that the n is positive. 78 | * @param n the request amount 79 | * @return false if n is non-positive. 80 | */ 81 | public static boolean validate(long n) { 82 | if (n <= 0) { 83 | RxJavaPlugins.onError(new IllegalArgumentException("n > 0 required but it was " + n)); 84 | return false; 85 | } 86 | return true; 87 | } 88 | 89 | 90 | /** 91 | * Atomically sets the subscription on the field if it is still null. 92 | *

If the field is not null and doesn't contain the {@link #CANCELLED} 93 | * instance, the {@link #reportSubscriptionSet()} is called. 94 | * @param field the target field 95 | * @param s the new subscription to set 96 | * @return true if the operation succeeded, false if the target field was not null. 97 | */ 98 | public static boolean setOnce(AtomicReference field, Subscription s) { 99 | Objects.requireNonNull(s, "s is null"); 100 | if (!field.compareAndSet(null, s)) { 101 | s.cancel(); 102 | if (field.get() != CANCELLED) { 103 | reportSubscriptionSet(); 104 | } 105 | return false; 106 | } 107 | return true; 108 | } 109 | 110 | /** 111 | * Atomically swaps in the common cancelled subscription instance 112 | * and cancels the previous subscription if any. 113 | * @param field the target field to dispose the contents of 114 | * @return true if the swap from the non-cancelled instance to the 115 | * common cancelled instance happened in the caller's thread (allows 116 | * further one-time actions). 117 | */ 118 | public static boolean cancel(AtomicReference field) { 119 | Subscription current = field.get(); 120 | if (current != CANCELLED) { 121 | current = field.getAndSet(CANCELLED); 122 | if (current != CANCELLED) { 123 | if (current != null) { 124 | current.cancel(); 125 | } 126 | return true; 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | /** 133 | * Atomically sets the new Subscription on the field and requests any accumulated amount 134 | * from the requested field. 135 | * @param field the target field for the new Subscription 136 | * @param requested the current requested amount 137 | * @param s the new Subscription, not null (verified) 138 | * @return true if the Subscription was set the first time 139 | */ 140 | public static boolean deferredSetOnce(AtomicReference field, AtomicLong requested, 141 | Subscription s) { 142 | if (SubscriptionHelper.setOnce(field, s)) { 143 | long r = requested.getAndSet(0L); 144 | if (r != 0L) { 145 | s.request(r); 146 | } 147 | return true; 148 | } 149 | return false; 150 | } 151 | 152 | /** 153 | * Atomically requests from the Subscription in the field if not null, otherwise accumulates 154 | * the request amount in the requested field to be requested once the field is set to non-null. 155 | * @param field the target field that may already contain a Subscription 156 | * @param requested the current requested amount 157 | * @param n the request amount, positive (verified) 158 | */ 159 | public static void deferredRequest(AtomicReference field, AtomicLong requested, long n) { 160 | Subscription s = field.get(); 161 | if (s != null) { 162 | s.request(n); 163 | } else { 164 | if (SubscriptionHelper.validate(n)) { 165 | BackpressureHelper.add(requested, n); 166 | 167 | s = field.get(); 168 | if (s != null) { 169 | long r = requested.getAndSet(0L); 170 | if (r != 0L) { 171 | s.request(r); 172 | } 173 | } 174 | } 175 | } 176 | } 177 | 178 | /** 179 | * Atomically sets the subscription on the field if it is still null and issues a positive request 180 | * to the given {@link Subscription}. 181 | *

182 | * If the field is not null and doesn't contain the {@link #CANCELLED} 183 | * instance, the {@link #reportSubscriptionSet()} is called. 184 | * @param field the target field 185 | * @param s the new subscription to set 186 | * @param request the amount to request, positive (not verified) 187 | * @return true if the operation succeeded, false if the target field was not null. 188 | * @since 2.1.11 189 | */ 190 | public static boolean setOnce(AtomicReference field, Subscription s, long request) { 191 | if (setOnce(field, s)) { 192 | s.request(request); 193 | return true; 194 | } 195 | return false; 196 | } 197 | } -------------------------------------------------------------------------------- /src/main/java/hu/akarnokd/rxjava3/interop/SubscriptionV1ToDisposableV3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import io.reactivex.rxjava3.disposables.Disposable; 20 | import rx.Subscription; 21 | 22 | /** 23 | * Wraps a v1 Subscription and exposes it as a v3 Disposable. 24 | * @since 0.11.0 25 | * @author Artem Zinnatulin 26 | */ 27 | final class SubscriptionV1ToDisposableV3 implements Disposable { 28 | 29 | private final Subscription subscription; 30 | 31 | SubscriptionV1ToDisposableV3(Subscription subscription) { 32 | this.subscription = subscription; 33 | } 34 | 35 | @Override 36 | public void dispose() { 37 | subscription.unsubscribe(); 38 | } 39 | 40 | @Override 41 | public boolean isDisposed() { 42 | return subscription.isUnsubscribed(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/hu/akarnokd/rxjava3/interop/BackpressureHelperTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | import java.util.List; 22 | import java.util.concurrent.atomic.AtomicLong; 23 | 24 | import org.junit.Test; 25 | 26 | import io.reactivex.rxjava3.plugins.RxJavaPlugins; 27 | 28 | public class BackpressureHelperTest { 29 | @Test 30 | public void constructorShouldBePrivate() { 31 | TestHelper.checkUtilityClass(BackpressureHelper.class); 32 | } 33 | 34 | @Test 35 | public void addCap() { 36 | assertEquals(2L, BackpressureHelper.addCap(1, 1)); 37 | assertEquals(Long.MAX_VALUE, BackpressureHelper.addCap(1, Long.MAX_VALUE - 1)); 38 | assertEquals(Long.MAX_VALUE, BackpressureHelper.addCap(1, Long.MAX_VALUE)); 39 | assertEquals(Long.MAX_VALUE, BackpressureHelper.addCap(Long.MAX_VALUE - 1, Long.MAX_VALUE - 1)); 40 | assertEquals(Long.MAX_VALUE, BackpressureHelper.addCap(Long.MAX_VALUE, Long.MAX_VALUE)); 41 | } 42 | 43 | @Test 44 | public void multiplyCap() { 45 | assertEquals(6, BackpressureHelper.multiplyCap(2, 3)); 46 | assertEquals(Long.MAX_VALUE, BackpressureHelper.multiplyCap(2, Long.MAX_VALUE)); 47 | assertEquals(Long.MAX_VALUE, BackpressureHelper.multiplyCap(Long.MAX_VALUE, Long.MAX_VALUE)); 48 | assertEquals(Long.MAX_VALUE, BackpressureHelper.multiplyCap(1L << 32, 1L << 32)); 49 | 50 | } 51 | 52 | @Test 53 | public void producedMore() { 54 | List list = TestHelper.trackPluginErrors(); 55 | 56 | try { 57 | AtomicLong requested = new AtomicLong(1); 58 | 59 | assertEquals(0, BackpressureHelper.produced(requested, 2)); 60 | 61 | TestHelper.assertError(list, 0, IllegalStateException.class, "More produced than requested: -1"); 62 | } finally { 63 | RxJavaPlugins.reset(); 64 | } 65 | } 66 | 67 | @Test 68 | public void producedMoreCancel() { 69 | List list = TestHelper.trackPluginErrors(); 70 | 71 | try { 72 | AtomicLong requested = new AtomicLong(1); 73 | 74 | assertEquals(0, BackpressureHelper.producedCancel(requested, 2)); 75 | 76 | TestHelper.assertError(list, 0, IllegalStateException.class, "More produced than requested: -1"); 77 | } finally { 78 | RxJavaPlugins.reset(); 79 | } 80 | } 81 | 82 | @Test 83 | public void requestProduceRace() { 84 | final AtomicLong requested = new AtomicLong(1); 85 | 86 | for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { 87 | 88 | Runnable r1 = new Runnable() { 89 | @Override 90 | public void run() { 91 | BackpressureHelper.produced(requested, 1); 92 | } 93 | }; 94 | 95 | Runnable r2 = new Runnable() { 96 | @Override 97 | public void run() { 98 | BackpressureHelper.add(requested, 1); 99 | } 100 | }; 101 | 102 | TestHelper.race(r1, r2); 103 | } 104 | } 105 | 106 | @Test 107 | public void requestCancelProduceRace() { 108 | final AtomicLong requested = new AtomicLong(1); 109 | 110 | for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { 111 | 112 | Runnable r1 = new Runnable() { 113 | @Override 114 | public void run() { 115 | BackpressureHelper.produced(requested, 1); 116 | } 117 | }; 118 | 119 | Runnable r2 = new Runnable() { 120 | @Override 121 | public void run() { 122 | BackpressureHelper.addCancel(requested, 1); 123 | } 124 | }; 125 | 126 | TestHelper.race(r1, r2); 127 | } 128 | } 129 | 130 | @Test 131 | public void utilityClass() { 132 | TestHelper.checkUtilityClass(BackpressureHelper.class); 133 | } 134 | 135 | @Test 136 | public void capped() { 137 | final AtomicLong requested = new AtomicLong(Long.MIN_VALUE); 138 | 139 | assertEquals(Long.MIN_VALUE, BackpressureHelper.addCancel(requested, 1)); 140 | assertEquals(Long.MIN_VALUE, BackpressureHelper.addCancel(requested, Long.MAX_VALUE)); 141 | 142 | requested.set(0); 143 | 144 | assertEquals(0, BackpressureHelper.addCancel(requested, Long.MAX_VALUE)); 145 | assertEquals(Long.MAX_VALUE, BackpressureHelper.addCancel(requested, 1)); 146 | assertEquals(Long.MAX_VALUE, BackpressureHelper.addCancel(requested, Long.MAX_VALUE)); 147 | 148 | requested.set(0); 149 | 150 | assertEquals(0, BackpressureHelper.add(requested, Long.MAX_VALUE)); 151 | assertEquals(Long.MAX_VALUE, BackpressureHelper.add(requested, 1)); 152 | assertEquals(Long.MAX_VALUE, BackpressureHelper.add(requested, Long.MAX_VALUE)); 153 | 154 | assertEquals(Long.MAX_VALUE, BackpressureHelper.produced(requested, 1)); 155 | assertEquals(Long.MAX_VALUE, BackpressureHelper.produced(requested, Long.MAX_VALUE)); 156 | } 157 | 158 | @Test 159 | public void multiplyCap2() { 160 | assertEquals(Long.MAX_VALUE, BackpressureHelper.multiplyCap(3, Long.MAX_VALUE >> 1)); 161 | 162 | assertEquals(Long.MAX_VALUE, BackpressureHelper.multiplyCap(1, Long.MAX_VALUE)); 163 | } 164 | 165 | @Test 166 | public void alreadyNegativeMaxLong() { 167 | assertEquals(Long.MIN_VALUE, BackpressureHelper.addCancel(new AtomicLong(Long.MIN_VALUE), 1)); 168 | } 169 | 170 | @Test 171 | public void alreadyMaxLong() { 172 | assertEquals(Long.MAX_VALUE, BackpressureHelper.addCancel(new AtomicLong(Long.MAX_VALUE), 1)); 173 | } 174 | 175 | @Test 176 | public void producedNegativeMaxLong() { 177 | assertEquals(Long.MIN_VALUE, BackpressureHelper.producedCancel(new AtomicLong(Long.MIN_VALUE), 1)); 178 | } 179 | 180 | @Test 181 | public void producedMaxLong() { 182 | assertEquals(Long.MAX_VALUE, BackpressureHelper.producedCancel(new AtomicLong(Long.MAX_VALUE), 1)); 183 | } 184 | } -------------------------------------------------------------------------------- /src/test/java/hu/akarnokd/rxjava3/interop/DisposableHelperTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import static org.junit.Assert.*; 20 | 21 | import java.util.List; 22 | import java.util.concurrent.atomic.AtomicReference; 23 | 24 | import org.junit.Test; 25 | 26 | import io.reactivex.rxjava3.disposables.Disposable; 27 | import io.reactivex.rxjava3.exceptions.ProtocolViolationException; 28 | import io.reactivex.rxjava3.plugins.RxJavaPlugins; 29 | 30 | public class DisposableHelperTest { 31 | @Test 32 | public void enumMethods() { 33 | assertEquals(1, DisposableHelper.values().length); 34 | assertNotNull(DisposableHelper.valueOf("DISPOSED")); 35 | } 36 | 37 | @Test 38 | public void innerDisposed() { 39 | assertTrue(DisposableHelper.DISPOSED.isDisposed()); 40 | DisposableHelper.DISPOSED.dispose(); 41 | assertTrue(DisposableHelper.DISPOSED.isDisposed()); 42 | } 43 | 44 | @Test 45 | public void validationNull() { 46 | List list = TestHelper.trackPluginErrors(); 47 | try { 48 | assertFalse(DisposableHelper.validate(null, null)); 49 | 50 | TestHelper.assertError(list, 0, NullPointerException.class, "next is null"); 51 | } finally { 52 | RxJavaPlugins.reset(); 53 | } 54 | } 55 | 56 | @Test 57 | public void disposeRace() { 58 | for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { 59 | final AtomicReference d = new AtomicReference<>(); 60 | 61 | Runnable r = new Runnable() { 62 | @Override 63 | public void run() { 64 | DisposableHelper.dispose(d); 65 | } 66 | }; 67 | 68 | TestHelper.race(r, r); 69 | } 70 | } 71 | 72 | @Test 73 | public void dispose() { 74 | Disposable u = Disposable.empty(); 75 | final AtomicReference d = new AtomicReference<>(u); 76 | 77 | DisposableHelper.dispose(d); 78 | 79 | assertTrue(u.isDisposed()); 80 | } 81 | 82 | @Test 83 | public void trySet() { 84 | AtomicReference ref = new AtomicReference<>(); 85 | 86 | Disposable d1 = Disposable.empty(); 87 | 88 | assertTrue(DisposableHelper.trySet(ref, d1)); 89 | 90 | Disposable d2 = Disposable.empty(); 91 | 92 | assertFalse(DisposableHelper.trySet(ref, d2)); 93 | 94 | assertFalse(d1.isDisposed()); 95 | 96 | assertFalse(d2.isDisposed()); 97 | 98 | DisposableHelper.dispose(ref); 99 | 100 | Disposable d3 = Disposable.empty(); 101 | 102 | assertFalse(DisposableHelper.trySet(ref, d3)); 103 | 104 | assertTrue(d3.isDisposed()); 105 | } 106 | 107 | @Test 108 | public void reportDisposableSet() throws Throwable { 109 | TestHelper.withErrorTracking(errors -> { 110 | 111 | DisposableHelper.validate(Disposable.empty(), Disposable.empty()); 112 | 113 | TestHelper.assertError(errors, 0, ProtocolViolationException.class); 114 | }); 115 | } 116 | 117 | @Test 118 | public void isDisposed() { 119 | assertFalse(DisposableHelper.isDisposed(Disposable.empty())); 120 | assertTrue(DisposableHelper.isDisposed(DisposableHelper.DISPOSED)); 121 | } 122 | 123 | @Test 124 | public void validate() { 125 | assertTrue(DisposableHelper.validate(null, Disposable.empty())); 126 | } 127 | 128 | @Test 129 | public void setOnceAndReport() throws Throwable { 130 | TestHelper.withErrorTracking(errors -> { 131 | 132 | AtomicReference ref = new AtomicReference<>(Disposable.empty()); 133 | 134 | assertFalse(DisposableHelper.setOnce(ref, Disposable.empty())); 135 | 136 | TestHelper.assertError(errors, 0, ProtocolViolationException.class); 137 | }); 138 | } 139 | } -------------------------------------------------------------------------------- /src/test/java/hu/akarnokd/rxjava3/interop/RxJavaInteropV1SchedulerToV3SchedulerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import static java.util.concurrent.TimeUnit.MINUTES; 20 | import static org.junit.Assert.*; 21 | import static org.mockito.Mockito.*; 22 | 23 | import java.util.concurrent.TimeUnit; 24 | 25 | import org.junit.Test; 26 | 27 | import rx.internal.schedulers.SchedulerLifecycle; 28 | 29 | public class RxJavaInteropV1SchedulerToV3SchedulerTest { 30 | 31 | @Test 32 | public void now() { 33 | rx.Scheduler v1Scheduler = mock(rx.Scheduler.class); 34 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 35 | 36 | when(v1Scheduler.now()).thenReturn(123L); 37 | 38 | assertEquals(123L, v3Scheduler.now(TimeUnit.MILLISECONDS)); 39 | } 40 | 41 | @Test 42 | public void workerSchedule() { 43 | rx.schedulers.TestScheduler v1Scheduler = new rx.schedulers.TestScheduler(); 44 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 45 | 46 | Runnable action0 = mock(Runnable.class); 47 | 48 | v3Scheduler.createWorker().schedule(action0); 49 | verifyNoInteractions(action0); 50 | 51 | v1Scheduler.triggerActions(); 52 | verify(action0).run(); 53 | } 54 | 55 | @Test 56 | public void workerScheduleNullAction() { 57 | rx.Scheduler v1Scheduler = mock(rx.Scheduler.class); 58 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 59 | 60 | try { 61 | v3Scheduler.createWorker().schedule(null); 62 | fail(); 63 | } catch (NullPointerException expected) { 64 | assertEquals("Source 3.x Runnable is null", expected.getMessage()); 65 | } 66 | } 67 | 68 | @Test 69 | public void workerScheduleDelayed() { 70 | rx.schedulers.TestScheduler v1Scheduler = new rx.schedulers.TestScheduler(); 71 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 72 | 73 | Runnable action0 = mock(Runnable.class); 74 | 75 | v3Scheduler.createWorker().schedule(action0, 123L, MINUTES); 76 | verifyNoInteractions(action0); 77 | 78 | v1Scheduler.advanceTimeBy(122L, MINUTES); 79 | verifyNoInteractions(action0); 80 | 81 | v1Scheduler.advanceTimeBy(1L, MINUTES); 82 | verify(action0).run(); 83 | 84 | v1Scheduler.advanceTimeBy(125L, MINUTES); // Check that it's not periodic. 85 | verifyNoMoreInteractions(action0); 86 | } 87 | 88 | @Test 89 | public void workerScheduleDelayedNullAction() { 90 | rx.Scheduler v1Scheduler = mock(rx.Scheduler.class); 91 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 92 | 93 | try { 94 | v3Scheduler.createWorker().schedule(null, 123L, MINUTES); 95 | fail(); 96 | } catch (NullPointerException expected) { 97 | assertEquals("Source 3.x Runnable is null", expected.getMessage()); 98 | } 99 | } 100 | 101 | @Test 102 | public void workerSchedulePeriodically() { 103 | rx.schedulers.TestScheduler v1Scheduler = new rx.schedulers.TestScheduler(); 104 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 105 | 106 | Runnable action0 = mock(Runnable.class); 107 | 108 | v3Scheduler.createWorker().schedulePeriodically(action0, 10L, 123L, MINUTES); 109 | verifyNoInteractions(action0); 110 | 111 | v1Scheduler.advanceTimeBy(9L, MINUTES); 112 | verifyNoInteractions(action0); 113 | 114 | v1Scheduler.advanceTimeBy(1L, MINUTES); 115 | verify(action0).run(); 116 | 117 | v1Scheduler.advanceTimeBy(122L, MINUTES); 118 | verifyNoMoreInteractions(action0); 119 | 120 | v1Scheduler.advanceTimeBy(1L, MINUTES); 121 | verify(action0, times(2)).run(); 122 | 123 | v1Scheduler.advanceTimeBy(123L, MINUTES); 124 | verify(action0, times(3)).run(); // Verify periodic. 125 | 126 | v1Scheduler.advanceTimeBy(123L, MINUTES); 127 | verify(action0, times(4)).run(); // Verify periodic. 128 | } 129 | 130 | @Test 131 | public void workerSchedulePeriodicallyNullAction() { 132 | rx.Scheduler v1Scheduler = mock(rx.Scheduler.class); 133 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 134 | 135 | try { 136 | v3Scheduler.createWorker().schedulePeriodically(null, 10L, 123L, MINUTES); 137 | fail(); 138 | } catch (NullPointerException expected) { 139 | assertEquals("Source 3.x Runnable is null", expected.getMessage()); 140 | } 141 | } 142 | 143 | @Test 144 | public void workerNow() { 145 | rx.Scheduler v1Scheduler = mock(rx.Scheduler.class); 146 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 147 | 148 | rx.Scheduler.Worker v1Worker = mock(rx.Scheduler.Worker.class); 149 | when(v1Scheduler.createWorker()).thenReturn(v1Worker); 150 | io.reactivex.rxjava3.core.Scheduler.Worker v3Worker = v3Scheduler.createWorker(); 151 | 152 | when(v1Worker.now()).thenReturn(123L); 153 | 154 | assertEquals(123L, v3Worker.now(TimeUnit.MILLISECONDS)); 155 | } 156 | 157 | @Test 158 | public void workerUnsubscribe() { 159 | rx.Scheduler v1Scheduler = mock(rx.Scheduler.class); 160 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 161 | 162 | rx.Scheduler.Worker v1Worker = mock(rx.Scheduler.Worker.class); 163 | when(v1Scheduler.createWorker()).thenReturn(v1Worker); 164 | 165 | io.reactivex.rxjava3.core.Scheduler.Worker v3Worker = v3Scheduler.createWorker(); 166 | verify(v1Worker, never()).unsubscribe(); 167 | 168 | v3Worker.dispose(); 169 | verify(v1Worker).unsubscribe(); 170 | } 171 | 172 | @Test 173 | public void workerIsUnsubscribed() { 174 | rx.Scheduler v1Scheduler = mock(rx.Scheduler.class); 175 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 176 | 177 | rx.Scheduler.Worker v1Worker = mock(rx.Scheduler.Worker.class); 178 | when(v1Scheduler.createWorker()).thenReturn(v1Worker); 179 | 180 | io.reactivex.rxjava3.core.Scheduler.Worker v3Worker = v3Scheduler.createWorker(); 181 | 182 | when(v1Worker.isUnsubscribed()).thenReturn(true); 183 | assertTrue(v3Worker.isDisposed()); 184 | 185 | when(v1Worker.isUnsubscribed()).thenReturn(false); 186 | assertFalse(v3Worker.isDisposed()); 187 | } 188 | 189 | @Test 190 | public void startStopNotSupported() { 191 | rx.Scheduler v1Scheduler = mock(rx.Scheduler.class); 192 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 193 | 194 | v3Scheduler.start(); 195 | 196 | verifyNoMoreInteractions(v1Scheduler); 197 | 198 | v3Scheduler.shutdown(); 199 | 200 | verifyNoMoreInteractions(v1Scheduler); 201 | } 202 | 203 | @Test 204 | public void startStopSupported() { 205 | rx.Scheduler v1Scheduler = mock(rx.Scheduler.class, withSettings().extraInterfaces(SchedulerLifecycle.class)); 206 | io.reactivex.rxjava3.core.Scheduler v3Scheduler = RxJavaInterop.toV3Scheduler(v1Scheduler); 207 | 208 | v3Scheduler.start(); 209 | 210 | ((SchedulerLifecycle)verify(v1Scheduler)).start(); 211 | 212 | v3Scheduler.shutdown(); 213 | 214 | ((SchedulerLifecycle)verify(v1Scheduler)).shutdown(); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/test/java/hu/akarnokd/rxjava3/interop/RxJavaInteropV3SchedulerToV1SchedulerTest.java: -------------------------------------------------------------------------------- 1 | package hu.akarnokd.rxjava3.interop; 2 | 3 | import static java.util.concurrent.TimeUnit.*; 4 | import static org.junit.Assert.*; 5 | import static org.mockito.Mockito.*; 6 | 7 | import org.junit.Test; 8 | 9 | import io.reactivex.rxjava3.core.Scheduler; 10 | import io.reactivex.rxjava3.schedulers.TestScheduler; 11 | import rx.functions.Action0; 12 | import rx.internal.schedulers.SchedulerLifecycle; 13 | 14 | public class RxJavaInteropV3SchedulerToV1SchedulerTest { 15 | 16 | @Test 17 | public void now() { 18 | Scheduler v3Scheduler = mock(Scheduler.class); 19 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 20 | 21 | when(v3Scheduler.now(MILLISECONDS)).thenReturn(123L); 22 | 23 | assertEquals(123L, v1Scheduler.now()); 24 | } 25 | 26 | @Test 27 | public void workerSchedule() { 28 | TestScheduler v3Scheduler = new TestScheduler(); 29 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 30 | 31 | Action0 action0 = mock(Action0.class); 32 | 33 | v1Scheduler.createWorker().schedule(action0); 34 | verifyNoInteractions(action0); 35 | 36 | v3Scheduler.triggerActions(); 37 | verify(action0).call(); 38 | } 39 | 40 | @Test 41 | public void workerScheduleNullAction() { 42 | Scheduler v3Scheduler = mock(Scheduler.class); 43 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 44 | 45 | try { 46 | v1Scheduler.createWorker().schedule(null); 47 | fail(); 48 | } catch (NullPointerException expected) { 49 | assertEquals("Source 1.x Action0 is null", expected.getMessage()); 50 | } 51 | } 52 | 53 | @Test 54 | public void workerScheduleDelayed() { 55 | TestScheduler v3Scheduler = new TestScheduler(); 56 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 57 | 58 | Action0 action0 = mock(Action0.class); 59 | 60 | v1Scheduler.createWorker().schedule(action0, 123L, MINUTES); 61 | verifyNoInteractions(action0); 62 | 63 | v3Scheduler.advanceTimeBy(122L, MINUTES); 64 | verifyNoInteractions(action0); 65 | 66 | v3Scheduler.advanceTimeBy(1L, MINUTES); 67 | verify(action0).call(); 68 | 69 | v3Scheduler.advanceTimeBy(125L, MINUTES); // Check that it's not periodic. 70 | verifyNoMoreInteractions(action0); 71 | } 72 | 73 | @Test 74 | public void workerScheduleDelayedNullAction() { 75 | Scheduler v3Scheduler = mock(Scheduler.class); 76 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 77 | 78 | try { 79 | v1Scheduler.createWorker().schedule(null, 123L, MINUTES); 80 | fail(); 81 | } catch (NullPointerException expected) { 82 | assertEquals("Source 1.x Action0 is null", expected.getMessage()); 83 | } 84 | } 85 | 86 | @Test 87 | public void workerSchedulePeriodically() { 88 | TestScheduler v3Scheduler = new TestScheduler(); 89 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 90 | 91 | Action0 action0 = mock(Action0.class); 92 | 93 | v1Scheduler.createWorker().schedulePeriodically(action0, 10L, 123L, MINUTES); 94 | verifyNoInteractions(action0); 95 | 96 | v3Scheduler.advanceTimeBy(9L, MINUTES); 97 | verifyNoInteractions(action0); 98 | 99 | v3Scheduler.advanceTimeBy(1L, MINUTES); 100 | verify(action0).call(); 101 | 102 | v3Scheduler.advanceTimeBy(122L, MINUTES); 103 | verifyNoMoreInteractions(action0); 104 | 105 | v3Scheduler.advanceTimeBy(1L, MINUTES); 106 | verify(action0, times(2)).call(); 107 | 108 | v3Scheduler.advanceTimeBy(123L, MINUTES); 109 | verify(action0, times(3)).call(); // Verify periodic. 110 | 111 | v3Scheduler.advanceTimeBy(123L, MINUTES); 112 | verify(action0, times(4)).call(); // Verify periodic. 113 | } 114 | 115 | @Test 116 | public void workerSchedulePeriodicallyNullAction() { 117 | Scheduler v3Scheduler = mock(Scheduler.class); 118 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 119 | 120 | try { 121 | v1Scheduler.createWorker().schedulePeriodically(null, 10L, 123L, MINUTES); 122 | fail(); 123 | } catch (NullPointerException expected) { 124 | assertEquals("Source 1.x Action0 is null", expected.getMessage()); 125 | } 126 | } 127 | 128 | @Test 129 | public void workerNow() { 130 | Scheduler v3Scheduler = mock(Scheduler.class); 131 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 132 | 133 | Scheduler.Worker v3Worker = mock(Scheduler.Worker.class); 134 | when(v3Scheduler.createWorker()).thenReturn(v3Worker); 135 | rx.Scheduler.Worker v1Worker = v1Scheduler.createWorker(); 136 | 137 | when(v3Worker.now(MILLISECONDS)).thenReturn(123L); 138 | 139 | assertEquals(123L, v1Worker.now()); 140 | } 141 | 142 | @Test 143 | public void workerUnsubscribe() { 144 | Scheduler v3Scheduler = mock(Scheduler.class); 145 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 146 | 147 | Scheduler.Worker v3Worker = mock(Scheduler.Worker.class); 148 | when(v3Scheduler.createWorker()).thenReturn(v3Worker); 149 | 150 | rx.Scheduler.Worker v1Worker = v1Scheduler.createWorker(); 151 | verify(v3Worker, never()).dispose(); 152 | 153 | v1Worker.unsubscribe(); 154 | verify(v3Worker).dispose(); 155 | } 156 | 157 | @Test 158 | public void workerIsUnsubscribed() { 159 | Scheduler v3Scheduler = mock(Scheduler.class); 160 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 161 | 162 | Scheduler.Worker v3Worker = mock(Scheduler.Worker.class); 163 | when(v3Scheduler.createWorker()).thenReturn(v3Worker); 164 | 165 | rx.Scheduler.Worker v1Worker = v1Scheduler.createWorker(); 166 | 167 | when(v3Worker.isDisposed()).thenReturn(true); 168 | assertTrue(v1Worker.isUnsubscribed()); 169 | 170 | when(v3Worker.isDisposed()).thenReturn(false); 171 | assertFalse(v1Worker.isUnsubscribed()); 172 | } 173 | 174 | @Test 175 | public void startStopSupport() { 176 | Scheduler v3Scheduler = mock(Scheduler.class); 177 | rx.Scheduler v1Scheduler = RxJavaInterop.toV1Scheduler(v3Scheduler); 178 | 179 | SchedulerLifecycle lc = (SchedulerLifecycle)v1Scheduler; 180 | 181 | lc.start(); 182 | 183 | verify(v3Scheduler).start(); 184 | 185 | lc.shutdown(); 186 | 187 | verify(v3Scheduler).shutdown(); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/test/java/hu/akarnokd/rxjava3/interop/SubscriptionHelperTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | import static org.junit.Assert.*; 20 | import static org.mockito.ArgumentMatchers.anyLong; 21 | import static org.mockito.Mockito.*; 22 | 23 | import java.util.List; 24 | import java.util.concurrent.atomic.*; 25 | 26 | import org.junit.Test; 27 | import org.reactivestreams.Subscription; 28 | 29 | import io.reactivex.rxjava3.exceptions.ProtocolViolationException; 30 | import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; 31 | import io.reactivex.rxjava3.plugins.RxJavaPlugins; 32 | 33 | public class SubscriptionHelperTest { 34 | 35 | @Test 36 | public void checkEnum() { 37 | TestHelper.checkEnum(SubscriptionHelper.class); 38 | } 39 | 40 | @Test 41 | public void validateNullThrows() { 42 | List errors = TestHelper.trackPluginErrors(); 43 | try { 44 | SubscriptionHelper.validate(null, null); 45 | 46 | TestHelper.assertError(errors, 0, NullPointerException.class, "next is null"); 47 | } finally { 48 | RxJavaPlugins.reset(); 49 | } 50 | } 51 | 52 | @Test 53 | public void cancelNoOp() { 54 | SubscriptionHelper.CANCELLED.cancel(); 55 | } 56 | 57 | @Test 58 | public void cancelRace() { 59 | for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { 60 | final AtomicReference atomicSubscription = new AtomicReference<>(); 61 | 62 | Runnable r = new Runnable() { 63 | @Override 64 | public void run() { 65 | SubscriptionHelper.cancel(atomicSubscription); 66 | } 67 | }; 68 | 69 | TestHelper.race(r, r); 70 | } 71 | } 72 | 73 | @Test 74 | public void invalidDeferredRequest() { 75 | AtomicReference atomicSubscription = new AtomicReference<>(); 76 | AtomicLong r = new AtomicLong(); 77 | 78 | List errors = TestHelper.trackPluginErrors(); 79 | try { 80 | SubscriptionHelper.deferredRequest(atomicSubscription, r, -99); 81 | 82 | TestHelper.assertError(errors, 0, IllegalArgumentException.class, "n > 0 required but it was -99"); 83 | } finally { 84 | RxJavaPlugins.reset(); 85 | } 86 | } 87 | 88 | @Test 89 | public void deferredRace() { 90 | for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { 91 | final AtomicReference atomicSubscription = new AtomicReference<>(); 92 | final AtomicLong r = new AtomicLong(); 93 | 94 | final AtomicLong q = new AtomicLong(); 95 | 96 | final Subscription a = new Subscription() { 97 | @Override 98 | public void request(long n) { 99 | q.addAndGet(n); 100 | } 101 | 102 | @Override 103 | public void cancel() { 104 | 105 | } 106 | }; 107 | 108 | Runnable r1 = new Runnable() { 109 | @Override 110 | public void run() { 111 | SubscriptionHelper.deferredSetOnce(atomicSubscription, r, a); 112 | } 113 | }; 114 | 115 | Runnable r2 = new Runnable() { 116 | @Override 117 | public void run() { 118 | SubscriptionHelper.deferredRequest(atomicSubscription, r, 1); 119 | } 120 | }; 121 | 122 | TestHelper.race(r1, r2); 123 | 124 | assertSame(a, atomicSubscription.get()); 125 | assertEquals(1, q.get()); 126 | assertEquals(0, r.get()); 127 | } 128 | } 129 | 130 | @Test 131 | public void setOnceAndRequest() { 132 | AtomicReference ref = new AtomicReference<>(); 133 | 134 | Subscription sub = mock(Subscription.class); 135 | 136 | assertTrue(SubscriptionHelper.setOnce(ref, sub, 1)); 137 | 138 | verify(sub).request(1); 139 | verify(sub, never()).cancel(); 140 | 141 | List errors = TestHelper.trackPluginErrors(); 142 | try { 143 | sub = mock(Subscription.class); 144 | 145 | assertFalse(SubscriptionHelper.setOnce(ref, sub, 1)); 146 | 147 | verify(sub, never()).request(anyLong()); 148 | verify(sub).cancel(); 149 | 150 | TestHelper.assertError(errors, 0, ProtocolViolationException.class); 151 | } finally { 152 | RxJavaPlugins.reset(); 153 | } 154 | } 155 | 156 | @Test 157 | public void reportDisposableSet() throws Throwable { 158 | TestHelper.withErrorTracking(errors -> { 159 | 160 | SubscriptionHelper.validate(new BooleanSubscription(), new BooleanSubscription()); 161 | 162 | TestHelper.assertError(errors, 0, ProtocolViolationException.class); 163 | }); 164 | } 165 | 166 | @Test 167 | public void validate() { 168 | assertTrue(SubscriptionHelper.validate(null, new BooleanSubscription())); 169 | } 170 | } -------------------------------------------------------------------------------- /src/test/java/hu/akarnokd/rxjava3/interop/TestException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 David Karnok 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package hu.akarnokd.rxjava3.interop; 18 | 19 | /** 20 | * Exception for testing if unchecked expections propagate as-is without confusing with 21 | * other type of common exceptions. 22 | */ 23 | public final class TestException extends RuntimeException { 24 | 25 | private static final long serialVersionUID = -1438148770465406172L; 26 | 27 | /** 28 | * Constructs a TestException without message or cause. 29 | */ 30 | public TestException() { 31 | super(); 32 | } 33 | 34 | /** 35 | * Counstructs a TestException with message and cause. 36 | * @param message the message 37 | * @param cause the cause 38 | */ 39 | public TestException(String message, Throwable cause) { 40 | super(message, cause); 41 | } 42 | 43 | /** 44 | * Constructs a TestException with a message only. 45 | * @param message the message 46 | */ 47 | public TestException(String message) { 48 | super(message); 49 | } 50 | 51 | /** 52 | * Constructs a TestException with a cause only. 53 | * @param cause the cause 54 | */ 55 | public TestException(Throwable cause) { 56 | super(cause); 57 | } 58 | } --------------------------------------------------------------------------------