Add JsonUtil

This commit is contained in:
2dust
2024-09-30 14:55:51 +08:00
parent af01e2ac06
commit 1fadca8524
11 changed files with 89 additions and 61 deletions
@@ -3,12 +3,12 @@ package com.v2ray.ang.service
import android.app.Service
import android.content.Intent
import android.os.IBinder
import com.google.gson.Gson
import com.v2ray.ang.AppConfig.MSG_MEASURE_CONFIG
import com.v2ray.ang.AppConfig.MSG_MEASURE_CONFIG_CANCEL
import com.v2ray.ang.AppConfig.MSG_MEASURE_CONFIG_SUCCESS
import com.v2ray.ang.dto.ConfigResult
import com.v2ray.ang.extension.serializable
import com.v2ray.ang.util.JsonUtil
import com.v2ray.ang.util.MessageUtil
import com.v2ray.ang.util.SpeedtestUtil
import com.v2ray.ang.util.Utils
@@ -33,8 +33,8 @@ class V2RayTestService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.getIntExtra("key", 0)) {
MSG_MEASURE_CONFIG -> {
val content = intent.serializable<String>("content")
val config = Gson().fromJson(content, ConfigResult::class.java)
val content = intent.serializable<String>("content") ?: ""
val config = JsonUtil.fromJson(content, ConfigResult::class.java)
realTestScope.launch {
val result = SpeedtestUtil.realPing(config.content)
MessageUtil.sendMsg2UI(this@V2RayTestService, MSG_MEASURE_CONFIG_SUCCESS, Pair(config.guid, result))
@@ -10,13 +10,14 @@ import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.gson.Gson
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityRoutingSettingBinding
import com.v2ray.ang.dto.RulesetItem
import com.v2ray.ang.extension.toast
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
import com.v2ray.ang.util.JsonUtil
import com.v2ray.ang.util.MmkvManager
import com.v2ray.ang.util.MmkvManager.settingsStorage
import com.v2ray.ang.util.SettingsManager
@@ -141,7 +142,7 @@ class RoutingSettingActivity : BaseActivity() {
if (rulesetList.isNullOrEmpty()) {
toast(R.string.toast_failure)
} else {
Utils.setClipboard(this, Gson().toJson(rulesetList))
Utils.setClipboard(this, JsonUtil.toJson(rulesetList))
toast(R.string.toast_success)
}
true
@@ -8,13 +8,14 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import com.blacksquircle.ui.editorkit.utils.EditorTheme
import com.blacksquircle.ui.language.json.JsonLanguage
import com.google.gson.Gson
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityServerCustomConfigBinding
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.JsonUtil
import com.v2ray.ang.util.MmkvManager
import com.v2ray.ang.util.Utils
import me.drakeet.support.toast.ToastCompat
@@ -78,7 +79,7 @@ class ServerCustomConfigActivity : BaseActivity() {
}
val v2rayConfig = try {
Gson().fromJson(binding.editor.text.toString(), V2rayConfig::class.java)
JsonUtil.fromJson(binding.editor.text.toString(), V2rayConfig::class.java)
} catch (e: Exception) {
e.printStackTrace()
ToastCompat.makeText(this, "${getString(R.string.toast_malformed_josn)} ${e.cause?.message}", Toast.LENGTH_LONG).show()
@@ -4,7 +4,7 @@ import android.content.Context
import android.graphics.Bitmap
import android.text.TextUtils
import android.util.Log
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonPrimitive
import com.google.gson.JsonSerializationContext
@@ -278,34 +278,21 @@ object AngConfigManager {
&& server.contains("routing")
) {
try {
//val gson = GsonBuilder().setPrettyPrinting().create()
val gson = GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.registerTypeAdapter( // custom serialiser is needed here since JSON by default parse number as Double, core will fail to start
object : TypeToken<Double>() {}.type,
JsonSerializer { src: Double?, _: Type?, _: JsonSerializationContext? ->
JsonPrimitive(
src?.toInt()
)
}
)
.create()
val serverList: Array<Any> =
Gson().fromJson(server, Array<Any>::class.java)
JsonUtil.fromJson(server, Array<Any>::class.java)
if (serverList.isNotEmpty()) {
var count = 0
for (srv in serverList.reversed()) {
val config = ServerConfig.create(EConfigType.CUSTOM)
config.fullConfig =
Gson().fromJson(Gson().toJson(srv), V2rayConfig::class.java)
JsonUtil.fromJson(JsonUtil.toJson(srv), V2rayConfig::class.java)
config.remarks = config.fullConfig?.remarks
?: ("%04d-".format(count + 1) + System.currentTimeMillis()
.toString())
config.subscriptionId = subid
val key = MmkvManager.encodeServerConfig("", config)
MmkvManager.encodeServerRaw(key, gson.toJson(srv))
MmkvManager.encodeServerRaw(key, JsonUtil.toJsonPretty(srv))
count += 1
}
return count
@@ -318,7 +305,7 @@ object AngConfigManager {
// For compatibility
val config = ServerConfig.create(EConfigType.CUSTOM)
config.subscriptionId = subid
config.fullConfig = Gson().fromJson(server, V2rayConfig::class.java)
config.fullConfig = JsonUtil.fromJson(server, V2rayConfig::class.java)
config.remarks = config.fullConfig?.remarks ?: System.currentTimeMillis().toString()
val key = MmkvManager.encodeServerConfig("", config)
MmkvManager.encodeServerRaw(key, server)
@@ -0,0 +1,37 @@
package com.v2ray.ang.util
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonPrimitive
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type
object JsonUtil {
private var gson = Gson()
fun toJson(src: Any?): String {
return gson.toJson(src)
}
fun <T> fromJson(json: String, cls: Class<T>): T {
return gson.fromJson(json, cls)
}
fun toJsonPretty(src: Any?): String {
val gsonPre = GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.registerTypeAdapter( // custom serialiser is needed here since JSON by default parse number as Double, core will fail to start
object : TypeToken<Double>() {}.type,
JsonSerializer { src: Double?, _: Type?, _: JsonSerializationContext? ->
JsonPrimitive(
src?.toInt()
)
}
)
.create()
return gsonPre.toJson(src)
}
}
@@ -1,6 +1,6 @@
package com.v2ray.ang.util
import com.google.gson.Gson
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig.PREF_IS_BOOTED
import com.v2ray.ang.AppConfig.PREF_ROUTING_RULESET
@@ -49,7 +49,7 @@ object MmkvManager {
}
fun encodeServerList(serverList: MutableList<String>) {
mainStorage.encode(KEY_ANG_CONFIGS, Gson().toJson(serverList))
mainStorage.encode(KEY_ANG_CONFIGS, JsonUtil.toJson(serverList))
}
fun decodeServerList(): MutableList<String> {
@@ -57,7 +57,7 @@ object MmkvManager {
return if (json.isNullOrBlank()) {
mutableListOf()
} else {
Gson().fromJson(json, Array<String>::class.java).toMutableList()
JsonUtil.fromJson(json, Array<String>::class.java).toMutableList()
}
}
@@ -69,7 +69,7 @@ object MmkvManager {
if (json.isNullOrBlank()) {
return null
}
return Gson().fromJson(json, ServerConfig::class.java)
return JsonUtil.fromJson(json, ServerConfig::class.java)
}
fun decodeProfileConfig(guid: String): ProfileItem? {
@@ -80,12 +80,12 @@ object MmkvManager {
if (json.isNullOrBlank()) {
return null
}
return Gson().fromJson(json, ProfileItem::class.java)
return JsonUtil.fromJson(json, ProfileItem::class.java)
}
fun encodeServerConfig(guid: String, config: ServerConfig): String {
val key = guid.ifBlank { Utils.getUuid() }
serverStorage.encode(key, Gson().toJson(config))
serverStorage.encode(key, JsonUtil.toJson(config))
val serverList = decodeServerList()
if (!serverList.contains(key)) {
serverList.add(0, key)
@@ -101,7 +101,7 @@ object MmkvManager {
server = config.getProxyOutbound()?.getServerAddress(),
serverPort = config.getProxyOutbound()?.getServerPort(),
)
profileStorage.encode(key, Gson().toJson(profile))
profileStorage.encode(key, JsonUtil.toJson(profile))
return key
}
@@ -141,7 +141,7 @@ object MmkvManager {
if (json.isNullOrBlank()) {
return null
}
return Gson().fromJson(json, ServerAffiliationInfo::class.java)
return JsonUtil.fromJson(json, ServerAffiliationInfo::class.java)
}
fun encodeServerTestDelayMillis(guid: String, testResult: Long) {
@@ -150,14 +150,14 @@ object MmkvManager {
}
val aff = decodeServerAffiliationInfo(guid) ?: ServerAffiliationInfo()
aff.testDelayMillis = testResult
serverAffStorage.encode(guid, Gson().toJson(aff))
serverAffStorage.encode(guid, JsonUtil.toJson(aff))
}
fun clearAllTestDelayResults(keys: List<String>?) {
keys?.forEach { key ->
decodeServerAffiliationInfo(key)?.let { aff ->
aff.testDelayMillis = 0
serverAffStorage.encode(key, Gson().toJson(aff))
serverAffStorage.encode(key, JsonUtil.toJson(aff))
}
}
}
@@ -217,7 +217,7 @@ object MmkvManager {
decodeSubsList().forEach { key ->
val json = subStorage.decodeString(key)
if (!json.isNullOrBlank()) {
subscriptions.add(Pair(key, Gson().fromJson(json, SubscriptionItem::class.java)))
subscriptions.add(Pair(key, JsonUtil.fromJson(json, SubscriptionItem::class.java)))
}
}
return subscriptions
@@ -234,7 +234,7 @@ object MmkvManager {
fun encodeSubscription(guid: String, subItem: SubscriptionItem) {
val key = guid.ifBlank { Utils.getUuid() }
subStorage.encode(key, Gson().toJson(subItem))
subStorage.encode(key, JsonUtil.toJson(subItem))
val subsList = decodeSubsList()
if (!subsList.contains(key)) {
@@ -245,11 +245,11 @@ object MmkvManager {
fun decodeSubscription(subscriptionId: String): SubscriptionItem? {
val json = subStorage.decodeString(subscriptionId) ?: return null
return Gson().fromJson(json, SubscriptionItem::class.java)
return JsonUtil.fromJson(json, SubscriptionItem::class.java)
}
fun encodeSubsList(subsList: MutableList<String>) {
mainStorage.encode(KEY_SUB_IDS, Gson().toJson(subsList))
mainStorage.encode(KEY_SUB_IDS, JsonUtil.toJson(subsList))
}
fun decodeSubsList(): MutableList<String> {
@@ -257,7 +257,7 @@ object MmkvManager {
return if (json.isNullOrBlank()) {
mutableListOf()
} else {
Gson().fromJson(json, Array<String>::class.java).toMutableList()
JsonUtil.fromJson(json, Array<String>::class.java).toMutableList()
}
}
@@ -270,7 +270,7 @@ object MmkvManager {
assetStorage.allKeys()?.forEach { key ->
val json = assetStorage.decodeString(key)
if (!json.isNullOrBlank()) {
assetUrlItems.add(Pair(key, Gson().fromJson(json, AssetUrlItem::class.java)))
assetUrlItems.add(Pair(key, JsonUtil.fromJson(json, AssetUrlItem::class.java)))
}
}
return assetUrlItems.sortedBy { (_, value) -> value.addedTime }
@@ -282,12 +282,12 @@ object MmkvManager {
fun encodeAsset(assetid: String, assetItem: AssetUrlItem) {
val key = assetid.ifBlank { Utils.getUuid() }
assetStorage.encode(key, Gson().toJson(assetItem))
assetStorage.encode(key, JsonUtil.toJson(assetItem))
}
fun decodeAsset(assetid: String): AssetUrlItem? {
val json = assetStorage.decodeString(assetid) ?: return null
return Gson().fromJson(json, AssetUrlItem::class.java)
return JsonUtil.fromJson(json, AssetUrlItem::class.java)
}
//endregion
@@ -297,14 +297,14 @@ object MmkvManager {
fun decodeRoutingRulesets(): MutableList<RulesetItem>? {
val ruleset = settingsStorage.decodeString(PREF_ROUTING_RULESET)
if (ruleset.isNullOrEmpty()) return null
return Gson().fromJson(ruleset, Array<RulesetItem>::class.java).toMutableList()
return JsonUtil.fromJson(ruleset, Array<RulesetItem>::class.java).toMutableList()
}
fun encodeRoutingRulesets(rulesetList: MutableList<RulesetItem>?) {
if (rulesetList.isNullOrEmpty())
settingsStorage.encode(PREF_ROUTING_RULESET, "")
else
settingsStorage.encode(PREF_ROUTING_RULESET, Gson().toJson(rulesetList))
settingsStorage.encode(PREF_ROUTING_RULESET, JsonUtil.toJson(rulesetList))
}
//endregion
@@ -3,7 +3,7 @@ package com.v2ray.ang.util
import android.content.Context
import android.os.SystemClock
import android.util.Log
import com.google.gson.Gson
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ServerConfig
@@ -38,8 +38,8 @@ object PluginUtil {
Log.d(packageName, "runPlugin ${configFile.absolutePath}")
configFile.parentFile?.mkdirs()
configFile.writeText(Gson().toJson(hy2Config))
Log.d(packageName, Gson().toJson(hy2Config))
configFile.writeText(JsonUtil.toJson(hy2Config))
Log.d(packageName, JsonUtil.toJson(hy2Config))
runHy2(context, configFile)
}
@@ -2,7 +2,7 @@ package com.v2ray.ang.util
import android.content.Context
import android.text.TextUtils
import com.google.gson.Gson
import com.v2ray.ang.AppConfig
import com.v2ray.ang.dto.RulesetItem
import com.v2ray.ang.dto.ServerConfig
@@ -35,7 +35,7 @@ object SettingsManager {
return null
}
return Gson().fromJson(assets, Array<RulesetItem>::class.java).toMutableList()
return JsonUtil.fromJson(assets, Array<RulesetItem>::class.java).toMutableList()
}
fun resetRoutingRulesets(context: Context, index: Int) {
@@ -49,7 +49,7 @@ object SettingsManager {
}
try {
val rulesetList = Gson().fromJson(content, Array<RulesetItem>::class.java).toMutableList()
val rulesetList = JsonUtil.fromJson(content, Array<RulesetItem>::class.java).toMutableList()
if (rulesetList.isNullOrEmpty()) {
return false
}
@@ -3,7 +3,7 @@ package com.v2ray.ang.util
import android.content.Context
import android.text.TextUtils
import android.util.Log
import com.google.gson.Gson
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.AppConfig.LOOPBACK
@@ -67,7 +67,7 @@ object V2rayConfigUtil {
if (TextUtils.isEmpty(assets)) {
return result
}
val v2rayConfig = Gson().fromJson(assets, V2rayConfig::class.java) ?: return result
val v2rayConfig = JsonUtil.fromJson(assets, V2rayConfig::class.java) ?: return result
v2rayConfig.log.loglevel = settingsStorage?.decodeString(AppConfig.PREF_LOGLEVEL) ?: "warning"
v2rayConfig.remarks = config.remarks
@@ -206,7 +206,7 @@ object V2rayConfigUtil {
return
}
val rule = Gson().fromJson(Gson().toJson(item), RulesBean::class.java) ?: return
val rule = JsonUtil.fromJson(JsonUtil.toJson(item), RulesBean::class.java) ?: return
v2rayConfig.routing.rules.add(rule)
@@ -440,7 +440,7 @@ object V2rayConfigUtil {
val requestString: String by lazy {
"""{"version":"1.1","method":"GET","headers":{"User-Agent":["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36","Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}"""
}
outbound.streamSettings?.tcpSettings?.header?.request = Gson().fromJson(
outbound.streamSettings?.tcpSettings?.header?.request = JsonUtil.fromJson(
requestString,
V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean.HeaderBean.RequestBean::class.java
)
@@ -2,13 +2,14 @@ package com.v2ray.ang.util.fmt
import android.text.TextUtils
import android.util.Log
import com.google.gson.Gson
import com.v2ray.ang.AppConfig
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.dto.VmessQRCode
import com.v2ray.ang.extension.idnHost
import com.v2ray.ang.util.JsonUtil
import com.v2ray.ang.util.MmkvManager.settingsStorage
import com.v2ray.ang.util.Utils
import java.net.URI
@@ -29,7 +30,7 @@ object VmessFmt {
Log.d(AppConfig.ANG_PACKAGE, "R.string.toast_decoding_failed")
return null
}
val vmessQRCode = Gson().fromJson(result, VmessQRCode::class.java)
val vmessQRCode = JsonUtil.fromJson(result, VmessQRCode::class.java)
// Although VmessQRCode fields are non null, looks like Gson may still create null fields
if (TextUtils.isEmpty(vmessQRCode.add)
|| TextUtils.isEmpty(vmessQRCode.port)
@@ -100,7 +101,7 @@ object VmessFmt {
vmessQRCode.host = transportDetails[1]
vmessQRCode.path = transportDetails[2]
}
val json = Gson().toJson(vmessQRCode)
val json = JsonUtil.toJson(vmessQRCode)
return Utils.encode(json)
}
@@ -11,7 +11,7 @@ import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.v2ray.ang.AngApplication
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
@@ -25,6 +25,7 @@ import com.v2ray.ang.extension.serializable
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.AngConfigManager
import com.v2ray.ang.util.AngConfigManager.updateConfigViaSub
import com.v2ray.ang.util.JsonUtil
import com.v2ray.ang.util.MessageUtil
import com.v2ray.ang.util.MmkvManager
import com.v2ray.ang.util.SpeedtestUtil
@@ -99,7 +100,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
try {
val config = ServerConfig.create(EConfigType.CUSTOM)
config.subscriptionId = subscriptionId
config.fullConfig = Gson().fromJson(server, V2rayConfig::class.java)
config.fullConfig = JsonUtil.fromJson(server, V2rayConfig::class.java)
config.remarks = config.fullConfig?.remarks ?: System.currentTimeMillis().toString()
val key = MmkvManager.encodeServerConfig("", config)
MmkvManager.encodeServerRaw(key, server)
@@ -217,7 +218,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
MessageUtil.sendMsg2TestService(
getApplication(),
AppConfig.MSG_MEASURE_CONFIG,
Gson().toJson(config)
JsonUtil.toJson(config)
)
}
}