Releases: RedMadRobot/mapmemory
v2.1
Reusable properties
Reusable properties introduced to address the problem described in issue #14
Reusable properties survive MapMemory.clear() call. It will not be removed from cache, but will be cleared instead. Reusable properties are especially useful for reactive types like Flow. You don't need to resubscribe to flow after MapMemory was cleared.
val flow by memory.sharedFlow<Int>()
// Subscribe to flow
flow.onEach(::println).launchIn(coroutineScope)
// And then clear MapMemory
memory.crear()
// Emitted value will be printed because the flow
// is the same as before memory clear
flow.emit(1)You can create reusable property using operator invoke with clear lambda:
class Counter {
fun reset() = { /*...*/ }
}
val counter: Counter by memory(clear = { it.reset() }) { Counter() }Many of default accessors are already turned into reusable: mutableList, mutableMap, reactiveMutableMap, stateFlow, sharedFlow, behaviorSubject, publishSubject.
Changes
⚠️ Deprecated functions removed:MapMemory.nullable,MapMemory.reactiveMap,ReactiveMutableMap.getStream,ReactiveMutableMap.getAll,ReactiveMutableMap.getAllStream- Added parameter
defaultValueto most of reusable properties:mutableList,mutableMap,reactiveMutableMap,behaviorSubject. ⚠️ mapmemory-rxjava:ReplayStrategywas removed. Please let us know if this change affected you: #20
Fixes
- ReactiveMutableMap: initial empty map is not emitted (#15)
Dependencies
- mapmemory: Kotlin
1.4.30→1.8.20 - mapmemory-coroutines: kotlinx.coroutines
1.4.2→1.6.4 - mapmemory-rxjava3: RxJava
3.0.11→3.1.6
Housekeeping
- infrastructure
0.8.2→0.18.1 - detekt
1.16.0→1.22.0 - Gradle
6.8.3→8.1.1 - binary-compatibility-validator
0.5.0→0.13.1
Full Changelog: v2.0...v2.1
v2.0
ReactiveMap refactored
ReactiveMap renamed to ReactiveMutableMap.
There are two type parameters K (for keys), V (for values) instead of one T (for values), so you can use keys with a type different from String.
Now ReactiveMutableMap implements interface MutableMap.
Also, you can wrap Map with ReactiveMutableMap, using constructor.
Naming changes
Old versions of methods are marked with
@Deprecatedto help migrate to new naming.
Methods getAll replaced with field values to match Map interface.
Word stream in methods names replaced with implementation-specific words to make API clearer.
Coroutines:
getStream→getFlowandgetValueFlowgetAllStream→valuesFlow- New field
flowwith the whole map
RxJava:
getStream→getValueObservablegetAllStream→valuesObservable- New field
observablewith the whole map
KAPT: 'IllegalStateException: Couldn't find declaration file' on delegate with inline getValue operator
There is a bug in Kotlin Compiler that affects MapMemory if you create subclasses - KT-46317.
You can use module mapmemory-kapt-bug-workaround as a workaround:
dependencies {
implementation("com.redmadrobot.mapmemory:mapmemory-kapt-bug-workaround:[latest-version]")
}- val someValue: String by memory
+ val someValue: String by memory.value()v2.0-rc1
Scoped and shared values (#1)
Now there are two types of memory values: scoped (to class) and shared.
All memory values by default are scoped to the class where it's declared.
Scoping prevents from unintended sharing of properties with the same name between classes.
This snippet demonstrates the problem:
package com.example
class StringsStorage(memory: MapMemory) {
var values: MutableList<String> by memory.list()
}
class IntsStorage(memory: MapMemory) {
var values: MutableList<Int> by memory.list() // The same field name as in StringsStorage
}
val strings = StringsStorage(memory)
val ints = IntsStorage(memory)
strings.values.add("A")
ints.values.add(1)
println(memory) Output:
For unscoped fields (old behaviour):
{values: [A, 1]}
For scoped fields (new behavior):
{com.example.StringsStorage#values: [A], com.example.IntsStorage#values: [1]}
You can make memory field shared using extension shared(key: String):
// It is recommended to create constants for shared properties keys
const val KEY_SERVER_HOST = "serverHost"
class ServerConfig(memory: MapMemory) {
var host: String by memory.shared(KEY_SERVER_HOST)
}
class DebugPanelConfig(memory: MapMemory) {
var serverHost: String by memory.shared(KEY_SERVER_HOST)
}Removed .nullable() and .withDefault { ... }
Accessor nullable() is not needed now.
You can just declare a nullable field:
-val selectedOption: String? by memory.nullable()
+val selectedOption: String? by memorywithDefault is no more compatible with MapMemory, so you should use the operator invoke instead:
-var counter: Int by memory.withDefault { 0 }
+var counter: Int by memory { 0 }Mutable collections accessors
BREAKING CHANGE
Now accessors map and list return delegates to access immutable collections.
You should use mutableMap and mutableList for mutable versions of collections.
Added
- Copying constructor for
MapMemory.
Now you can initialize memory with specified content on creation. - New module
mapmemory-test.
Contains utilities helping to test code that usesMapMemory. - New module
mapmemory-rxjava3with accessors for RxJava3.
Changed
MapMemorynow isMutableMap<String, Any>instead ofMutableMap<String, Any?>.
It is made to prevent NPEs becauseConcurrentHashMapnot supports nullable values.
You still can store nullable values in memory using a delegate.