Add store-kotlin module (#229)

* Add store-kotlin module

* Remove useless file

* Fix package in AndroidManifest

* Refactor module tests to assertJ

* Remove wrong annotation

* Add store-kotlin artifact to README

* Add module README

* Add KDoc to Javadoc jar

* Add Experimental annotation

* Mark all public store-kotlin classes as @Experimental

* Replace use of rx's @Experimental with local one instead
This commit is contained in:
Jorge Antonio Díaz-Benito Soriano 2017-06-23 03:22:34 +02:00 committed by Mike Nakhimovich
parent 9926293696
commit 10d0cf6d07
25 changed files with 586 additions and 13 deletions

View file

@ -293,6 +293,11 @@ public class SampleStore extends RealStore<String, BarCode> {
```groovy
compile 'com.nytimes.android:store3:CurrentVersion'
```
+ **Store-Kotlin** Store plus a couple of added Kotlin classes for more idiomatic usage.
```groovy
compile 'com.nytimes.android:store-kotlin3:CurrentVersion'
```
+ **Middleware** Sample Gson parsers, (feel free to create more and open PRs)
```groovy

View file

@ -15,6 +15,10 @@ buildscript {
jcenter()
}
rootProject.ext.versions = [
kotlin: '1.1.2-5'
]
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'com.google.gms:google-services:3.0.0'
@ -22,6 +26,8 @@ buildscript {
classpath 'me.tatarka:gradle-retrolambda:3.6.1'
classpath 'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.8'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.versions.kotlin"
classpath 'org.jetbrains.dokka:dokka-gradle-plugin:0.9.14'
}
// this corresponds to the lombok.ast included above. fixes lint for retro-lambda

View file

@ -12,7 +12,7 @@ allprojects {
}
}
ext.versions = [
ext.versions += [
minSdk : 16,
targetSdk : 25,
compileSdk : 25,
@ -52,6 +52,7 @@ ext.versions = [
autoCommon : '0.6',
javaWriter : '2.5.1',
javax : '1',
commonsLang3 : '3.0',
// Debugging & Inspecting.
slf4j : '1.7.19',
@ -116,6 +117,8 @@ ext.libraries = [
autoCommon : "com.google.auto:auto-common:$versions.autoCommon",
javaWriter : "com.squareup:javawriter:$versions.javaWriter",
javax : "javax.inject:javax.inject:$versions.javax",
kotlinStdLib : "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin",
commonsLang3 : "org.apache.commons:commons-lang3:$versions.commonsLang3",
// Debugging & Inspecting.
slf4jNoOp : "org.slf4j:slf4j-api:$versions.slf4j",

View file

@ -47,7 +47,6 @@ afterEvaluate { project ->
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
pom.groupId = GROUP
pom.artifactId = POM_ARTIFACT_ID
pom.version = VERSION_NAME
@ -195,6 +194,11 @@ afterEvaluate { project ->
classifier = 'javadoc'
from javadoc.destinationDir
}
task kotlinJavadocJar(type: Jar, dependsOn:javadoc) {
classifier = 'javadoc'
from "$buildDir/dokka"
}
}
if (JavaVersion.current().isJava8Compatible()) {
@ -212,7 +216,11 @@ afterEvaluate { project ->
archives androidJavadocsJar
} else {
archives sourcesJar
archives javadocJar
if (project.getPlugins().hasPlugin('kotlin')) {
archives kotlinJavadocJar
} else {
archives javadocJar
}
}
}
}
}

View file

@ -2,11 +2,10 @@ package com.nytimes.android.external.store3.middleware.jackson;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nytimes.android.external.fs3.ObjectToSourceTransformer;
import com.nytimes.android.external.store3.annotations.Experimental;
import javax.annotation.Nonnull;
import io.reactivex.annotations.Experimental;
/**
* Factory which returns Jackson {@link io.reactivex.SingleTransformer} implementations.
*/

View file

@ -1,14 +1,13 @@
package com.nytimes.android.external.store3.middleware.moshi;
import com.nytimes.android.external.fs3.ObjectToSourceTransformer;
import com.nytimes.android.external.store3.annotations.Experimental;
import com.squareup.moshi.Moshi;
import java.lang.reflect.Type;
import javax.annotation.Nonnull;
import io.reactivex.annotations.Experimental;
/**
* Factory which returns Moshi {@link io.reactivex.SingleTransformer} implementations.
*/

View file

@ -2,11 +2,10 @@ package com.nytimes.android.external.store3.middleware;
import com.google.gson.Gson;
import com.nytimes.android.external.fs3.ObjectToSourceTransformer;
import com.nytimes.android.external.store3.annotations.Experimental;
import javax.annotation.Nonnull;
import io.reactivex.annotations.Experimental;
/**
* Factory which returns Gson {@link io.reactivex.SingleTransformer} implementations.
*/

View file

@ -1 +1 @@
include ':app', ':store', ':middleware', ':cache', ':filesystem', ':middleware-moshi', ':middleware-jackson'
include ':app', ':store', ':store-kotlin', ':middleware', ':cache', ':filesystem', ':middleware-moshi', ':middleware-jackson'

40
store-kotlin/README.md Normal file
View file

@ -0,0 +1,40 @@
# store-kotlin
Store with bindings for Kotlin.
## Usage
StoreBuilder:
```kotlin
FluentStoreBuilder.barcode(myFetcher) {
persister = myPersister
memoryPolicy = myMemoryPolicy
stalePolicy = myStalePolicy
}
FluentStoreBuilder.key().fetcher(myFetcher) {
persister = myPersister
memoryPolicy = myMemoryPolicy
stalePolicy = myStalePolicy
}
FluentStoreBuilder.parsedWithKey<Key, Raw, Parsed>(myFetcher) {
persister = myPersister
memoryPolicy = myMemoryPolicy
stalePolicy = myStalePolicy
parser = myParser
parsers = myParsers
}
```
MemoryPolicyBuilder:
```kotlin
FluentMemoryPolicyBuilder.build {
expireAfterWrite = expireAfterWriteValue
expireAfterAccess = expireAfterWriteAccess
expireAfterTimeUnit = expireAfterTimeUnitValue
memorySize = maxSizeValue
}
```
And you can always omit the configuration block if you're happy with the defaults!

26
store-kotlin/build.gradle Normal file
View file

@ -0,0 +1,26 @@
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'org.jetbrains.dokka'
group = GROUP
version = VERSION_NAME
compileKotlin {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
kotlinOptions.jvmTarget = "1.8"
}
javadoc.dependsOn dokka
dependencies {
compile project(':store')
compile libraries.kotlinStdLib
testCompile libraries.mockito
testCompile libraries.junit
testCompile libraries.commonsLang3
testCompile libraries.assertJ
}
apply from: rootProject.file("gradle/maven-push.gradle")

View file

@ -0,0 +1,3 @@
POM_NAME=com.nytimes.android
POM_ARTIFACT_ID=store-kotlin3
POM_PACKAGING=aar

View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
package="com.nytimes.android.external.store-kotlin"/>

View file

@ -0,0 +1,31 @@
package com.nytimes.android.external.store3.base.impl
import com.nytimes.android.external.store3.annotations.Experimental
/**
* Wraps methods for fluent MemoryPolicy instantiation.
*/
@Experimental
class FluentMemoryPolicyBuilder private constructor() {
companion object {
/**
* Builds a MemoryPolicy.
* @param config The desired configuration for the memory policy.
* @return A MemoryPolicy with the desired parameters or default ones if none were provided.
*/
fun build(config: (MemoryPolicyParameters.() -> Unit)? = null): MemoryPolicy =
MemoryPolicyParameters().apply { config?.invoke(this) }.let {
MemoryPolicy.builder()
.apply {
if (it.expireAfterAccess != MemoryPolicy.DEFAULT_POLICY) {
this.setExpireAfterAccess(it.expireAfterAccess)
} else if (it.expireAfterWrite != MemoryPolicy.DEFAULT_POLICY) {
this.setExpireAfterWrite(it.expireAfterWrite)
}
}
.setExpireAfterTimeUnit(it.expireAfterTimeUnit)
.setMemorySize(it.memorySize)
.build()
}
}
}

View file

@ -0,0 +1,46 @@
package com.nytimes.android.external.store3.base.impl
import com.nytimes.android.external.store3.base.Fetcher
import com.nytimes.android.external.store3.base.Parser
import com.nytimes.android.external.store3.base.Persister
import com.nytimes.android.external.store3.util.KeyParser
/**
* A fluent builder for Store instantiation.
* @param fetcher The fetcher for the created instance.
*/
internal class FluentRealStoreBuilder<Raw, Parsed, Key> constructor(
private val fetcher: Fetcher<Raw, Key>,
private val persister: Persister<Raw, Key>?,
private val keyParser: KeyParser<Key, Raw, Parsed>?,
private val parsers: List<Parser<Raw, Parsed>>?,
private val memoryPolicy: MemoryPolicy?,
private val stalePolicy: StalePolicy) {
/**
* Creates the Store instance.
* @return The created Store with the parameters passed into the constructor.
*/
fun open(): Store<Parsed, Key> {
var builder = StoreBuilder.parsedWithKey<Key, Raw, Parsed>()
.fetcher(fetcher)
if (persister != null) {
builder = builder.persister(persister)
}
if (keyParser != null) {
builder = builder.parser(keyParser)
} else {
if (parsers != null) {
builder = builder.parsers(parsers)
}
}
if (memoryPolicy != null) {
builder = builder.memoryPolicy(memoryPolicy)
}
when (stalePolicy) {
StalePolicy.REFRESH_ON_STALE -> builder = builder.refreshOnStale()
StalePolicy.NETWORK_BEFORE_STALE -> builder = builder.networkBeforeStale()
StalePolicy.UNSPECIFIED -> { } // Do nothing
}
return builder.open()
}
}

View file

@ -0,0 +1,60 @@
package com.nytimes.android.external.store3.base.impl
import com.nytimes.android.external.store3.annotations.Experimental
import com.nytimes.android.external.store3.base.Fetcher
/**
* Wraps methods for fluent Store instantiation.
*/
@Experimental
class FluentStoreBuilder private constructor() {
companion object {
/**
* Provides a fluent builder to instantiate a Store that uses BarCode objects as keys.
* @param fetcher Fetcher for the Store.
* @param config Optional configuration block.
*/
fun <Parsed> barcode(
fetcher: Fetcher<Parsed, BarCode>,
config: (StoreParameters<Parsed, BarCode>.() -> Unit)? = null) =
key(fetcher, config)
/**
* Provides a fluent builder to instantiate a Store with a custom type for keys.
* @param fetcher Fetcher for the Store.
* @param config Optional configuration block.
*/
fun <Parsed, Key> key(
fetcher: Fetcher<Parsed, Key>,
config: (StoreParameters<Parsed, Key>.() -> Unit)? = null) =
StoreParameters(fetcher).apply {
if (config != null) {
this.config()
}
}.let {
FluentRealStoreBuilder<Parsed, Parsed, Key>(
fetcher, it.persister, null, null, it.memoryPolicy, it.stalePolicy)
.open()
}
/**
* Provides a fluent builder to instantiate a Store with a custom type for keys and
* conversion between raw and parsed types.
* @param fetcher Fetcher for the Store.
* @param config Optional configuration block.
*/
fun <Key, Raw, Parsed> parsedWithKey(
fetcher: Fetcher<Raw, Key>,
config: (ParsableStoreParameters<Raw, Parsed, Key>.() -> Unit)? = null) =
ParsableStoreParameters<Raw, Parsed, Key>(fetcher).apply {
if (config != null) {
this.config()
}
}.let {
FluentRealStoreBuilder(
fetcher, it.persister, it.parser, it.parsers, it.memoryPolicy,
it.stalePolicy)
.open()
}
}
}

View file

@ -0,0 +1,22 @@
package com.nytimes.android.external.store3.base.impl
import com.nytimes.android.external.store3.annotations.Experimental
import java.util.concurrent.TimeUnit
import kotlin.properties.Delegates
/**
* A parameter box for MemoryPolicy instantiation.
*/
@Experimental
class MemoryPolicyParameters {
var expireAfterWrite by Delegates.vetoable(MemoryPolicy.DEFAULT_POLICY) {
_, _, newValue -> newValue >= 0
}
var expireAfterAccess by Delegates.vetoable(MemoryPolicy.DEFAULT_POLICY) {
_, _, newValue -> newValue >= 0
}
var expireAfterTimeUnit = TimeUnit.SECONDS
var memorySize by Delegates.vetoable(1L) {
_, _, newValue -> newValue >= 1
}
}

View file

@ -0,0 +1,41 @@
package com.nytimes.android.external.store3.base.impl
import com.nytimes.android.external.store3.annotations.Experimental
import com.nytimes.android.external.store3.base.Fetcher
import com.nytimes.android.external.store3.base.Parser
import com.nytimes.android.external.store3.base.Persister
import com.nytimes.android.external.store3.util.KeyParser
/**
* A parameter box for Store instantiation, used for Stores the do not make use of parsing.
* @param fetcher The fetcher for the Store.
*/
@Experimental
open class StoreParameters<Raw, Key> internal constructor(private val fetcher: Fetcher<Raw, Key>) {
var persister: Persister<Raw, Key>? = null
var memoryPolicy: MemoryPolicy? = null
var stalePolicy: StalePolicy = StalePolicy.UNSPECIFIED
}
/**
* A parameter box for Store instantiation, used for Stores that can have parsing.
* @param fetcher The fetcher for the Store.
*/
@Experimental
class ParsableStoreParameters<Raw, Parsed, Key> internal constructor(fetcher: Fetcher<Raw, Key>)
: StoreParameters<Raw, Key>(fetcher) {
var parser: KeyParser<Key, Raw, Parsed>? = null
set(value) {
field = value
if (value != null) {
parsers = null
}
}
var parsers: List<Parser<Raw, Parsed>>? = null
set(value) {
field = value
if (value != null) {
parser = null
}
}
}

View file

@ -0,0 +1,50 @@
package com.nytimes.android.external.store3.base.impl
import org.apache.commons.lang3.builder.EqualsBuilder
import org.junit.Test
import java.util.concurrent.TimeUnit
/**
* Spec for FluentMemoryPolicyBuilder.
*/
class FluentMemoryPolicyBuilderSpec {
@Test
fun shouldBuildAnEquivalentObjectWithAfterWrite() {
val expireAfterWriteValue = 10L
val expireAfterTimeUnitValue = TimeUnit.MILLISECONDS
val maxSizeValue = 1000L
val javaResult = MemoryPolicy.builder()
.setExpireAfterWrite(expireAfterWriteValue)
.setExpireAfterTimeUnit(expireAfterTimeUnitValue)
.setMemorySize(maxSizeValue)
.build()
val kotlinResult = FluentMemoryPolicyBuilder.build {
expireAfterWrite = expireAfterWriteValue
expireAfterTimeUnit = expireAfterTimeUnitValue
memorySize = maxSizeValue
}
assertEquivalent(javaResult, kotlinResult)
}
@Test
fun shouldBuildAnEquivalentObjectWithAfterAccess() {
val expireAfterAccessValue = 20L
val expireAfterTimeUnitValue = TimeUnit.MILLISECONDS
val maxSizeValue = 1000L
val javaResult = MemoryPolicy.builder()
.setExpireAfterAccess(expireAfterAccessValue)
.setExpireAfterTimeUnit(expireAfterTimeUnitValue)
.setMemorySize(maxSizeValue)
.build()
val kotlinResult = FluentMemoryPolicyBuilder.build {
expireAfterAccess = expireAfterAccessValue
expireAfterTimeUnit = expireAfterTimeUnitValue
memorySize = maxSizeValue
}
assertEquivalent(javaResult, kotlinResult)
}
private fun assertEquivalent(expected: MemoryPolicy, actual: MemoryPolicy) =
EqualsBuilder.reflectionEquals(expected, actual)
}

View file

@ -0,0 +1,43 @@
package com.nytimes.android.external.store3.base.impl
import com.nytimes.android.external.store3.base.Fetcher
import com.nytimes.android.external.store3.base.Parser
import com.nytimes.android.external.store3.base.Persister
import com.nytimes.android.external.store3.util.KeyParser
import org.apache.commons.lang3.builder.EqualsBuilder
import org.junit.Test
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import java.util.concurrent.TimeUnit
/**
* Spec for FluentRealStoreBuilder.
*/
@Suppress("UNCHECKED_CAST")
class FluentRealStoreBuilderSpec {
@Test
fun shouldOpenAnEquivalentObject() {
val fetcher = mock(Fetcher::class.java) as Fetcher<Int, Int>
val persister = mock(Persister::class.java) as Persister<Int, Int>
val keyParser = mock(KeyParser::class.java) as KeyParser<Int, Int, Int>
val parsers = listOf<Parser<Int, Int>>()
val memoryPolicy = mock(MemoryPolicy::class.java)
`when`(memoryPolicy.expireAfterTimeUnit).thenReturn(TimeUnit.MILLISECONDS)
val stalePolicy = StalePolicy.NETWORK_BEFORE_STALE
val javaResult = RealStoreBuilder.builder<Int, Int, Int>()
.fetcher(fetcher)
.persister(persister)
.parser(keyParser)
.parsers(parsers)
.memoryPolicy(memoryPolicy)
.networkBeforeStale()
.open()
val kotlinResult = FluentRealStoreBuilder(fetcher, persister, keyParser, parsers,
memoryPolicy, stalePolicy
).open()
assertEquivalent(javaResult, kotlinResult)
}
private fun <T, V> assertEquivalent(expected: Store<T, V>, actual: Store<T, V>) =
EqualsBuilder.reflectionEquals(expected, actual)
}

View file

@ -0,0 +1,47 @@
package com.nytimes.android.external.store3.base.impl
import com.nytimes.android.external.store3.base.Fetcher
import org.apache.commons.lang3.builder.EqualsBuilder
import org.junit.Test
import org.mockito.Mockito
/**
* Spec for FluentStoreBuilder.
*/
class FluentStoreBuilderSpec {
@Test
fun equivalentBarcode() {
@Suppress("UNCHECKED_CAST")
val fetcher = Mockito.mock(Fetcher::class.java) as Fetcher<Any, BarCode>
val javaResult = StoreBuilder.barcode<Any>()
.fetcher(fetcher)
.open()
val kotlinResult = FluentStoreBuilder.barcode(fetcher)
assertEquivalent(javaResult, kotlinResult)
}
@Test
fun equivalentKey() {
@Suppress("UNCHECKED_CAST")
val fetcher = Mockito.mock(Fetcher::class.java) as Fetcher<Any, BarCode>
val javaResult = StoreBuilder.key<BarCode, Any>()
.fetcher(fetcher)
.open()
val kotlinResult = FluentStoreBuilder.key(fetcher)
assertEquivalent(javaResult, kotlinResult)
}
@Test
fun equivalentParsedWithKey() {
@Suppress("UNCHECKED_CAST")
val fetcher = Mockito.mock(Fetcher::class.java) as Fetcher<Any, BarCode>
val javaResult = StoreBuilder.parsedWithKey<BarCode, Any, Any>()
.fetcher(fetcher)
.open()
val kotlinResult = FluentStoreBuilder.parsedWithKey<BarCode, Any, Any>(fetcher)
assertEquivalent(javaResult, kotlinResult)
}
private fun <T, V> assertEquivalent(expected: Store<T, V>, actual: Store<T, V>) =
EqualsBuilder.reflectionEquals(expected, actual)
}

View file

@ -0,0 +1,67 @@
package com.nytimes.android.external.store3.base.impl
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import java.util.concurrent.TimeUnit
/**
* Spec for MemoryPolicyParameters.
*/
class MemoryPolicyParametersSpec {
@Test
fun shouldHaveExpireAfterWriteBeMemoryPolicyDEFAULT_POLICY() {
val sut = MemoryPolicyParameters()
assertThat(sut.expireAfterWrite).isEqualTo(MemoryPolicy.DEFAULT_POLICY)
}
@Test
fun shouldHaveExpireAfterAccessBeMemoryPolicyDEFAULT_POLICY() {
val sut = MemoryPolicyParameters()
assertThat(sut.expireAfterAccess).isEqualTo(MemoryPolicy.DEFAULT_POLICY)
}
@Test
fun shouldHaveExpireAfterTimeUnitBeTimeUnitSECONDS() {
val sut = MemoryPolicyParameters()
assertThat(sut.expireAfterTimeUnit).isEqualTo(TimeUnit.SECONDS)
}
@Test
fun shouldHaveMemorySizeBe1() {
val sut = MemoryPolicyParameters()
assertThat(sut.memorySize).isEqualTo(1)
}
@Test
fun expiredAfterWriteMustBeGreaterThanOrEqualTo0() {
val sut = MemoryPolicyParameters()
val validValue = 82L
val invalidValue = -1L
sut.expireAfterWrite = validValue
assertThat(sut.expireAfterWrite).isEqualTo(validValue)
sut.expireAfterWrite = invalidValue
assertThat(sut.expireAfterWrite).isEqualTo(validValue)
}
@Test
fun expiredAfterAccessMustBeGreaterThanOrEqualTo0() {
val sut = MemoryPolicyParameters()
val validValue = 82L
val invalidValue = -1L
sut.expireAfterAccess = validValue
assertThat(sut.expireAfterAccess).isEqualTo(validValue)
sut.expireAfterAccess = invalidValue
assertThat(sut.expireAfterAccess).isEqualTo(validValue)
}
@Test
fun memorySizeShouldBeGreaterThanOrEqualTo1() {
val sut = MemoryPolicyParameters()
val validValue = 3L
val invalidValue = -1L
sut.memorySize = validValue
assertThat(sut.memorySize).isEqualTo(validValue)
sut.memorySize = invalidValue
assertThat(sut.memorySize).isEqualTo(validValue)
}
}

View file

@ -0,0 +1,66 @@
package com.nytimes.android.external.store3.base.impl
import com.nytimes.android.external.store3.base.Fetcher
import com.nytimes.android.external.store3.base.Parser
import com.nytimes.android.external.store3.util.KeyParser
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.mockito.Mockito.mock
/**
* Spec for StoreParameters.
*/
open class StoreParametersSpec {
@Test
fun defaultPersisterIsNull() {
@Suppress("UNCHECKED_CAST")
val sut = StoreParameters(mock(Fetcher::class.java) as Fetcher<Any, Any>)
assertThat(sut.persister).isNull()
}
@Test
fun defaultMemoryPolicyIsNull() {
@Suppress("UNCHECKED_CAST")
val sut = StoreParameters(mock(Fetcher::class.java) as Fetcher<Any, Any>)
assertThat(sut.memoryPolicy).isNull()
}
@Test
fun defaultStalePolicyIsUnspecified() {
@Suppress("UNCHECKED_CAST")
val sut = StoreParameters(mock(Fetcher::class.java) as Fetcher<Any, Any>)
assertThat(sut.stalePolicy).isEqualTo(StalePolicy.UNSPECIFIED)
}
}
/**
* Spec for ParsableStoreParameters.
*/
@Suppress("UNCHECKED_CAST")
class ParsableStoreParametersSpec : StoreParametersSpec() {
@Test
fun defaultParserIsNull() {
val sut = ParsableStoreParameters<Any, Any, Any>(mock(Fetcher::class.java) as Fetcher<Any, Any>)
assertThat(sut.parser).isNull()
}
@Test
fun defaultParsersIsNull() {
val sut = ParsableStoreParameters<Any, Any, Any>(mock(Fetcher::class.java) as Fetcher<Any, Any>)
assertThat(sut.parsers).isNull()
}
@Test
fun shouldMakeParserNullWhenParsersIsAssigned() {
val sut = ParsableStoreParameters<Any, Any, Any>(mock(Fetcher::class.java) as Fetcher<Any, Any>)
sut.parser = mock(KeyParser::class.java) as KeyParser<Any, Any, Any>
sut.parsers = mock(List::class.java) as List<Parser<Any, Any>>
assertThat(sut.parser).isNull()
}
@Test
fun shouldMakeParsersNullWhenParserIsAssigned() {
val sut = ParsableStoreParameters<Any, Any, Any>(mock(Fetcher::class.java) as Fetcher<Any, Any>)
sut.parsers = mock(List::class.java) as List<Parser<Any, Any>>
sut.parser = mock(KeyParser::class.java) as KeyParser<Any, Any, Any>
assertThat(sut.parsers).isNull()
}
}

View file

@ -0,0 +1,8 @@
package com.nytimes.android.external.store3.annotations;
/**
* Indicates the feature is in experimental state: its existence, signature or behavior
* might change without warning from one release to the next.
*/
public @interface Experimental {
}

View file

@ -1,6 +1,7 @@
package com.nytimes.android.external.store3.base.impl;
import com.nytimes.android.external.cache3.Cache;
import com.nytimes.android.external.store3.annotations.Experimental;
import com.nytimes.android.external.store3.base.Fetcher;
import com.nytimes.android.external.store3.base.InternalStore;
import com.nytimes.android.external.store3.base.Persister;
@ -15,7 +16,6 @@ import javax.annotation.Nullable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.annotations.Experimental;
import io.reactivex.subjects.PublishSubject;
/**

View file

@ -1,11 +1,12 @@
package com.nytimes.android.external.store3.base.impl;
import com.nytimes.android.external.store3.annotations.Experimental;
import javax.annotation.Nonnull;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.annotations.Experimental;
/**