Skip to content

Commit bcc184f

Browse files
authored
LIBMOBILE-529 java compatibility (#30)
* add XElementBuilders.kt to easily build JsonObject in pure Java codebase * bug fix * add unit tests for XElementBuilders * add JavaAnalytics.kt and JavaConfiguration.kt in parity with swift * replace xson with json * replace xson with json * update JavaConfiguration to use builder pattern * rename Serializable.kt to JsonSerializable.kt * update JavaAnalytics.kt with more convenient methods * remove unnecessary annotation * add java compatibility to EventManipulationFunctions.kt * bug fix * add unit tests * add more convenient functions for compatibility * add a constructor to allow init with existing analytics object * add java compat readme * add main readme * add comments * bug fix * fix merge conflicts * add alias to JavaAnalytics.kt * add unit test for alias * update readme files
1 parent 571996e commit bcc184f

File tree

11 files changed

+1793
-49
lines changed

11 files changed

+1793
-49
lines changed

JAVA_COMPAT.md

Lines changed: 454 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,32 @@ NOTE: This project is currently in the Pilot phase and is covered by Segment's [
77
to try out this new library. Please provide feedback via Github issues/PRs, and feel free to submit pull requests. This library will eventually
88
supplant our `analytics-android` library.
99

10+
NOTE: If you use pure Java codebase, please refer to [Java Compatibility](JAVA_COMPAT.md) for sample usages.
11+
1012
## Table of Contents
11-
- [Installation](#installation)
12-
- [Usage](#usage)
13+
- [Analytics-Kotlin](#analytics-kotlin)
14+
- [Table of Contents](#table-of-contents)
15+
- [Installation](#installation)
16+
- [Permissions](#permissions)
17+
- [Usage](#usage)
1318
- [Setting up the client](#setting-up-the-client)
1419
- [Client Options](#client-options)
15-
- [Client Methods](#client-methods)
16-
- track
17-
- identify
18-
- screen
19-
- group
20-
- add
21-
- find
22-
- remove
23-
- flush
24-
- [Plugin Architecture](#plugin-architecture)
20+
- [Client Methods](#client-methods)
21+
- [track](#track)
22+
- [identify](#identify)
23+
- [screen](#screen)
24+
- [group](#group)
25+
- [alias](#alias)
26+
- [add](#add)
27+
- [find](#find)
28+
- [remove](#remove)
29+
- [flush](#flush)
30+
- [Plugin Architecture](#plugin-architecture)
2531
- [Fundamentals](#fundamentals)
26-
- [Advanced Concepts](#advanced-concepts)
27-
- [Contributing](#contributing)
28-
- [Code of Conduct](#code-of-conduct)
29-
- [License](#license)
32+
- [Advanced concepts](#advanced-concepts)
33+
- [Contributing](#contributing)
34+
- [Code of Conduct](#code-of-conduct)
35+
- [License](#license)
3036

3137
## Installation
3238
For our pilot phase, we will be using [jitpack](https://jitpack.io/#segmentio/analytics-kotlin) to distribute the library
@@ -93,7 +99,6 @@ Android
9399
Analytics("SEGMENT_API_KEY", applicationContext) {
94100
analyticsScope = applicationCoroutineScope
95101
collectDeviceId = true
96-
recordScreenViews = true
97102
trackApplicationLifecycleEvents = true
98103
trackDeepLinks = true
99104
flushAt = 1
@@ -156,7 +161,7 @@ Example usage:
156161
```kotlin
157162
analytics.track("View Product", buildJsonObject {
158163
put("productId", 123)
159-
put("productName" "Striped trousers")
164+
put("productName", "Striped trousers")
160165
});
161166
```
162167

@@ -218,6 +223,19 @@ analytics.group("user-123", buildJsonObject {
218223
});
219224
```
220225

226+
### alias
227+
228+
The alias method is used to merge two user identities, effectively connecting two sets of user data as one. This is an advanced method, but it is required to manage user identities successfully in some of our integrations.
229+
Method signature:
230+
```kotlin
231+
fun alias(newId: String)
232+
```
233+
234+
Example Usage:
235+
```kotlin
236+
analytics.alias("newId")
237+
```
238+
221239
### add
222240
add API allows you to add a plugin to the analytics timeline
223241

@@ -230,7 +248,6 @@ Example Usage:
230248
```kotlin
231249
val plugin = object: Plugin {
232250
override val type = Plugin.Type.Enrichment
233-
override val name = "SomePlugin"
234251
override var lateinit analytics: Analytics
235252
}
236253
analytics.add(plugin)
@@ -241,25 +258,25 @@ find a registered plugin from the analytics timeline
241258

242259
Method signature:
243260
```kotlin
244-
fun find(pluginName: String): Plugin
261+
fun <T: Plugin> find(plugin: KClass<T>): T?
245262
```
246263

247264
Example Usage:
248265
```kotlin
249-
val plugin = analytics.find("SomePlugin")
266+
val plugin = analytics.find(plugin::class)
250267
```
251268

252269
### remove
253270
remove a registered plugin from the analytics timeline
254271

255272
Method signature:
256273
```kotlin
257-
fun remove(pluginName: String): Analytics
274+
fun remove(plugin: Plugin): Analytics
258275
```
259276

260277
Example Usage:
261278
```kotlin
262-
analytics.remove("SomePlugin")
279+
analytics.remove(plugin)
263280
```
264281

265282
### flush
@@ -283,7 +300,6 @@ For example if you wanted to add something to the context object of any event pa
283300
```kotlin
284301
class SomePlugin: Plugin {
285302
override val type = Plugin.Type.Enrichment
286-
override val name = "SomePlugin"
287303

288304
override var lateinit analytics: Analytics
289305

@@ -316,7 +332,7 @@ allowing you to modify/augment how events reach the particular destination.
316332
For example if you wanted to implement a device-mode destination plugin for Amplitude
317333
```kotlin
318334
class AmplitudePlugin: DestinationPlugin() {
319-
override val name = "Amplitude"
335+
override val key = "Amplitude"
320336

321337
val amplitudeSDK: Amplitude
322338

@@ -351,7 +367,6 @@ analytics.add(amplitudePlugin) // add amplitudePlugin to the analytics client
351367

352368
val amplitudeEnrichment = object: Plugin {
353369
override val type = Plugin.Type.Enrichment
354-
override val name = "SomePlugin"
355370

356371
override var lateinit analytics: Analytics
357372

core/src/main/java/com/segment/analytics/kotlin/core/Analytics.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ class Analytics(val configuration: Configuration) : Subscriber {
371371

372372
/**
373373
* Remove a plugin from the analytics timeline using its name
374-
* @param pluginName [Plugin] to be remove
374+
* @param plugin [Plugin] to be remove
375375
*/
376376
fun remove(plugin: Plugin): Analytics {
377377
this.timeline.remove(plugin)
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package com.segment.analytics.kotlin.core.compat
2+
3+
import kotlinx.serialization.json.JsonArray
4+
import kotlinx.serialization.json.JsonElement
5+
import kotlinx.serialization.json.JsonObject
6+
import kotlinx.serialization.json.JsonPrimitive
7+
8+
/**
9+
* This class is an extension to {@link JsonElementBuilders kotlinx.serialization.json.JsonElementBuilders},
10+
* which provides a series of builder methods to help build Kotlin {@link JsonElement kotlinx.serialization.json.JsonElement}.
11+
* The builders in this class is merely a wrapper but with methods that brings Java compatibility.
12+
* It's strongly recommended to remain using Kotlin's {@link JsonElementBuilders kotlinx.serialization.json.JsonElementBuilders}
13+
* in a kotlin based project.
14+
*/
15+
class Builders {
16+
17+
companion object {
18+
19+
/**
20+
* Builder function that takes a lambda (a Function in Java) to build a Kotlin JsonObject
21+
* @param action a lambda expression or a Function in Java
22+
* @return a Kotlin JsonObject
23+
*/
24+
@JvmStatic
25+
fun buildJsonObjectFunc(action: JsonObjectBuilder.() -> Unit): JsonObject {
26+
val builder = JsonObjectBuilder()
27+
builder.action()
28+
return builder.build()
29+
}
30+
31+
/**
32+
* Builder function that takes a Consumer in Java to build a Kotlin JsonObject. This method
33+
* is only available to API 24 or above in Android. If below 24, please consider to use
34+
* @see buildJsonObjectFunc
35+
* @param action a Consumer in Java
36+
* @return a Kotlin JsonObject
37+
*/
38+
@JvmStatic
39+
@Suppress("NewApi")
40+
fun buildJsonObject(action: java.util.function.Consumer<in JsonObjectBuilder>): JsonObject =
41+
buildJsonObjectFunc(action::accept)
42+
43+
/**
44+
* Builder function that takes a lambda (a Function in Java) to build a Kotlin JsonArray
45+
* @param action a lambda expression or a Function in Java
46+
* @return a Kotlin JsonArray
47+
*/
48+
@JvmStatic
49+
fun buildJsonArrayFunc(action: JsonArrayBuilder.() -> Unit): JsonArray {
50+
val builder = JsonArrayBuilder()
51+
builder.action()
52+
return builder.build()
53+
}
54+
55+
/**
56+
* Builder function that takes a Consumer in Java to build a Kotlin JsonArray. This method
57+
* is only available to API 24 or above in Android. If below 24, please consider to use
58+
* @see buildJsonArrayFunc
59+
* @param action a Consumer in Java
60+
* @return a Kotlin JsonArray
61+
*/
62+
@JvmStatic
63+
@Suppress("NewApi")
64+
fun buildJsonArray(action: java.util.function.Consumer<in JsonArrayBuilder>): JsonArray =
65+
buildJsonArrayFunc(action::accept)
66+
67+
}
68+
69+
/**
70+
* DSL builder for Kotlin JsonObject
71+
*/
72+
@JsonDslMarker
73+
class JsonObjectBuilder {
74+
private val content: MutableMap<String, JsonElement> = linkedMapOf()
75+
76+
/**
77+
* add a JsonElement to current JsonObject with a given key.
78+
* returns the builder instance
79+
*/
80+
fun put(key: String, element: JsonElement): JsonObjectBuilder = apply { content[key] = element }
81+
82+
/**
83+
* add a boolean value to current JsonObject with a given key.
84+
* returns the builder instance
85+
*/
86+
fun put(key: String, value: Boolean?): JsonObjectBuilder = apply { put(key, JsonPrimitive(value)) }
87+
88+
/**
89+
* add a numeric value to current JsonObject with a given key.
90+
* returns the builder instance
91+
*/
92+
fun put(key: String, value: Number?) : JsonObjectBuilder = apply { put(key, JsonPrimitive(value)) }
93+
94+
/**
95+
* add a string to current JsonObject with a given key.
96+
* returns the builder instance
97+
*/
98+
fun put(key: String, value: String?) : JsonObjectBuilder = apply { put(key, JsonPrimitive(value)) }
99+
100+
/**
101+
* add another JsonObject to current JsonObject with a given key. the other JsonObject is
102+
* built through a Consumer in Java
103+
* returns the builder instance
104+
*/
105+
fun putJsonObject(key: String, action: java.util.function.Consumer<in JsonObjectBuilder>): JsonObjectBuilder = apply{ put(key, buildJsonObject(action)) }
106+
107+
/**
108+
* add a JsonArray to current JsonObject with a given key. the JsonArray is built through a
109+
* Consumer in Java
110+
* returns the builder instance
111+
*/
112+
fun putJsonArray(key: String, action: java.util.function.Consumer<in JsonArrayBuilder>): JsonObjectBuilder = apply{ put(key, buildJsonArray(action)) }
113+
114+
/**
115+
* build the content in JsonObject form
116+
*/
117+
internal fun build(): JsonObject = JsonObject(content)
118+
}
119+
120+
/**
121+
* add another JsonObject to current JsonObject with a given key. the other JsonObject is
122+
* built through a lambda expression or a Function in Java
123+
* returns the builder instance
124+
*/
125+
fun JsonObjectBuilder.putJsonObject(key: String, action: JsonObjectBuilder.() -> Unit): JsonObjectBuilder = apply{ put(key, buildJsonObject(action)) }
126+
127+
/**
128+
* add a JsonArray to current JsonObject with a given key. the JsonArray is built through a
129+
* lambda expression or a Function in Java
130+
* returns the builder instance
131+
*/
132+
fun JsonObjectBuilder.putJsonArray(key: String, action: JsonArrayBuilder.() -> Unit): JsonObjectBuilder = apply{ put(key, buildJsonArray(action)) }
133+
134+
/**
135+
* DSL builder for Kotlin JsonArray
136+
*/
137+
@JsonDslMarker
138+
class JsonArrayBuilder {
139+
private val content: MutableList<JsonElement> = mutableListOf()
140+
141+
/**
142+
* add a JsonElement to current JsonArray.
143+
* returns the builder instance
144+
*/
145+
fun add(element: JsonElement): JsonArrayBuilder = apply { content += element }
146+
147+
/**
148+
* add a boolean value to current JsonArray.
149+
* returns the builder instance
150+
*/
151+
fun add(element: Boolean?): JsonArrayBuilder = apply { add(JsonPrimitive(element)) }
152+
153+
/**
154+
* add a numeric value to current JsonArray.
155+
* returns the builder instance
156+
*/
157+
fun add(element: Number?): JsonArrayBuilder = apply { add(JsonPrimitive(element)) }
158+
159+
/**
160+
* add a string to current JsonArray.
161+
* returns the builder instance
162+
*/
163+
fun add(element: String?): JsonArrayBuilder = apply { add(JsonPrimitive(element)) }
164+
165+
/**
166+
* add a JsonObject to current JsonArray.the JsonObject is
167+
* built through a Consumer in Java
168+
* returns the builder instance
169+
*/
170+
fun addJsonObject(action: java.util.function.Consumer<in JsonObjectBuilder>): JsonArrayBuilder = apply{ add(buildJsonObject(action)) }
171+
172+
/**
173+
* add another JsonArray to current JsonArray.the other JsonArray is
174+
* built through a Consumer in Java
175+
* returns the builder instance
176+
*/
177+
fun addJsonArray(action: java.util.function.Consumer<in JsonArrayBuilder>): JsonArrayBuilder = apply{ add(buildJsonArray(action)) }
178+
179+
/**
180+
* build the content in JsonArray form
181+
*/
182+
internal fun build(): JsonArray = JsonArray(content)
183+
}
184+
185+
/**
186+
* add a JsonObject to current JsonArray. the JsonObject is
187+
* built through a lambda expression or a Function in Java
188+
* returns the builder instance
189+
*/
190+
fun JsonArrayBuilder.addJsonObject(action: JsonObjectBuilder.() -> Unit): JsonArrayBuilder = apply{ add(buildJsonObject(action)) }
191+
192+
/**
193+
* add another JsonArray to current JsonArray. the other JsonArray is
194+
* built through a lambda expression or a Function in Java
195+
* returns the builder instance
196+
*/
197+
fun JsonArrayBuilder.addJsonArray(action: JsonArrayBuilder.() -> Unit): JsonArrayBuilder = apply{ add(buildJsonArray(action)) }
198+
199+
@DslMarker
200+
internal annotation class JsonDslMarker
201+
}

0 commit comments

Comments
 (0)