diff --git a/.pubnub.yml b/.pubnub.yml
index 81fb52b57..907e1d764 100644
--- a/.pubnub.yml
+++ b/.pubnub.yml
@@ -1,9 +1,9 @@
name: java
-version: 6.4.3
+version: 6.4.4
schema: 1
scm: github.com/pubnub/java
files:
- - build/libs/pubnub-gson-6.4.3-all.jar
+ - build/libs/pubnub-gson-6.4.4-all.jar
sdks:
-
type: library
@@ -23,8 +23,8 @@ sdks:
-
distribution-type: library
distribution-repository: maven
- package-name: pubnub-gson-6.4.3
- location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-gson/6.4.3/pubnub-gson-6.4.3.jar
+ package-name: pubnub-gson-6.4.4
+ location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-gson/6.4.4/pubnub-gson-6.4.4.jar
supported-platforms:
supported-operating-systems:
Android:
@@ -100,11 +100,11 @@ sdks:
license-url: https://github.com/google/gson/blob/gson-parent-2.9.0/LICENSE
is-required: Required
-
- name: jackson-databind
- min-version: 2.14.2
- location: https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.14.2/jackson-databind-2.14.2.jar
- license: Apache License, Version 2.0
- license-url: hhttps://github.com/FasterXML/jackson-databind/blob/jackson-databind-2.14.2/README.md
+ name: cbor
+ min-version: "0.9"
+ location: https://repo.maven.apache.org/maven2/co/nstant/in/cbor/0.9
+ license: The Apache Software License, Version 2.0
+ license-url: https://www.apache.org/licenses/LICENSE-2.0.txt
is-required: Required
-
name: json
@@ -115,6 +115,11 @@ sdks:
is-required: Required
changelog:
+ - date: 2023-11-30
+ version: v6.4.4
+ changes:
+ - type: bug
+ text: "Bring back compatibility with Android 6+ by removing the Jackson library dependency."
- date: 2023-11-28
version: v6.4.3
changes:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f0226aefc..6fb559739 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## v6.4.4
+November 30 2023
+
+#### Fixed
+- Bring back compatibility with Android 6+ by removing the Jackson library dependency.
+
## v6.4.3
November 28 2023
diff --git a/README.md b/README.md
index 844442896..a571cd500 100644
--- a/README.md
+++ b/README.md
@@ -22,13 +22,13 @@ You will need the publish and subscribe keys to authenticate your app. Get your
com.pubnub
pubnub-gson
- 6.4.3
+ 6.4.4
```
* for Gradle, add the following dependency in your `gradle.build`:
```groovy
- implementation 'com.pubnub:pubnub-gson:6.4.3'
+ implementation 'com.pubnub:pubnub-gson:6.4.4'
```
2. Configure your keys:
diff --git a/build.gradle b/build.gradle
index c3198607c..42388c3ee 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,7 +10,7 @@ plugins {
}
group = 'com.pubnub'
-version = '6.4.3'
+version = '6.4.4'
description = """"""
@@ -56,8 +56,8 @@ dependencies {
implementation group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.6.2'
// cbor
- implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
- implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.14.2'
+ implementation 'co.nstant.in:cbor:0.9'
+
implementation 'org.jetbrains:annotations:23.0.0'
diff --git a/gradle.properties b/gradle.properties
index 827b176fc..abe45b364 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -3,7 +3,7 @@ SONATYPE_HOST=DEFAULT
SONATYPE_AUTOMATIC_RELEASE=true
GROUP=com.pubnub
POM_ARTIFACT_ID=pubnub-gson
-VERSION_NAME=6.4.3
+VERSION_NAME=6.4.4
POM_PACKAGING=jar
POM_NAME=PubNub Java SDK
diff --git a/src/main/java/com/pubnub/api/PubNub.java b/src/main/java/com/pubnub/api/PubNub.java
index bf1a42c29..1928b77e0 100644
--- a/src/main/java/com/pubnub/api/PubNub.java
+++ b/src/main/java/com/pubnub/api/PubNub.java
@@ -105,7 +105,7 @@ public class PubNub {
private static final int TIMESTAMP_DIVIDER = 1000;
private static final int MAX_SEQUENCE = 65535;
- private static final String SDK_VERSION = "6.4.3";
+ private static final String SDK_VERSION = "6.4.4";
private final ListenerManager listenerManager;
private final StateManager stateManager;
diff --git a/src/main/java/com/pubnub/api/endpoints/files/PublishFileMessage.java b/src/main/java/com/pubnub/api/endpoints/files/PublishFileMessage.java
index 63c290817..5c335756e 100644
--- a/src/main/java/com/pubnub/api/endpoints/files/PublishFileMessage.java
+++ b/src/main/java/com/pubnub/api/endpoints/files/PublishFileMessage.java
@@ -86,7 +86,7 @@ protected void validateParams() throws PubNubException {
@Override
protected Call> doWork(Map baseParams) throws PubNubException {
- String stringifiedMessage = mapper.toJsonUsinJackson(new FileUploadNotification(this.message, pnFile));
+ String stringifiedMessage = mapper.toJson(new FileUploadNotification(this.message, pnFile));
String messageAsString;
CryptoModule cryptoModule = getPubnub().getCryptoModule();
if (cryptoModule != null) {
@@ -99,7 +99,7 @@ protected Call> doWork(Map baseParams) throws PubNu
final HashMap params = new HashMap<>(baseParams);
if (meta != null) {
- String stringifiedMeta = mapper.toJsonUsinJackson(meta);
+ String stringifiedMeta = mapper.toJson(meta);
stringifiedMeta = PubNubUtil.urlEncode(stringifiedMeta);
params.put("meta", stringifiedMeta);
}
diff --git a/src/main/java/com/pubnub/api/managers/MapperManager.java b/src/main/java/com/pubnub/api/managers/MapperManager.java
index 6d214cce5..94b6ea47f 100644
--- a/src/main/java/com/pubnub/api/managers/MapperManager.java
+++ b/src/main/java/com/pubnub/api/managers/MapperManager.java
@@ -1,7 +1,5 @@
package com.pubnub.api.managers;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
@@ -29,7 +27,9 @@
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
public class MapperManager {
@@ -38,8 +38,6 @@ public class MapperManager {
@Getter
private final Converter.Factory converterFactory;
- private final ObjectMapper jacksonObjectMapper = new ObjectMapper();
-
public MapperManager() {
TypeAdapter booleanAsIntAdapter = getBooleanTypeAdapter();
@@ -150,7 +148,15 @@ public JsonElement toJsonTree(Object object) {
public String toJson(Object input) throws PubNubException {
try {
- return this.objectMapper.toJson(input);
+ if (input instanceof List && input.getClass().isAnonymousClass()) {
+ return this.objectMapper.toJson(input, List.class);
+ } else if (input instanceof Map && input.getClass().isAnonymousClass()) {
+ return this.objectMapper.toJson(input, Map.class);
+ } else if (input instanceof Set && input.getClass().isAnonymousClass()) {
+ return this.objectMapper.toJson(input, Set.class);
+ } else {
+ return this.objectMapper.toJson(input);
+ }
} catch (JsonParseException e) {
throw PubNubException.builder()
.pubnubError(PubNubErrorBuilder.PNERROBJ_JSON_ERROR)
@@ -160,18 +166,6 @@ public String toJson(Object input) throws PubNubException {
}
}
- public String toJsonUsinJackson(Object input) throws PubNubException {
- try {
- return this.jacksonObjectMapper.writeValueAsString(input);
- } catch (JsonProcessingException e) {
- throw PubNubException.builder()
- .pubnubError(PubNubErrorBuilder.PNERROBJ_JSON_ERROR)
- .errormsg(e.getMessage())
- .cause(e)
- .build();
- }
- }
-
@NotNull
private TypeAdapter getBooleanTypeAdapter() {
return new TypeAdapter() {
diff --git a/src/main/java/com/pubnub/api/managers/token_manager/TokenParser.java b/src/main/java/com/pubnub/api/managers/token_manager/TokenParser.java
deleted file mode 100644
index 59623923e..000000000
--- a/src/main/java/com/pubnub/api/managers/token_manager/TokenParser.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.pubnub.api.managers.token_manager;
-
-import com.fasterxml.jackson.annotation.JsonSetter;
-import com.fasterxml.jackson.annotation.Nulls;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
-import com.pubnub.api.PubNubException;
-import com.pubnub.api.models.consumer.access_manager.v3.PNToken;
-import com.pubnub.api.vendor.Base64;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-
-import static com.pubnub.api.builder.PubNubErrorBuilder.PNERROBJ_INVALID_ACCESS_TOKEN;
-
-public class TokenParser {
- private final ObjectMapper mapper = objectMapper();
-
- public PNToken unwrapToken(String token) throws PubNubException {
- try {
- byte[] byteArray = Base64.decode(token.getBytes(StandardCharsets.UTF_8), Base64.URL_SAFE);
- return mapper.readValue(byteArray, PNToken.class);
- } catch (IOException e) {
- throw PubNubException.builder()
- .cause(e)
- .pubnubError(PNERROBJ_INVALID_ACCESS_TOKEN)
- .build();
- }
- }
-
- private ObjectMapper objectMapper() {
- ObjectMapper objectMapper = new ObjectMapper(new CBORFactory());
- objectMapper.configOverride(Map.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
- objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- return objectMapper;
- }
-}
diff --git a/src/main/java/com/pubnub/api/managers/token_manager/TokenParser.kt b/src/main/java/com/pubnub/api/managers/token_manager/TokenParser.kt
new file mode 100644
index 000000000..4262cc598
--- /dev/null
+++ b/src/main/java/com/pubnub/api/managers/token_manager/TokenParser.kt
@@ -0,0 +1,110 @@
+package com.pubnub.api.managers.token_manager
+
+import co.nstant.`in`.cbor.CborDecoder
+import co.nstant.`in`.cbor.model.ByteString
+import co.nstant.`in`.cbor.model.NegativeInteger
+import co.nstant.`in`.cbor.model.UnsignedInteger
+import com.pubnub.api.PubNubException
+import com.pubnub.api.builder.PubNubErrorBuilder
+import com.pubnub.api.models.consumer.access_manager.v3.PNToken
+import com.pubnub.api.vendor.Base64
+import java.math.BigInteger
+import java.nio.charset.StandardCharsets
+import kotlin.collections.Map
+import kotlin.collections.component1
+import kotlin.collections.component2
+import kotlin.collections.set
+import co.nstant.`in`.cbor.model.Map as CborMap
+
+internal class TokenParser {
+
+ private fun getException(message: String) = PubNubException(
+ message, PubNubErrorBuilder.PNERROBJ_INVALID_ACCESS_TOKEN, null, null, 0, null, null
+ )
+
+ @Throws(PubNubException::class)
+ fun unwrapToken(token: String): PNToken {
+ val byteArray = Base64.decode(token.toByteArray(StandardCharsets.UTF_8), Base64.URL_SAFE)
+ val firstElement = CborDecoder(byteArray.inputStream()).decode().firstOrNull() ?: throw getException("Empty token")
+
+ val firstLevelMap = (firstElement as? CborMap)?.toJvmMap() ?: throw getException("First element is not a map")
+ val version = firstLevelMap[VERSION_KEY]?.toString()?.toInt() ?: throw getException("Couldn't parse version")
+ val timestamp = firstLevelMap[TIMESTAMP_KEY]?.toString()?.toLong() ?: throw getException("Couldn't parse timestamp")
+ val ttl = firstLevelMap[TTL_KEY]?.toString()?.toLong() ?: throw getException("Couldn't parse ttl")
+ val resourcesValue = firstLevelMap[RESOURCES_KEY] as? Map<*, *> ?: throw getException("Resources are not present or are not map")
+ val patternsValue = firstLevelMap[PATTERNS_KEY] as? Map<*, *> ?: throw getException("Patterns are not present or are not map")
+
+ return try {
+ PNToken.of(
+ version,
+ timestamp,
+ ttl,
+ resourcesValue.toPNTokenResources(),
+ patternsValue.toPNTokenResources(),
+ firstLevelMap[AUTHORIZED_UUID_KEY]?.toString(),
+ firstLevelMap[META_KEY],
+ )
+ } catch (e: Exception) {
+ if (e is PubNubException) throw e
+ throw getException("Couldn't parse token: ${e.message}")
+ }
+ }
+
+ private fun CborMap.toJvmMap(depth: Int = 0): MutableMap {
+ if (depth > 3) {
+ throw getException("Token is too deep")
+ }
+ val result = mutableMapOf()
+ for (key in this.keys) {
+ val value = this.get(key)
+ val keyString = when (key) {
+ is ByteString -> key.bytes.toString(StandardCharsets.UTF_8)
+ else -> key.toString()
+ }
+
+ when (value) {
+ is CborMap -> result[keyString] = value.toJvmMap(depth + 1)
+ is ByteString -> result[keyString] = value.bytes
+ is List<*> -> result[keyString] = value.map { it.toString() }
+ is UnsignedInteger -> result[keyString] = value.value
+ is NegativeInteger -> result[keyString] = value.value
+ else -> result[keyString] = value.toString()
+ }
+ }
+ return result
+ }
+
+ private fun Map<*, *>.toMapOfStringToInt(): Map {
+ return mapNotNull { (k, v) ->
+ when (v) {
+ is BigInteger -> k.toString() to v.toInt()
+ else -> v.toString().toIntOrNull()?.let { k.toString() to it }
+ }
+ }.toMap()
+ }
+
+ private fun Map<*, *>.toPNTokenResources(): PNToken.PNTokenResources {
+ val channels = (this[CHANNELS_KEY] as? Map<*, *>)?.toMapOfStringToInt() ?: emptyMap()
+ val groups = (this[GROUPS_KEY] as? Map<*, *>)?.toMapOfStringToInt() ?: emptyMap()
+ val uuids = (this[UUIDS_KEY] as? Map<*, *>)?.toMapOfStringToInt() ?: emptyMap()
+
+ return PNToken.PNTokenResources.of(
+ channels.mapValues { (_, v) -> PNToken.PNResourcePermissions.of(v) },
+ groups.mapValues { (_, v) -> PNToken.PNResourcePermissions.of(v) },
+ uuids.mapValues { (_, v) -> PNToken.PNResourcePermissions.of(v) }
+ )
+ }
+
+ companion object {
+ private const val VERSION_KEY = "v"
+ private const val TIMESTAMP_KEY = "t"
+ private const val TTL_KEY = "ttl"
+ private const val AUTHORIZED_UUID_KEY = "uuid"
+ private const val RESOURCES_KEY = "res"
+ private const val PATTERNS_KEY = "pat"
+ private const val META_KEY = "meta"
+ private const val CHANNELS_KEY = "chan"
+ private const val GROUPS_KEY = "grp"
+ private const val UUIDS_KEY = "uuid"
+ }
+}
diff --git a/src/main/java/com/pubnub/api/models/consumer/access_manager/v3/PNToken.java b/src/main/java/com/pubnub/api/models/consumer/access_manager/v3/PNToken.java
index 15e1e4a44..8f18d25f1 100644
--- a/src/main/java/com/pubnub/api/models/consumer/access_manager/v3/PNToken.java
+++ b/src/main/java/com/pubnub/api/models/consumer/access_manager/v3/PNToken.java
@@ -1,8 +1,5 @@
package com.pubnub.api.models.consumer.access_manager.v3;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
import com.pubnub.api.models.TokenBitmask;
import lombok.Data;
import lombok.NonNull;
@@ -10,7 +7,6 @@
import java.util.Map;
@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
public class PNToken {
private final int version;
private final long timestamp;
@@ -22,20 +18,18 @@ public class PNToken {
@NonNull
private final PNTokenResources patterns;
- @JsonCreator
public static PNToken of(
- @JsonProperty("v") final int v,
- @JsonProperty("t") final long t,
- @JsonProperty("ttl") final long ttl,
- @JsonProperty("res") final PNTokenResources res,
- @JsonProperty("pat") final PNTokenResources pat,
- @JsonProperty("uuid") final String uuid,
- @JsonProperty("meta") final Object meta) {
+ final int v,
+ final long t,
+ final long ttl,
+ final PNTokenResources res,
+ final PNTokenResources pat,
+ final String uuid,
+ final Object meta) {
return new PNToken(v, t, ttl, uuid, meta, res, pat);
}
@Data
- @JsonIgnoreProperties(ignoreUnknown = true)
public static class PNTokenResources {
@NonNull
private final Map channels;
@@ -44,10 +38,9 @@ public static class PNTokenResources {
@NonNull
private final Map uuids;
- @JsonCreator
- public static PNTokenResources of(@JsonProperty("chan") final Map chan,
- @JsonProperty("grp") final Map grp,
- @JsonProperty("uuid") final Map uuid) {
+ public static PNTokenResources of(final Map chan,
+ final Map grp,
+ final Map uuid) {
return new PNTokenResources(chan, grp, uuid);
}
@@ -63,7 +56,6 @@ public static class PNResourcePermissions {
private final boolean update;
private final boolean join;
- @JsonCreator
public static PNResourcePermissions of(int grant) {
return new PNResourcePermissions(
(grant & TokenBitmask.READ) != 0,
diff --git a/src/test/java/com/pubnub/api/PubNubTest.java b/src/test/java/com/pubnub/api/PubNubTest.java
index cf039f361..8a9350716 100644
--- a/src/test/java/com/pubnub/api/PubNubTest.java
+++ b/src/test/java/com/pubnub/api/PubNubTest.java
@@ -100,7 +100,7 @@ public void getVersionAndTimeStamp() {
pubnub = new PubNub(pnConfiguration);
String version = pubnub.getVersion();
int timeStamp = pubnub.getTimestamp();
- Assert.assertEquals("6.4.3", version);
+ Assert.assertEquals("6.4.4", version);
Assert.assertTrue(timeStamp > 0);
}
diff --git a/src/test/java/com/pubnub/api/managers/MapperManagerTest.java b/src/test/java/com/pubnub/api/managers/MapperManagerTest.java
new file mode 100644
index 000000000..7d1f62a70
--- /dev/null
+++ b/src/test/java/com/pubnub/api/managers/MapperManagerTest.java
@@ -0,0 +1,83 @@
+package com.pubnub.api.managers;
+
+import com.pubnub.api.PubNubException;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MapperManagerTest {
+
+ @Test
+ void toJson_anonymousList() throws PubNubException {
+ MapperManager mapperManager = new MapperManager();
+
+ String expected = "[1,2,3]";
+ List anonList = new ArrayList(){{
+ add(1);
+ add(2);
+ add(3);
+ }};
+ List regularList = new ArrayList();
+ regularList.add(1);
+ regularList.add(2);
+ regularList.add(3);
+
+
+ String json1 = mapperManager.toJson(anonList);
+ String json2 = mapperManager.toJson(regularList);
+
+
+ assertEquals(expected, json1);
+ assertEquals(expected, json2);
+ }
+
+ @Test
+ void toJson_anonymousMap() throws PubNubException {
+ MapperManager mapperManager = new MapperManager();
+ String expected = "{\"city\":\"Toronto\"}";
+
+ HashMap anonMap = new HashMap() {{
+ put("city", "Toronto");
+ }};
+
+ HashMap regularMap = new HashMap();
+ regularMap.put("city", "Toronto");
+
+
+ String json1 = mapperManager.toJson(anonMap);
+ String json2 = mapperManager.toJson(regularMap);
+ assertEquals(expected, json1);
+ assertEquals(expected, json2);
+ }
+
+ @Test
+ void toJson_anonymousSet() throws PubNubException {
+ MapperManager mapperManager = new MapperManager();
+
+ String expected = "[1,2,3]";
+ Set anonSet = new HashSet(){{
+ add(1);
+ add(2);
+ add(3);
+ }};
+ Set regularSet = new HashSet();
+ regularSet.add(1);
+ regularSet.add(2);
+ regularSet.add(3);
+
+
+ String json1 = mapperManager.toJson(anonSet);
+ String json2 = mapperManager.toJson(regularSet);
+
+
+ assertEquals(expected, json1);
+ assertEquals(expected, json2);
+ }
+
+}
\ No newline at end of file