Reactive Model Generator

An annotation processor for generating reactive models

License

License

GroupId

GroupId

com.github.dimsuz
ArtifactId

ArtifactId

etg-model-generator-runtime
Last Version

Last Version

1.0.0-RC5
Release Date

Release Date

Type

Type

jar
Description

Description

Reactive Model Generator
An annotation processor for generating reactive models
Project URL

Project URL

https://github.com/dimsuz/etg-model-generator
Source Code Management

Source Code Management

https://github.com/dimsuz/etg-model-generator

Download etg-model-generator-runtime

How to add to project

<!-- https://jarcasting.com/artifacts/com.github.dimsuz/etg-model-generator-runtime/ -->
<dependency>
    <groupId>com.github.dimsuz</groupId>
    <artifactId>etg-model-generator-runtime</artifactId>
    <version>1.0.0-RC5</version>
</dependency>
// https://jarcasting.com/artifacts/com.github.dimsuz/etg-model-generator-runtime/
implementation 'com.github.dimsuz:etg-model-generator-runtime:1.0.0-RC5'
// https://jarcasting.com/artifacts/com.github.dimsuz/etg-model-generator-runtime/
implementation ("com.github.dimsuz:etg-model-generator-runtime:1.0.0-RC5")
'com.github.dimsuz:etg-model-generator-runtime:jar:1.0.0-RC5'
<dependency org="com.github.dimsuz" name="etg-model-generator-runtime" rev="1.0.0-RC5">
  <artifact name="etg-model-generator-runtime" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.github.dimsuz', module='etg-model-generator-runtime', version='1.0.0-RC5')
)
libraryDependencies += "com.github.dimsuz" % "etg-model-generator-runtime" % "1.0.0-RC5"
[com.github.dimsuz/etg-model-generator-runtime "1.0.0-RC5"]

Dependencies

compile (1)

Group / Artifact Type Version
io.reactivex.rxjava2 : rxjava jar 2.2.7

runtime (1)

Group / Artifact Type Version
org.jetbrains.kotlin : kotlin-stdlib-jdk8 jar 1.3.21

Project Modules

There are no modules declared in this project.

Reactive Model Generator

Given

@GenerateReducingImplementation(
  baseClass = SerialReactiveModel::class, 
  lceState = LceState::class
)
interface SampleModel {
  fun fetchMovieList(userId: String)
  fun fetchMovieListState(): Observable<LceState<List<Movie>>>

  fun saveMovieRating(userId: String, movieId: String)
  fun saveMovieRatingState(): Observable<LceState<Unit>>

  fun movieGenreList(): Observable<List<Genre>>
}

this processor will generate this model implementation. It will be based on an interface SampleModelOperations which is also generated for you to implement:

// Generated by processor
interface SampleModelOperations {
  fun createFetchMovieListOperation(userId: String, state: SampleModelImpl.State): Single<LceState<List<Movie>>>

  fun createSaveMovieRating(userId: String, movieId: String, state: SampleModelImpl.State): Completable

  fun movieGenreList(): Observable<List<Genre>>
}

Reactive properties are recognized based on the returned LCE state type. To tell the processor about this type you'll need to provide it with a factory which knows how to create instances of LCE state:

data class LceState<C>(
  val isLoading: Boolean,
  val content: C?,
  val error: Throwable?
)

class LceStateFactoryImpl : LceStateFactory<LceState<*>> {
  override fun createLceContent(content: Any): LceState<*> {
    return LceState(isLoading = false, content = content, error = null)
  }

  override fun createLceError(error: Any): LceState<*> {
    return LceState(isLoading = false, content = null, error = error as Throwable)
  }

  override fun createLceLoading(): LceState<*> {
    return LceState(isLoading = true, content = content, error = null)
  }

}

After processor knows about LCE state type, it will search for reactive getters — functions with return type Observable<LceState<*>>, and then attempt to find matching "request"-functions by removing State suffix from getter name. For example: getter saveMovieRatingState should have request named saveMovieRating to be found by processor.

All methods of the model interface which are not recognized as reactive getters/requests will be copied to generated operations-interface without any changes (see movieGenreList() in the above example)

To create an instance of the model which uses the generated implementation call:

val operationsImpl = object : SampleModelOperations {
   // Tyour implementation
}
val lceStateFactory = LceStateFactoryImpl()
val model = ModelGenerator.createModel(operationsImpl, lceStateFactory)
model.fetchMovieListState().subscribe({ println("Got list $it") })
model.fetchMovieList("my-user-id")

Download

Add a Gradle dependency:

apply plugin: 'kotlin-kapt'

implementation 'com.github.dimsuz:etg-model-generator-runtime:1.0.0-RC5'
kapt 'com.github.dimsuz:etg-model-generator-processor:1.0.0-RC5'

License

   Copyright 2019 Dmitry Suzdalev

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

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and 
   limitations under the License.

Versions

Version
1.0.0-RC5
1.0.0-RC4
1.0.0-RC3
1.0.0-RC2
1.0.0-RC1