diff --git a/app/src/main/java/io/legado/app/api/controller/BookController.kt b/app/src/main/java/io/legado/app/api/controller/BookController.kt index 17be8f1c3..31c698bda 100644 --- a/app/src/main/java/io/legado/app/api/controller/BookController.kt +++ b/app/src/main/java/io/legado/app/api/controller/BookController.kt @@ -166,9 +166,8 @@ object BookController { * 保存书籍 */ fun saveBook(postData: String?): ReturnData { - val book = GSON.fromJsonObject(postData) val returnData = ReturnData() - if (book != null) { + GSON.fromJsonObject(postData).getOrNull()?.let { book -> book.save() AppWebDav.uploadBookProgress(book) if (ReadBook.book?.bookUrl == book.bookUrl) { diff --git a/app/src/main/java/io/legado/app/api/controller/BookSourceController.kt b/app/src/main/java/io/legado/app/api/controller/BookSourceController.kt index 417db03e8..f5c6d007e 100644 --- a/app/src/main/java/io/legado/app/api/controller/BookSourceController.kt +++ b/app/src/main/java/io/legado/app/api/controller/BookSourceController.kt @@ -73,11 +73,13 @@ object BookSourceController { fun deleteSources(postData: String?): ReturnData { kotlin.runCatching { - GSON.fromJsonArray(postData)?.let { + GSON.fromJsonArray(postData).getOrThrow()?.let { it.forEach { source -> appDb.bookSourceDao.delete(source) } } + }.onFailure { + return ReturnData().setErrorMsg(it.localizedMessage ?: "数据格式错误") } return ReturnData().setData("已执行"/*okSources*/) } diff --git a/app/src/main/java/io/legado/app/data/entities/BaseSource.kt b/app/src/main/java/io/legado/app/data/entities/BaseSource.kt index 00b5f07d2..ef0a63ab8 100644 --- a/app/src/main/java/io/legado/app/data/entities/BaseSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BaseSource.kt @@ -8,10 +8,7 @@ import io.legado.app.help.AppConfig import io.legado.app.help.CacheManager import io.legado.app.help.JsExtensions import io.legado.app.help.http.CookieStore -import io.legado.app.utils.EncoderUtils -import io.legado.app.utils.GSON -import io.legado.app.utils.fromJsonArray -import io.legado.app.utils.fromJsonObject +import io.legado.app.utils.* import javax.script.SimpleBindings /** @@ -30,7 +27,10 @@ interface BaseSource : JsExtensions { fun getKey(): String fun loginUi(): List? { - return GSON.fromJsonArray(loginUi) + return GSON.fromJsonArray(loginUi) + .onFailure { + it.printOnDebug() + }.getOrNull() } fun getLoginJs(): String? { @@ -64,7 +64,7 @@ interface BaseSource : JsExtensions { evalJS(it.substring(4, it.lastIndexOf("<"))).toString() else -> it } - )?.let { map -> + ).getOrNull()?.let { map -> putAll(map) } } @@ -84,7 +84,7 @@ interface BaseSource : JsExtensions { fun getLoginHeaderMap(): Map? { val cache = getLoginHeader() ?: return null - return GSON.fromJsonObject(cache) + return GSON.fromJsonObject>(cache).getOrNull() } /** @@ -117,7 +117,7 @@ interface BaseSource : JsExtensions { } fun getLoginInfoMap(): Map? { - return GSON.fromJsonObject(getLoginInfo()) + return GSON.fromJsonObject>(getLoginInfo()).getOrNull() } /** diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index a7684f89a..315a1f31e 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -92,8 +92,8 @@ data class Book( @delegate:Transient @delegate:Ignore @IgnoredOnParcel - override val variableMap by lazy { - GSON.fromJsonObject>(variable) ?: HashMap() + override val variableMap: HashMap by lazy { + GSON.fromJsonObject>(variable).getOrNull() ?: hashMapOf() } override fun putVariable(key: String, value: String?) { @@ -307,6 +307,6 @@ data class Book( fun readConfigToString(config: ReadConfig?): String = GSON.toJson(config) @TypeConverter - fun stringToReadConfig(json: String?) = GSON.fromJsonObject(json) + fun stringToReadConfig(json: String?) = GSON.fromJsonObject(json).getOrNull() } } diff --git a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt index 9afff1941..7e335ccfd 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt @@ -50,8 +50,8 @@ data class BookChapter( @delegate:Transient @delegate:Ignore @IgnoredOnParcel - override val variableMap by lazy { - GSON.fromJsonObject>(variable) ?: HashMap() + override val variableMap: HashMap by lazy { + GSON.fromJsonObject>(variable).getOrNull() ?: hashMapOf() } override fun putVariable(key: String, value: String?) { diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index 7bdb2b30e..31650756c 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -108,7 +108,7 @@ data class BookSource( } } if (ruleStr.isJsonArray()) { - GSON.fromJsonArray(ruleStr)?.let { + GSON.fromJsonArray(ruleStr).getOrThrow()?.let { kinds.addAll(it) } } else { @@ -219,34 +219,44 @@ data class BookSource( class Converters { @TypeConverter - fun exploreRuleToString(exploreRule: ExploreRule?): String = GSON.toJson(exploreRule) + fun exploreRuleToString(exploreRule: ExploreRule?): String = + GSON.toJson(exploreRule) @TypeConverter - fun stringToExploreRule(json: String?) = GSON.fromJsonObject(json) + fun stringToExploreRule(json: String?) = + GSON.fromJsonObject(json).getOrNull() @TypeConverter - fun searchRuleToString(searchRule: SearchRule?): String = GSON.toJson(searchRule) + fun searchRuleToString(searchRule: SearchRule?): String = + GSON.toJson(searchRule) @TypeConverter - fun stringToSearchRule(json: String?) = GSON.fromJsonObject(json) + fun stringToSearchRule(json: String?) = + GSON.fromJsonObject(json).getOrNull() @TypeConverter - fun bookInfoRuleToString(bookInfoRule: BookInfoRule?): String = GSON.toJson(bookInfoRule) + fun bookInfoRuleToString(bookInfoRule: BookInfoRule?): String = + GSON.toJson(bookInfoRule) @TypeConverter - fun stringToBookInfoRule(json: String?) = GSON.fromJsonObject(json) + fun stringToBookInfoRule(json: String?) = + GSON.fromJsonObject(json).getOrNull() @TypeConverter - fun tocRuleToString(tocRule: TocRule?): String = GSON.toJson(tocRule) + fun tocRuleToString(tocRule: TocRule?): String = + GSON.toJson(tocRule) @TypeConverter - fun stringToTocRule(json: String?) = GSON.fromJsonObject(json) + fun stringToTocRule(json: String?) = + GSON.fromJsonObject(json).getOrNull() @TypeConverter - fun contentRuleToString(contentRule: ContentRule?): String = GSON.toJson(contentRule) + fun contentRuleToString(contentRule: ContentRule?): String = + GSON.toJson(contentRule) @TypeConverter - fun stringToContentRule(json: String?) = GSON.fromJsonObject(json) + fun stringToContentRule(json: String?) = + GSON.fromJsonObject(json).getOrNull() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt index 911fb16b8..b9861147a 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt @@ -36,8 +36,8 @@ data class RssArticle( @delegate:Transient @delegate:Ignore @IgnoredOnParcel - override val variableMap by lazy { - GSON.fromJsonObject>(variable) ?: HashMap() + override val variableMap: HashMap by lazy { + GSON.fromJsonObject>(variable).getOrNull() ?: hashMapOf() } override fun putVariable(key: String, value: String?) { diff --git a/app/src/main/java/io/legado/app/data/entities/RssStar.kt b/app/src/main/java/io/legado/app/data/entities/RssStar.kt index df4bd546f..5f875b16b 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssStar.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssStar.kt @@ -29,7 +29,7 @@ data class RssStar( @delegate:Ignore @IgnoredOnParcel override val variableMap by lazy { - GSON.fromJsonObject>(variable) ?: HashMap() + GSON.fromJsonObject>(variable).getOrNull() ?: hashMapOf() } override fun putVariable(key: String, value: String?) { diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 96c525b3a..f995a66da 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -59,8 +59,8 @@ data class SearchBook( @delegate:Transient @delegate:Ignore @IgnoredOnParcel - override val variableMap by lazy { - GSON.fromJsonObject>(variable) ?: HashMap() + override val variableMap: HashMap by lazy { + GSON.fromJsonObject>(variable).getOrNull() ?: HashMap() } override fun putVariable(key: String, value: String?) { diff --git a/app/src/main/java/io/legado/app/help/DefaultData.kt b/app/src/main/java/io/legado/app/help/DefaultData.kt index 06d05173b..d1b9e11a1 100644 --- a/app/src/main/java/io/legado/app/help/DefaultData.kt +++ b/app/src/main/java/io/legado/app/help/DefaultData.kt @@ -28,7 +28,8 @@ object DefaultData { appCtx.assets.open("defaultData${File.separator}${ReadBookConfig.configFileName}") .readBytes() ) - GSON.fromJsonArray(json)!! + GSON.fromJsonArray(json).getOrNull() + ?: emptyList() } val txtTocRules: List by lazy { @@ -36,7 +37,7 @@ object DefaultData { appCtx.assets.open("defaultData${File.separator}$txtTocRuleFileName") .readBytes() ) - GSON.fromJsonArray(json)!! + GSON.fromJsonArray(json).getOrNull() ?: emptyList() } val themeConfigs: List by lazy { @@ -44,15 +45,17 @@ object DefaultData { appCtx.assets.open("defaultData${File.separator}${ThemeConfig.configFileName}") .readBytes() ) - GSON.fromJsonArray(json)!! + GSON.fromJsonArray(json).getOrNull() ?: emptyList() } val rssSources: List by lazy { - val json = String( - appCtx.assets.open("defaultData${File.separator}rssSources.json") - .readBytes() - ) - RssSource.fromJsonArray(json) + kotlin.runCatching { + val json = String( + appCtx.assets.open("defaultData${File.separator}rssSources.json") + .readBytes() + ) + RssSource.fromJsonArray(json) + }.getOrDefault(emptyList()) } fun importDefaultHttpTTS() { diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 6999546a4..7d018e404 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -97,7 +97,7 @@ interface JsExtensions { fun connect(urlStr: String, header: String?): StrResponse { return runBlocking { - val headerMap = GSON.fromJsonObject>(header) + val headerMap = GSON.fromJsonObject>(header).getOrNull() val analyzeUrl = AnalyzeUrl(urlStr, headerMapF = headerMap, source = getSource()) kotlin.runCatching { analyzeUrl.getStrResponseAwait() diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 45e789df3..fca5e0ff2 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -6,15 +6,17 @@ import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import androidx.annotation.Keep import io.legado.app.R +import io.legado.app.constant.AppLog import io.legado.app.constant.PreferKey import io.legado.app.help.coroutine.Coroutine +import io.legado.app.model.NoStackTraceException import io.legado.app.ui.book.read.page.provider.ChapterProvider import io.legado.app.utils.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.withContext import splitties.init.appCtx - import java.io.File +import java.io.IOException /** * 阅读界面配置 @@ -60,9 +62,9 @@ object ReadBookConfig { if (configFile.exists()) { try { val json = configFile.readText() - configs = GSON.fromJsonArray(json) + configs = GSON.fromJsonArray(json).getOrThrow() } catch (e: Exception) { - e.printOnDebug() + AppLog.put("读取排版配置文件出错", e) } } (configs ?: DefaultData.readConfigs).let { @@ -77,7 +79,7 @@ object ReadBookConfig { if (configFile.exists()) { try { val json = configFile.readText() - c = GSON.fromJsonObject(json) + c = GSON.fromJsonObject(json).getOrThrow() } catch (e: Exception) { e.printOnDebug() } @@ -325,7 +327,7 @@ object ReadBookConfig { } fun getExportConfig(): Config { - val exportConfig = GSON.fromJsonObject(GSON.toJson(durConfig))!! + val exportConfig = durConfig.deepCopy() if (shareLayout) { exportConfig.textFont = shareConfig.textFont exportConfig.textBold = shareConfig.textBold @@ -364,6 +366,7 @@ object ReadBookConfig { return exportConfig } + @Throws(IOException::class) suspend fun import(byteArray: ByteArray): Config { return withContext(IO) { val configZipPath = FileUtils.getPath(appCtx.externalCache, "readConfig.zip") @@ -376,7 +379,8 @@ object ReadBookConfig { ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath)) val configDir = FileUtils.createFolderIfNotExist(configDirPath) val configFile = configDir.getFile(configFileName) - val config: Config = GSON.fromJsonObject(configFile.readText())!! + val config: Config = GSON.fromJsonObject(configFile.readText()).getOrThrow() + ?: throw NoStackTraceException("排版配置格式错误") if (config.textFont.isNotEmpty()) { val fontName = FileUtils.getName(config.textFont) val fontPath = diff --git a/app/src/main/java/io/legado/app/help/SourceAnalyzer.kt b/app/src/main/java/io/legado/app/help/SourceAnalyzer.kt index 666e21a66..4db179cf6 100644 --- a/app/src/main/java/io/legado/app/help/SourceAnalyzer.kt +++ b/app/src/main/java/io/legado/app/help/SourceAnalyzer.kt @@ -3,6 +3,7 @@ package io.legado.app.help import androidx.annotation.Keep import com.jayway.jsonpath.JsonPath import io.legado.app.constant.AppConst +import io.legado.app.constant.AppLog import io.legado.app.constant.BookType import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.* @@ -31,11 +32,10 @@ object SourceAnalyzer { fun jsonToBookSource(json: String): BookSource? { val source = BookSource() - val sourceAny = try { - GSON.fromJsonObject(json.trim()) - } catch (e: Exception) { - null - } + val sourceAny = GSON.fromJsonObject(json.trim()) + .onFailure { + AppLog.put("转化书源出错", it) + }.getOrNull() try { if (sourceAny?.ruleToc == null) { source.apply { @@ -132,30 +132,40 @@ object SourceAnalyzer { source.weight = sourceAny.weight source.exploreUrl = sourceAny.exploreUrl source.ruleExplore = if (sourceAny.ruleExplore is String) { - GSON.fromJsonObject(sourceAny.ruleExplore.toString()) + GSON.fromJsonObject(sourceAny.ruleExplore.toString()) + .getOrNull() } else { - GSON.fromJsonObject(GSON.toJson(sourceAny.ruleExplore)) + GSON.fromJsonObject(GSON.toJson(sourceAny.ruleExplore)) + .getOrNull() } source.searchUrl = sourceAny.searchUrl source.ruleSearch = if (sourceAny.ruleSearch is String) { - GSON.fromJsonObject(sourceAny.ruleSearch.toString()) + GSON.fromJsonObject(sourceAny.ruleSearch.toString()) + .getOrNull() } else { - GSON.fromJsonObject(GSON.toJson(sourceAny.ruleSearch)) + GSON.fromJsonObject(GSON.toJson(sourceAny.ruleSearch)) + .getOrNull() } source.ruleBookInfo = if (sourceAny.ruleBookInfo is String) { - GSON.fromJsonObject(sourceAny.ruleBookInfo.toString()) + GSON.fromJsonObject(sourceAny.ruleBookInfo.toString()) + .getOrNull() } else { - GSON.fromJsonObject(GSON.toJson(sourceAny.ruleBookInfo)) + GSON.fromJsonObject(GSON.toJson(sourceAny.ruleBookInfo)) + .getOrNull() } source.ruleToc = if (sourceAny.ruleToc is String) { - GSON.fromJsonObject(sourceAny.ruleToc.toString()) + GSON.fromJsonObject(sourceAny.ruleToc.toString()) + .getOrNull() } else { - GSON.fromJsonObject(GSON.toJson(sourceAny.ruleToc)) + GSON.fromJsonObject(GSON.toJson(sourceAny.ruleToc)) + .getOrNull() } source.ruleContent = if (sourceAny.ruleContent is String) { - GSON.fromJsonObject(sourceAny.ruleContent.toString()) + GSON.fromJsonObject(sourceAny.ruleContent.toString()) + .getOrNull() } else { - GSON.fromJsonObject(GSON.toJson(sourceAny.ruleContent)) + GSON.fromJsonObject(GSON.toJson(sourceAny.ruleContent)) + .getOrNull() } } } catch (e: Exception) { diff --git a/app/src/main/java/io/legado/app/help/ThemeConfig.kt b/app/src/main/java/io/legado/app/help/ThemeConfig.kt index 35ed45062..8cd0a130d 100644 --- a/app/src/main/java/io/legado/app/help/ThemeConfig.kt +++ b/app/src/main/java/io/legado/app/help/ThemeConfig.kt @@ -83,10 +83,11 @@ object ThemeConfig { } fun addConfig(json: String): Boolean { - GSON.fromJsonObject(json.trim { it < ' ' })?.let { - addConfig(it) - return true - } + GSON.fromJsonObject(json.trim { it < ' ' }).getOrNull() + ?.let { + addConfig(it) + return true + } return false } @@ -106,7 +107,7 @@ object ThemeConfig { if (configFile.exists()) { kotlin.runCatching { val json = configFile.readText() - return GSON.fromJsonArray(json) + return GSON.fromJsonArray(json).getOrThrow() }.onFailure { it.printOnDebug() } diff --git a/app/src/main/java/io/legado/app/help/storage/AppWebDav.kt b/app/src/main/java/io/legado/app/help/storage/AppWebDav.kt index 082e85434..53e6ec5d9 100644 --- a/app/src/main/java/io/legado/app/help/storage/AppWebDav.kt +++ b/app/src/main/java/io/legado/app/help/storage/AppWebDav.kt @@ -172,9 +172,7 @@ object AppWebDav { WebDav(url).download()?.let { byteArray -> val json = String(byteArray) if (json.isJson()) { - GSON.fromJsonObject(json)?.let { - return it - } + return GSON.fromJsonObject(json).getOrNull() } } } diff --git a/app/src/main/java/io/legado/app/help/storage/BackupRestore.kt b/app/src/main/java/io/legado/app/help/storage/BackupRestore.kt index 0db50c607..48647915d 100644 --- a/app/src/main/java/io/legado/app/help/storage/BackupRestore.kt +++ b/app/src/main/java/io/legado/app/help/storage/BackupRestore.kt @@ -13,7 +13,7 @@ abstract class BackupRestore { val ignoreConfig: HashMap by lazy { val file = FileUtils.createFileIfNotExist(ignoreConfigPath) val json = file.readText() - GSON.fromJsonObject>(json) ?: hashMapOf() + GSON.fromJsonObject>(json).getOrNull() ?: hashMapOf() } //忽略key diff --git a/app/src/main/java/io/legado/app/help/storage/OldReplace.kt b/app/src/main/java/io/legado/app/help/storage/OldReplace.kt index 66664637d..eb8b4b8d2 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldReplace.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldReplace.kt @@ -20,12 +20,9 @@ object OldReplace { } private fun jsonToReplaceRule(json: String): ReplaceRule? { - var replaceRule: ReplaceRule? = null + val replaceRule: ReplaceRule? = GSON.fromJsonObject(json.trim()).getOrNull() runCatching { - replaceRule = GSON.fromJsonObject(json.trim()) - } - runCatching { - if (replaceRule == null || replaceRule?.pattern.isNullOrBlank()) { + if (replaceRule == null || replaceRule.pattern.isBlank()) { val jsonItem = jsonPath.parse(json.trim()) val rule = ReplaceRule() rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis() diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 6cb9b6b45..d26bc2e99 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -6,6 +6,7 @@ import androidx.documentfile.provider.DocumentFile import io.legado.app.BuildConfig import io.legado.app.R import io.legado.app.constant.AppConst.androidId +import io.legado.app.constant.AppLog import io.legado.app.constant.EventBus import io.legado.app.constant.PreferKey import io.legado.app.data.appDb @@ -20,7 +21,6 @@ import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import splitties.init.appCtx - import java.io.File @@ -193,9 +193,10 @@ object Restore : BackupRestore() { try { val file = FileUtils.createFileIfNotExist(path + File.separator + fileName) val json = file.readText() - return GSON.fromJsonArray(json) + return GSON.fromJsonArray(json).getOrThrow() } catch (e: Exception) { - e.printOnDebug() + AppLog.put("读取文件出错\n${e.localizedMessage}", e) + appCtx.toastOnUi("读取文件出错\n${e.localizedMessage}") } return null } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 5d654fb70..0dcc796a9 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -341,8 +341,11 @@ class AnalyzeRule( val putMatcher = putPattern.matcher(vRuleStr) while (putMatcher.find()) { vRuleStr = vRuleStr.replace(putMatcher.group(), "") - val map = GSON.fromJsonObject>(putMatcher.group(1)) - map?.let { putMap.putAll(map) } + GSON.fromJsonObject>(putMatcher.group(1)) + .getOrNull() + ?.let { + putMap.putAll(it) + } } return vRuleStr } @@ -379,7 +382,7 @@ class AnalyzeRule( * 分解规则生成规则列表 */ fun splitSourceRule(ruleStr: String?, allInOne: Boolean = false): List { - if (ruleStr.isNullOrEmpty()) return ArrayList() + if (ruleStr.isNullOrEmpty()) return emptyList() val ruleList = ArrayList() var mMode: Mode = Mode.Default var start = 0 @@ -597,9 +600,9 @@ class AnalyzeRule( private fun isRule(ruleStr: String): Boolean { return ruleStr.startsWith('@') //js首个字符不可能是@,除非是装饰器,所以@开头规定为规则 - || ruleStr.startsWith("$.") - || ruleStr.startsWith("$[") - || ruleStr.startsWith("//") + || ruleStr.startsWith("$.") + || ruleStr.startsWith("$[") + || ruleStr.startsWith("//") } } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 8dc3ed72f..4fc1fff7b 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -167,34 +167,35 @@ class AnalyzeUrl( baseUrl = it } if (urlNoOption.length != ruleUrl.length) { - GSON.fromJsonObject(ruleUrl.substring(urlMatcher.end()))?.let { option -> - option.method?.let { - if (it.equals("POST", true)) method = RequestMethod.POST - } - option.headers?.let { headers -> - if (headers is Map<*, *>) { - headers.forEach { entry -> - headerMap[entry.key.toString()] = entry.value.toString() + GSON.fromJsonObject(ruleUrl.substring(urlMatcher.end())).getOrNull() + ?.let { option -> + option.method?.let { + if (it.equals("POST", true)) method = RequestMethod.POST + } + option.headers?.let { headers -> + if (headers is Map<*, *>) { + headers.forEach { entry -> + headerMap[entry.key.toString()] = entry.value.toString() + } + } else if (headers is String) { + GSON.fromJsonObject>(headers).getOrNull() + ?.let { headerMap.putAll(it) } } - } else if (headers is String) { - GSON.fromJsonObject>(headers) - ?.let { headerMap.putAll(it) } } - } - option.body?.let { - body = if (it is String) it else GSON.toJson(it) - } - type = option.type - charset = option.charset - retry = option.retry - useWebView = option.webView?.toString()?.isNotBlank() == true - webJs = option.webJs - option.js?.let { jsStr -> - evalJS(jsStr, url)?.toString()?.let { - url = it + option.body?.let { + body = if (it is String) it else GSON.toJson(it) + } + type = option.type + charset = option.charset + retry = option.retry + useWebView = option.webView?.toString()?.isNotBlank() == true + webJs = option.webJs + option.js?.let { jsStr -> + evalJS(jsStr, url)?.toString()?.let { + url = it + } } } - } } headerMap[UA_NAME] ?: let { headerMap[UA_NAME] = AppConfig.userAgent @@ -510,7 +511,7 @@ class AnalyzeUrl( suspend fun upload(fileName: String, file: Any, contentType: String): StrResponse { return getProxyClient(proxy).newCallStrResponse(retry) { url(urlNoQuery) - val bodyMap = GSON.fromJsonObject>(body)!! + val bodyMap = GSON.fromJsonObject>(body).getOrNull()!! bodyMap.forEach { entry -> if (entry.value.toString() == "fileRequest") { bodyMap[entry.key] = mapOf( diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index 66bef1143..9fe0e344d 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -141,8 +141,8 @@ object LocalBook { //将文件名注入到脚步的src变量中 SimpleBindings().also { it["src"] = tempFileName } ).toString() - val bookMess = - GSON.fromJsonObject>(jsonStr) ?: HashMap() + val bookMess = GSON.fromJsonObject>(jsonStr) + .getOrThrow() ?: HashMap() name = bookMess["name"] ?: tempFileName author = bookMess["author"]?.takeIf { it.length != tempFileName.length } ?: "" } catch (e: Exception) { diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index bc8d55cd1..9a5f474de 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -37,7 +37,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener @Synchronized private fun initTts() { ttsInitFinish = false - val engine = GSON.fromJsonObject>(ReadAloud.ttsEngine)?.value + val engine = GSON.fromJsonObject>(ReadAloud.ttsEngine).getOrNull()?.value textToSpeech = if (engine.isNullOrBlank()) { TextToSpeech(this, this) } else { diff --git a/app/src/main/java/io/legado/app/ui/association/BaseAssociationViewModel.kt b/app/src/main/java/io/legado/app/ui/association/BaseAssociationViewModel.kt index f0e252a3e..bd031907a 100644 --- a/app/src/main/java/io/legado/app/ui/association/BaseAssociationViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/association/BaseAssociationViewModel.kt @@ -19,11 +19,11 @@ abstract class BaseAssociationViewModel(application: Application) : BaseViewMode fun importTextTocRule(json: String, finally: (title: String, msg: String) -> Unit) { execute { if (json.isJsonArray()) { - GSON.fromJsonArray(json)?.let { + GSON.fromJsonArray(json).getOrThrow()?.let { appDb.txtTocRuleDao.insert(*it.toTypedArray()) } ?: throw NoStackTraceException("格式不对") } else { - GSON.fromJsonObject(json)?.let { + GSON.fromJsonObject(json).getOrThrow()?.let { appDb.txtTocRuleDao.insert(it) } ?: throw NoStackTraceException("格式不对") } @@ -63,11 +63,11 @@ abstract class BaseAssociationViewModel(application: Application) : BaseViewMode fun importTheme(json: String, finally: (title: String, msg: String) -> Unit) { execute { if (json.isJsonArray()) { - GSON.fromJsonArray(json)?.forEach { + GSON.fromJsonArray(json).getOrThrow()?.forEach { ThemeConfig.addConfig(it) } ?: throw NoStackTraceException("格式不对") } else { - GSON.fromJsonObject(json)?.let { + GSON.fromJsonObject(json).getOrThrow()?.let { ThemeConfig.addConfig(it) } ?: throw NoStackTraceException("格式不对") } diff --git a/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleDialog.kt b/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleDialog.kt index 7185cea3f..66490bf7a 100644 --- a/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleDialog.kt @@ -181,7 +181,7 @@ class ImportReplaceRuleDialog() : BaseDialogFragment(R.layout.dialog_recycler_vi override fun onCodeSave(code: String, requestId: String?) { requestId?.toInt()?.let { - GSON.fromJsonObject(code)?.let { rule -> + GSON.fromJsonObject(code).getOrNull()?.let { rule -> viewModel.allRules[it] = rule adapter.setItem(it, rule) } diff --git a/app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleActivity.kt b/app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleActivity.kt index 96f08798e..29fc96d7e 100644 --- a/app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleActivity.kt @@ -6,7 +6,6 @@ import android.view.Menu import android.view.MenuItem import androidx.activity.viewModels import androidx.recyclerview.widget.ItemTouchHelper -import com.google.android.material.snackbar.Snackbar import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.appDb @@ -22,8 +21,8 @@ import io.legado.app.ui.widget.recycler.ItemTouchCallback import io.legado.app.ui.widget.recycler.VerticalDivider import io.legado.app.utils.ACache import io.legado.app.utils.setEdgeEffectColor -import io.legado.app.utils.snackbar import io.legado.app.utils.splitNotBlank +import io.legado.app.utils.toastOnUi import io.legado.app.utils.viewbindingdelegate.viewBinding import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.launch @@ -184,10 +183,8 @@ class TxtTocRuleActivity : VMBaseActivity - binding.root.snackbar(msg) + toastOnUi(msg) } } } diff --git a/app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleViewModel.kt index 47c261a16..2c4cf0028 100644 --- a/app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/local/rule/TxtTocRuleViewModel.kt @@ -42,14 +42,14 @@ class TxtTocRuleViewModel(app: Application) : BaseViewModel(app) { okHttpClient.newCallResponseBody { url(url) }.text("utf-8").let { json -> - GSON.fromJsonArray(json)?.let { + GSON.fromJsonArray(json).getOrThrow()?.let { appDb.txtTocRuleDao.insert(*it.toTypedArray()) } } }.onSuccess { finally("导入成功") }.onError { - finally("导入失败") + finally("导入失败\n${it.localizedMessage}") } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt index b7d67ee56..0c07b9e0c 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt @@ -65,7 +65,7 @@ class ReadAloudConfigDialog : DialogFragment() { return appDb.httpTTSDao.getName(ttsEngine.toLong()) ?: getString(R.string.system_tts) } - return GSON.fromJsonObject>(ttsEngine)?.title + return GSON.fromJsonObject>(ttsEngine).getOrNull()?.title ?: getString(R.string.system_tts) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt index feb9e4fc5..f86a5a4ec 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt @@ -95,8 +95,8 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di labelSys.visible() cbName.text = engine.label cbName.tag = engine.name - cbName.isChecked = - GSON.fromJsonObject>(ttsEngine)?.value == cbName.tag + cbName.isChecked = GSON.fromJsonObject>(ttsEngine) + .getOrNull()?.value == cbName.tag cbName.setOnClickListener { upTts(GSON.toJson(SelectItem(engine.label, engine.name))) } @@ -192,7 +192,8 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di private fun upTts(tts: String) { ttsEngine = tts sysTtsViews.forEach { - it.isChecked = GSON.fromJsonObject>(ttsEngine)?.value == it.tag + it.isChecked = GSON.fromJsonObject>(ttsEngine) + .getOrNull()?.value == it.tag } adapter.notifyItemRangeChanged(adapter.getHeaderCount(), adapter.itemCount) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt index dd6cf5339..4f8c4351c 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt @@ -10,7 +10,6 @@ import androidx.appcompat.widget.Toolbar import androidx.fragment.app.viewModels import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.snackbar.Snackbar import io.legado.app.R import io.legado.app.base.BaseDialogFragment import io.legado.app.base.adapter.ItemViewHolder @@ -154,10 +153,8 @@ class TocRegexDialog() : BaseDialogFragment(R.layout.dialog_toc_regex), cacheUrls.add(0, it) aCache.put(importTocRuleKey, cacheUrls.joinToString(",")) } - Snackbar.make(binding.toolBar, R.string.importing, Snackbar.LENGTH_INDEFINITE) - .show() viewModel.importOnLine(it) { msg -> - binding.toolBar.snackbar(msg) + toastOnUi(msg) } } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexViewModel.kt index 011f4debe..7846d4426 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexViewModel.kt @@ -33,14 +33,14 @@ class TocRegexViewModel(application: Application) : BaseViewModel(application) { okHttpClient.newCallResponseBody { url(url) }.text("utf-8").let { json -> - GSON.fromJsonArray(json)?.let { + GSON.fromJsonArray(json).getOrThrow()?.let { appDb.txtTocRuleDao.insert(*it.toTypedArray()) } } }.onSuccess { finally("导入成功") }.onError { - finally("导入失败") + finally("导入失败\n${it.localizedMessage}") } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 471a0d976..c63b8c569 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -126,7 +126,7 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) private fun importBookshelfByJson(json: String, groupId: Long) { execute { val bookSources = appDb.bookSourceDao.allEnabled - GSON.fromJsonArray>(json)?.forEach { bookInfo -> + GSON.fromJsonArray>(json).getOrThrow()?.forEach { bookInfo -> if (!isActive) return@execute val name = bookInfo["name"] ?: "" val author = bookInfo["author"] ?: "" @@ -143,6 +143,8 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) } } } + }.onError { + it.printOnDebug() }.onFinally { context.toastOnUi(R.string.success) } diff --git a/app/src/main/java/io/legado/app/utils/DataExtensions.kt b/app/src/main/java/io/legado/app/utils/DataExtensions.kt new file mode 100644 index 000000000..8e9f15404 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/DataExtensions.kt @@ -0,0 +1,41 @@ +package io.legado.app.utils + +import kotlin.reflect.KClass +import kotlin.reflect.full.memberProperties +import kotlin.reflect.full.primaryConstructor + +@Suppress("UNCHECKED_CAST") +fun T.deepCopy(): T { + //如果不是数据类,直接返回 + if (!this::class.isData) { + return this + } + + //拿到构造函数 + return this::class.primaryConstructor!!.let { primaryConstructor -> + //转换类型 + //memberProperties 返回非扩展属性中的第一个并将构造函数赋值给其 + //最终value=第一个参数类型的对象 + + //如果当前类(这里的当前类指的是参数对应的类型,比如说这里如果非基本类型时)是数据类 + + //最终返回一个新的映射map,即返回一个属性值重新组合的map,并调用callBy返回指定的对象 + primaryConstructor.parameters.associate { parameter -> + //转换类型 + //memberProperties 返回非扩展属性中的第一个并将构造函数赋值给其 + //最终value=第一个参数类型的对象 + val value = (this::class as KClass).memberProperties.first { + it.name == parameter.name + }.get(this) + + //如果当前类(这里的当前类指的是参数对应的类型,比如说这里如果非基本类型时)是数据类 + if ((parameter.type.classifier as? KClass<*>)?.isData == true) { + parameter to value?.deepCopy() + } else { + parameter to value + } + + //最终返回一个新的映射map,即返回一个属性值重新组合的map,并调用callBy返回指定的对象 + }.let(primaryConstructor::callBy) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt index 878362ba3..443b95560 100644 --- a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt @@ -4,7 +4,6 @@ import com.google.gson.* import com.google.gson.internal.LinkedTreeMap import com.google.gson.reflect.TypeToken import com.google.gson.stream.JsonWriter - import java.io.OutputStream import java.io.OutputStreamWriter import java.lang.reflect.ParameterizedType @@ -26,22 +25,16 @@ val GSON: Gson by lazy { inline fun genericType(): Type = object : TypeToken() {}.type -inline fun Gson.fromJsonObject(json: String?): T? {//可转成任意类型 - json ?: return null +inline fun Gson.fromJsonObject(json: String?): Result { return kotlin.runCatching { fromJson(json, genericType()) as? T - }.onFailure { - DebugLog.e("GSON解析出错", json, it) - }.getOrNull() + } } -inline fun Gson.fromJsonArray(json: String?): List? { - json ?: return null +inline fun Gson.fromJsonArray(json: String?): Result?> { return kotlin.runCatching { fromJson(json, ParameterizedTypeImpl(T::class.java)) as? List - }.onFailure { - DebugLog.e("GSON解析出错", json, it) - }.getOrNull() + } } fun Gson.writeToOutputStream(out: OutputStream, any: Any) { diff --git a/app/src/main/java/io/legado/app/utils/IntentExtensions.kt b/app/src/main/java/io/legado/app/utils/IntentExtensions.kt index f64dcf7b4..3edc732bd 100644 --- a/app/src/main/java/io/legado/app/utils/IntentExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/IntentExtensions.kt @@ -12,10 +12,10 @@ fun Intent.putJson(key: String, any: Any?) { inline fun Intent.getJsonObject(key: String): T? { val value = getStringExtra(key) - return GSON.fromJsonObject(value) + return GSON.fromJsonObject(value).getOrNull() } inline fun Intent.getJsonArray(key: String): List? { val value = getStringExtra(key) - return GSON.fromJsonArray(value) + return GSON.fromJsonArray(value).getOrNull() } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/web/socket/BookSourceDebugWebSocket.kt b/app/src/main/java/io/legado/app/web/socket/BookSourceDebugWebSocket.kt index e7c97182a..06b5ead97 100644 --- a/app/src/main/java/io/legado/app/web/socket/BookSourceDebugWebSocket.kt +++ b/app/src/main/java/io/legado/app/web/socket/BookSourceDebugWebSocket.kt @@ -49,7 +49,8 @@ class BookSourceDebugWebSocket(handshakeRequest: NanoHTTPD.IHTTPSession) : close(NanoWSD.WebSocketFrame.CloseCode.NormalClosure, "调试结束", false) return@launch } - val debugBean = GSON.fromJsonObject>(message.textPayload) + val debugBean = + GSON.fromJsonObject>(message.textPayload).getOrNull() if (debugBean != null) { val tag = debugBean["tag"] val key = debugBean["key"] diff --git a/app/src/main/java/io/legado/app/web/socket/RssSourceDebugWebSocket.kt b/app/src/main/java/io/legado/app/web/socket/RssSourceDebugWebSocket.kt index 1cd21eab6..c1b3b8eca 100644 --- a/app/src/main/java/io/legado/app/web/socket/RssSourceDebugWebSocket.kt +++ b/app/src/main/java/io/legado/app/web/socket/RssSourceDebugWebSocket.kt @@ -49,7 +49,8 @@ class RssSourceDebugWebSocket(handshakeRequest: NanoHTTPD.IHTTPSession) : close(NanoWSD.WebSocketFrame.CloseCode.NormalClosure, "调试结束", false) return@launch } - val debugBean = GSON.fromJsonObject>(message.textPayload) + val debugBean = + GSON.fromJsonObject>(message.textPayload).getOrNull() if (debugBean != null) { val tag = debugBean["tag"] if (tag.isNullOrBlank()) {