From def45c7402cc5cfeee3c55b5fe059214acd47a74 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Wed, 5 Nov 2025 21:47:58 +0700 Subject: [PATCH] Migrate data storage from Couchbase to Redis Replaces Couchbase with Redis for data persistence, updating environment variables, Docker Compose files, and repository logic. Removes Couchbase and Jackson dependencies, introduces Gson for JSON serialization, and refactors models and repositories to support Redis. Adds utility classes for Redis and Gson, and updates tests and scrapers to use Gson. --- .env.example | 7 +- build.gradle.kts | 6 +- compose.dev.yml | 18 ++--- compose.yml | 34 +------- .../api/apple/AppStoreScraper.java | 12 +-- .../api/google/GooglePlayScraper.java | 12 +-- .../miti99/storescraperbot/config/Config.java | 6 +- .../storescraperbot/constant/Constant.java | 5 ++ .../storescraperbot/model/AbstractModel.java | 7 +- .../miti99/storescraperbot/model/Admin.java | 4 + .../storescraperbot/model/AppleApp.java | 4 + .../storescraperbot/model/GoogleApp.java | 4 + .../miti99/storescraperbot/model/Group.java | 4 + .../repository/AbstractRepository.java | 59 +++++++------- .../repository/AdminRepository.java | 6 +- .../repository/AppleAppRepository.java | 5 -- .../repository/GoogleAppRepository.java | 5 -- .../repository/GroupRepository.java | 4 - .../storescraperbot/util/CouchbaseUtil.java | 81 ------------------- .../miti99/storescraperbot/util/GsonUtil.java | 18 +++++ .../storescraperbot/util/JacksonUtil.java | 47 ----------- .../storescraperbot/util/RedisUtil.java | 17 ++++ .../api/apple/AppStoreScraperTest.java | 6 +- .../api/google/GooglePlayScraperTest.java | 6 +- 24 files changed, 120 insertions(+), 257 deletions(-) create mode 100644 src/main/java/com/miti99/storescraperbot/constant/Constant.java delete mode 100644 src/main/java/com/miti99/storescraperbot/util/CouchbaseUtil.java create mode 100644 src/main/java/com/miti99/storescraperbot/util/GsonUtil.java delete mode 100644 src/main/java/com/miti99/storescraperbot/util/JacksonUtil.java create mode 100644 src/main/java/com/miti99/storescraperbot/util/RedisUtil.java diff --git a/.env.example b/.env.example index ca95628..bf790bb 100644 --- a/.env.example +++ b/.env.example @@ -1,11 +1,8 @@ # Copy this file to .env and customize the values for your environment # cp .env.example .env -# Couchbase configuration -COUCHBASE_CONNECTION_STRING=couchbase://localhost -COUCHBASE_USERNAME=admin -COUCHBASE_PASSWORD=your_password_here -COUCHBASE_BUCKET_NAME=store_scraper +# Redis configuration +REDIS_URL=localhost:6379 # Telegram Bot configuration TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here diff --git a/build.gradle.kts b/build.gradle.kts index e3451cd..9bb2710 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,13 +22,15 @@ configurations { dependencies { annotationProcessor("org.projectlombok:lombok:1.18.36") - implementation("com.couchbase.client:java-client:3.4.11") + implementation("com.google.code.gson:gson:2.11.0") + implementation("com.google.guava:guava:33.4.0-jre") + implementation("org.apache.commons:commons-text:1.13.0") implementation("org.apache.logging.log4j:log4j-core:2.24.3") implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.24.3") - // implementation("org.telegram:telegrambots-abilities:8.0.0") implementation("org.telegram:telegrambots-client:8.0.0") implementation("org.telegram:telegrambots-extensions:8.0.0") implementation("org.telegram:telegrambots-longpolling:8.0.0") + implementation("redis.clients:jedis:5.2.0") testAnnotationProcessor("org.projectlombok:lombok:1.18.36") testImplementation(platform("org.junit:junit-bom:5.11.4")) diff --git a/compose.dev.yml b/compose.dev.yml index 4a2e505..3f4d356 100644 --- a/compose.dev.yml +++ b/compose.dev.yml @@ -1,18 +1,12 @@ services: - couchbase: - image: couchbase:community-7.6.2 - env_file: - - .env + redis: + image: redis:7.2-alpine ports: - - "8091-8097:8091-8097" - - "9123:9123" - - "11207:11207" - - "11210:11210" - - "11280:11280" - - "18091-18097:18091-18097" + - "6379:6379" volumes: - - couchbase_data:/opt/couchbase/var + - redis_data:/data restart: unless-stopped + command: redis-server --appendonly yes volumes: - couchbase_data: + redis_data: \ No newline at end of file diff --git a/compose.yml b/compose.yml index 2a951d5..8b86a6e 100644 --- a/compose.yml +++ b/compose.yml @@ -2,36 +2,6 @@ services: server: build: context: . - env_file: - - .env - depends_on: - - couchbase - hostname: couchbase - networks: - - internal - command: > - bash -c "couchbase-server -- -advertised_hostname couchbase" - couchbase: - image: couchbase:community-7.6.2 - # env_file: - # - .env - # ports: # Enable these ports if you need - # - "8091-8097:8091-8097" - # - "9123:9123" - # - "11207:11207" - # - "11210:11210" - # - "11280:11280" - # - "18091-18097:18091-18097" - volumes: - - couchbase_data:/opt/couchbase/var - restart: unless-stopped - networks: - - internal - -volumes: - couchbase_data: - -networks: - internal: - driver: bridge +# If you need redis, add redis service +# Check compose.dev.yml for example diff --git a/src/main/java/com/miti99/storescraperbot/api/apple/AppStoreScraper.java b/src/main/java/com/miti99/storescraperbot/api/apple/AppStoreScraper.java index a023f43..1e7370b 100644 --- a/src/main/java/com/miti99/storescraperbot/api/apple/AppStoreScraper.java +++ b/src/main/java/com/miti99/storescraperbot/api/apple/AppStoreScraper.java @@ -1,10 +1,8 @@ package com.miti99.storescraperbot.api.apple; -import com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpHeaderNames; -import com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpHeaderValues; import com.miti99.storescraperbot.api.apple.request.AppleAppRequest; import com.miti99.storescraperbot.api.apple.response.AppleAppResponse; -import com.miti99.storescraperbot.util.JacksonUtil; +import com.miti99.storescraperbot.util.GsonUtil; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpClient.Redirect; @@ -22,10 +20,8 @@ public class AppStoreScraper { HttpRequest.newBuilder() .uri(URI.create(BASE_URL + "/app")) // .timeout(Duration.ofMillis(TIMEOUT)) - .header( - HttpHeaderNames.CONTENT_TYPE.toString(), - HttpHeaderValues.APPLICATION_JSON.toString()) - .POST(BodyPublishers.ofString(JacksonUtil.writeValueAsString(request))) + .header("Content-Type", "application/json") + .POST(BodyPublishers.ofString(GsonUtil.toJson(request))) .build(); var body = @@ -35,6 +31,6 @@ public class AppStoreScraper { .build() .send(httpRequest, BodyHandlers.ofString()) .body(); - return JacksonUtil.readValue(body, AppleAppResponse.class); + return GsonUtil.fromJson(body, AppleAppResponse.class); } } diff --git a/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java b/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java index 4b12fc4..02b3c09 100644 --- a/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java +++ b/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java @@ -1,10 +1,8 @@ package com.miti99.storescraperbot.api.google; -import com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpHeaderNames; -import com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpHeaderValues; import com.miti99.storescraperbot.api.google.request.GoogleAppRequest; import com.miti99.storescraperbot.api.google.response.GoogleAppResponse; -import com.miti99.storescraperbot.util.JacksonUtil; +import com.miti99.storescraperbot.util.GsonUtil; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpClient.Redirect; @@ -22,10 +20,8 @@ public class GooglePlayScraper { HttpRequest.newBuilder() .uri(URI.create(BASE_URL + "/app")) // .timeout(Duration.ofMillis(TIMEOUT)) - .header( - HttpHeaderNames.CONTENT_TYPE.toString(), - HttpHeaderValues.APPLICATION_JSON.toString()) - .POST(BodyPublishers.ofString(JacksonUtil.writeValueAsString(request))) + .header("Content-Type", "application/json") + .POST(BodyPublishers.ofString(GsonUtil.toJson(request))) .build(); var body = @@ -35,6 +31,6 @@ public class GooglePlayScraper { .build() .send(httpRequest, BodyHandlers.ofString()) .body(); - return JacksonUtil.readValue(body, GoogleAppResponse.class); + return GsonUtil.fromJson(body, GoogleAppResponse.class); } } diff --git a/src/main/java/com/miti99/storescraperbot/config/Config.java b/src/main/java/com/miti99/storescraperbot/config/Config.java index 2ecc0d6..e89db87 100644 --- a/src/main/java/com/miti99/storescraperbot/config/Config.java +++ b/src/main/java/com/miti99/storescraperbot/config/Config.java @@ -8,11 +8,7 @@ import java.util.Set; import java.util.stream.Collectors; public class Config { - public static final String COUCHBASE_CONNECTION_STRING = - System.getenv("COUCHBASE_CONNECTION_STRING"); - public static final String COUCHBASE_USERNAME = System.getenv("COUCHBASE_USERNAME"); - public static final String COUCHBASE_PASSWORD = System.getenv("COUCHBASE_PASSWORD"); - public static final String COUCHBASE_BUCKET_NAME = System.getenv("COUCHBASE_BUCKET_NAME"); + public static final String REDIS_URL = System.getenv("REDIS_URL"); public static final String TELEGRAM_BOT_TOKEN = System.getenv("TELEGRAM_BOT_TOKEN"); public static final String TELEGRAM_BOT_USERNAME = System.getenv("TELEGRAM_BOT_USERNAME"); diff --git a/src/main/java/com/miti99/storescraperbot/constant/Constant.java b/src/main/java/com/miti99/storescraperbot/constant/Constant.java new file mode 100644 index 0000000..4a7fee3 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/constant/Constant.java @@ -0,0 +1,5 @@ +package com.miti99.storescraperbot.constant; + +public class Constant { + public static final String APP_NAME = "store_scraper_bot"; +} diff --git a/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java b/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java index 44b3586..6659b30 100644 --- a/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java +++ b/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java @@ -1,11 +1,14 @@ package com.miti99.storescraperbot.model; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; import lombok.Getter; +import lombok.RequiredArgsConstructor; @Getter +@RequiredArgsConstructor public abstract class AbstractModel { + final K key; - @JsonProperty("class") + @SerializedName("class") protected String clazz = getClass().getSimpleName(); } diff --git a/src/main/java/com/miti99/storescraperbot/model/Admin.java b/src/main/java/com/miti99/storescraperbot/model/Admin.java index fec1850..49fd54b 100644 --- a/src/main/java/com/miti99/storescraperbot/model/Admin.java +++ b/src/main/java/com/miti99/storescraperbot/model/Admin.java @@ -10,4 +10,8 @@ import lombok.Setter; @Setter public class Admin extends AbstractModel { List groups = new ArrayList<>(); + + public Admin(String key) { + super(key); + } } diff --git a/src/main/java/com/miti99/storescraperbot/model/AppleApp.java b/src/main/java/com/miti99/storescraperbot/model/AppleApp.java index cedeb03..3463b99 100644 --- a/src/main/java/com/miti99/storescraperbot/model/AppleApp.java +++ b/src/main/java/com/miti99/storescraperbot/model/AppleApp.java @@ -9,4 +9,8 @@ import lombok.Setter; public class AppleApp extends AbstractModel { long cacheTime; AppleAppResponse rawResponse; + + public AppleApp(String key) { + super(key); + } } diff --git a/src/main/java/com/miti99/storescraperbot/model/GoogleApp.java b/src/main/java/com/miti99/storescraperbot/model/GoogleApp.java index e18f7dd..a6d7903 100644 --- a/src/main/java/com/miti99/storescraperbot/model/GoogleApp.java +++ b/src/main/java/com/miti99/storescraperbot/model/GoogleApp.java @@ -9,4 +9,8 @@ import lombok.Setter; public class GoogleApp extends AbstractModel { long cacheTime; GoogleAppResponse rawResponse; + + public GoogleApp(String key) { + super(key); + } } diff --git a/src/main/java/com/miti99/storescraperbot/model/Group.java b/src/main/java/com/miti99/storescraperbot/model/Group.java index 70edef3..609aea5 100644 --- a/src/main/java/com/miti99/storescraperbot/model/Group.java +++ b/src/main/java/com/miti99/storescraperbot/model/Group.java @@ -11,6 +11,10 @@ import lombok.Setter; public class Group extends AbstractModel { List apps; + public Group(Long key) { + super(key); + } + public static class App { String appId; AppType type; diff --git a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java index adffca0..5be7b34 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java @@ -1,29 +1,32 @@ package com.miti99.storescraperbot.repository; -import com.couchbase.client.java.Collection; +import com.google.common.base.CaseFormat; import com.miti99.storescraperbot.config.Config; +import com.miti99.storescraperbot.constant.Constant; import com.miti99.storescraperbot.model.AbstractModel; -import com.miti99.storescraperbot.util.CouchbaseUtil; +import com.miti99.storescraperbot.util.GsonUtil; +import com.miti99.storescraperbot.util.RedisUtil; import java.lang.reflect.ParameterizedType; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import lombok.extern.log4j.Log4j2; -/** 1 repository = 1 collection */ @Log4j2 +@NoArgsConstructor(access = AccessLevel.PROTECTED) public abstract class AbstractRepository> { - public static final String SEPARATOR = "_"; - // protected static ObjectMapper objectMapper = new ObjectMapper(); + public static final String SEPARATOR = ":"; + protected final Class classK = getKeyClass(); protected final Class classV = getDataClass(); - // protected final JavaType type = objectMapper.getTypeFactory().constructType(classV); - protected final String scopeName = Config.ENV.name().toLowerCase(); - protected final String collectionName; + protected final String prefix = + String.join( + SEPARATOR, + Constant.APP_NAME, + Config.ENV.name().toLowerCase(), + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, classV.getSimpleName())); - protected AbstractRepository(String collectionName) { - this.collectionName = collectionName.toLowerCase(); - CouchbaseUtil.createCollection(scopeName, collectionName); - } - - public Collection collection() { - return CouchbaseUtil.BUCKET.scope(scopeName).collection(collectionName); + protected Class getKeyClass() { + return (Class) + ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } /** @@ -43,7 +46,7 @@ public abstract class AbstractRepository> { if (exist(key)) { return; } - V data = classV.getDeclaredConstructor().newInstance(); + V data = classV.getDeclaredConstructor(classK).newInstance(key); save(key, data); } catch (Exception e) { log.error("Error while initializing data", e); @@ -51,13 +54,14 @@ public abstract class AbstractRepository> { } protected String getDatabaseKey(K key) { - return String.join(SEPARATOR, classV.getSimpleName(), String.valueOf(key)); + return String.join(SEPARATOR, prefix, String.valueOf(key)); } public void save(K key, V data) { var databaseKey = getDatabaseKey(key); - try { - collection().upsert(databaseKey, data); + try (var jedis = RedisUtil.getJedis()) { + var json = GsonUtil.toJson(data); + jedis.set(databaseKey, json); } catch (Exception e) { log.error("save error - key {}, databaseKey {}", key, databaseKey, e); } @@ -65,8 +69,8 @@ public abstract class AbstractRepository> { public boolean exist(K key) { var databaseKey = getDatabaseKey(key); - try { - return collection().exists(databaseKey).exists(); + try (var jedis = RedisUtil.getJedis()) { + return jedis.exists(databaseKey); } catch (Exception e) { log.error("exist error - key {}, databaseKey {}", key, databaseKey, e); return false; @@ -75,12 +79,9 @@ public abstract class AbstractRepository> { public V load(K key) { var databaseKey = getDatabaseKey(key); - try { - var getResult = collection().get(databaseKey); - if (getResult == null) { - return null; - } - return getResult.contentAs(classV); + try (var jedis = RedisUtil.getJedis()) { + var json = jedis.get(databaseKey); + return GsonUtil.fromJson(json, classV); } catch (Exception e) { log.error("load error - key {}, databaseKey {}", key, databaseKey, e); return null; @@ -89,8 +90,8 @@ public abstract class AbstractRepository> { public void delete(K key) { var databaseKey = getDatabaseKey(key); - try { - collection().remove(databaseKey); + try (var jedis = RedisUtil.getJedis()) { + jedis.del(databaseKey); } catch (Exception e) { log.error("delete error", e); } diff --git a/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java index 03f447f..4f29514 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java @@ -2,14 +2,12 @@ package com.miti99.storescraperbot.repository; import com.miti99.storescraperbot.model.Admin; -/** - * Đây là repository chỉ chứa 1 key duy nhất, key là "" (rỗng) - */ +/** Đây là repository chỉ chứa 1 key duy nhất, key là "" (rỗng) */ public class AdminRepository extends AbstractRepository { public static final AdminRepository INSTANCE = new AdminRepository(); protected AdminRepository() { - super("admin"); + super(); } public void init() { diff --git a/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java index 913594b..d8b0ae4 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java @@ -1,12 +1,7 @@ package com.miti99.storescraperbot.repository; import com.miti99.storescraperbot.model.AppleApp; -import com.miti99.storescraperbot.model.Group; public class AppleAppRepository extends AbstractRepository { public static final AppleAppRepository INSTANCE = new AppleAppRepository(); - - protected AppleAppRepository() { - super("apple"); - } } diff --git a/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java b/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java index 2a4eaf4..8c2186f 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java @@ -1,12 +1,7 @@ package com.miti99.storescraperbot.repository; import com.miti99.storescraperbot.model.GoogleApp; -import com.miti99.storescraperbot.model.Group; public class GoogleAppRepository extends AbstractRepository { private static final GoogleAppRepository INSTANCE = new GoogleAppRepository(); - - protected GoogleAppRepository() { - super("google"); - } } diff --git a/src/main/java/com/miti99/storescraperbot/repository/GroupRepository.java b/src/main/java/com/miti99/storescraperbot/repository/GroupRepository.java index d72efde..a47798e 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/GroupRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/GroupRepository.java @@ -4,8 +4,4 @@ import com.miti99.storescraperbot.model.Group; public class GroupRepository extends AbstractRepository { public static final GroupRepository INSTANCE = new GroupRepository(); - - protected GroupRepository() { - super("group"); - } } diff --git a/src/main/java/com/miti99/storescraperbot/util/CouchbaseUtil.java b/src/main/java/com/miti99/storescraperbot/util/CouchbaseUtil.java deleted file mode 100644 index 20487f6..0000000 --- a/src/main/java/com/miti99/storescraperbot/util/CouchbaseUtil.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.miti99.storescraperbot.util; - -import static com.miti99.storescraperbot.config.Config.COUCHBASE_BUCKET_NAME; -import static com.miti99.storescraperbot.config.Config.COUCHBASE_CONNECTION_STRING; -import static com.miti99.storescraperbot.config.Config.COUCHBASE_PASSWORD; -import static com.miti99.storescraperbot.config.Config.COUCHBASE_USERNAME; - -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.Cluster; -import com.couchbase.client.java.ClusterOptions; -import com.couchbase.client.java.manager.collection.CollectionSpec; -import com.miti99.storescraperbot.config.Config; -import java.time.Duration; -import lombok.extern.log4j.Log4j2; - -@Log4j2 -public class CouchbaseUtil { - public static final Cluster CLUSTER; - public static final Bucket BUCKET; - - static { - CLUSTER = - Cluster.connect( - COUCHBASE_CONNECTION_STRING, - ClusterOptions.clusterOptions(COUCHBASE_USERNAME, COUCHBASE_PASSWORD) - .environment(env -> {})); - - BUCKET = CLUSTER.bucket(COUCHBASE_BUCKET_NAME); - BUCKET.waitUntilReady(Duration.ofSeconds(10)); - } - - public static void createScope(String scopeName) { - var collectionManager = BUCKET.collections(); - try { - boolean scopeExists = - collectionManager.getAllScopes().stream().anyMatch(s -> s.name().equals(scopeName)); - - if (!scopeExists) { - collectionManager.createScope(scopeName); - log.info("Scope created: {}", scopeName); - } else { - log.info("Scope existed: {}", scopeName); - } - } catch (Exception e) { - log.error("createScope error - scopeName: '{}'", scopeName, e); - } - } - - public static void createCollection(String scopeName, String collectionName) { - var collectionManager = BUCKET.collections(); - try { - var scopeSpecOpt = - collectionManager.getAllScopes().stream() - .filter(s -> s.name().equals(scopeName)) - .findFirst(); - if (scopeSpecOpt.isEmpty()) { - createScope(scopeName); - createCollection(scopeName, collectionName); - return; - } - - var scopeSpec = scopeSpecOpt.get(); - boolean collectionExists = - scopeSpec.collections().stream().anyMatch(c -> c.name().equals(collectionName)); - - if (!collectionExists) { - var spec = CollectionSpec.create(collectionName, scopeName); - collectionManager.createCollection(spec); - log.info("Collection created: {} in {}", collectionName, scopeName); - } else { - log.info("Collection existed: {} in {}", collectionName, scopeName); - } - } catch (Exception e) { - log.error( - "createCollection error - collectionName: '{}', scopeName: '{}'", - collectionName, - scopeName, - e); - } - } -} diff --git a/src/main/java/com/miti99/storescraperbot/util/GsonUtil.java b/src/main/java/com/miti99/storescraperbot/util/GsonUtil.java new file mode 100644 index 0000000..d8e5718 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/util/GsonUtil.java @@ -0,0 +1,18 @@ +package com.miti99.storescraperbot.util; + +import com.google.gson.Gson; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class GsonUtil { + public static final Gson GSON = new Gson(); + + public static T fromJson(String input, Class valueType) { + return GSON.fromJson(input, valueType); + } + + public static String toJson(Object input) { + return GSON.toJson(input); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/util/JacksonUtil.java b/src/main/java/com/miti99/storescraperbot/util/JacksonUtil.java deleted file mode 100644 index de46f13..0000000 --- a/src/main/java/com/miti99/storescraperbot/util/JacksonUtil.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.miti99.storescraperbot.util; - -import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.PropertyAccessor; -import com.fasterxml.jackson.core.JsonParser.Feature; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import lombok.SneakyThrows; - -public class JacksonUtil { - public static ObjectMapper MAPPER = objectMapper(); - - private static ObjectMapper objectMapper() { - var objectMapper = new ObjectMapper(); - - objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - objectMapper.disable( - SerializationFeature.FAIL_ON_EMPTY_BEANS, - SerializationFeature.INDENT_OUTPUT, - SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); - - objectMapper.enable( - DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, - DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, - DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL); - objectMapper.enable( - Feature.ALLOW_SINGLE_QUOTES, Feature.ALLOW_UNQUOTED_FIELD_NAMES, Feature.IGNORE_UNDEFINED); - objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); - - objectMapper.setSerializationInclusion(Include.NON_NULL); - objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); - - return objectMapper; - } - - @SneakyThrows - public static T readValue(String input, Class valueType) { - return MAPPER.readValue(input, valueType); - } - - @SneakyThrows - public static String writeValueAsString(Object input) { - return MAPPER.writeValueAsString(input); - } -} diff --git a/src/main/java/com/miti99/storescraperbot/util/RedisUtil.java b/src/main/java/com/miti99/storescraperbot/util/RedisUtil.java new file mode 100644 index 0000000..78143cc --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/util/RedisUtil.java @@ -0,0 +1,17 @@ +package com.miti99.storescraperbot.util; + +import static com.miti99.storescraperbot.config.Config.REDIS_URL; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class RedisUtil { + private static final JedisPool REDIS_POOL = new JedisPool(REDIS_URL); + + public static Jedis getJedis() { + return REDIS_POOL.getResource(); + } +} diff --git a/src/test/java/com/miti99/storescraperbot/api/apple/AppStoreScraperTest.java b/src/test/java/com/miti99/storescraperbot/api/apple/AppStoreScraperTest.java index 9a32b53..931b9a5 100644 --- a/src/test/java/com/miti99/storescraperbot/api/apple/AppStoreScraperTest.java +++ b/src/test/java/com/miti99/storescraperbot/api/apple/AppStoreScraperTest.java @@ -1,9 +1,7 @@ package com.miti99.storescraperbot.api.apple; -import static org.junit.jupiter.api.Assertions.*; - import com.miti99.storescraperbot.api.apple.request.AppleAppRequest; -import com.miti99.storescraperbot.util.JacksonUtil; +import com.miti99.storescraperbot.util.GsonUtil; import org.junit.jupiter.api.Test; class AppStoreScraperTest { @@ -11,6 +9,6 @@ class AppStoreScraperTest { void testApp() { var request = new AppleAppRequest("com.mpt.kvtm"); var response = AppStoreScraper.app(request); - System.out.println(JacksonUtil.writeValueAsString(response)); + System.out.println(GsonUtil.toJson(response)); } } diff --git a/src/test/java/com/miti99/storescraperbot/api/google/GooglePlayScraperTest.java b/src/test/java/com/miti99/storescraperbot/api/google/GooglePlayScraperTest.java index e9da330..26cc8b9 100644 --- a/src/test/java/com/miti99/storescraperbot/api/google/GooglePlayScraperTest.java +++ b/src/test/java/com/miti99/storescraperbot/api/google/GooglePlayScraperTest.java @@ -1,9 +1,7 @@ package com.miti99.storescraperbot.api.google; -import static org.junit.jupiter.api.Assertions.*; - import com.miti99.storescraperbot.api.google.request.GoogleAppRequest; -import com.miti99.storescraperbot.util.JacksonUtil; +import com.miti99.storescraperbot.util.GsonUtil; import org.junit.jupiter.api.Test; class GooglePlayScraperTest { @@ -11,6 +9,6 @@ class GooglePlayScraperTest { void testApp() { var request = new GoogleAppRequest("vn.kvtm.js"); var response = GooglePlayScraper.app(request); - System.out.println(JacksonUtil.writeValueAsString(response)); + System.out.println(GsonUtil.toJson(response)); } }