moshi

moshi 的使用方法簡介,項目地址

1、通過 JsonClass 解析 Kotlin

// build.gradle 依賴
id 'kotlin-kapt'

kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.14.0'
// @JsonClass 注解
@JsonClass(generateAdapter = true) data class PlantParserData(
    val plantId: String,
    val name: String,
    val description: String,
    val growZoneNumber: Int,
    val wateringInterval: Int,
    val imageUrl: String,
)

fun parserJsonClass() {
    val moshi = Moshi.Builder().build()

    val jsonAdapter: JsonAdapter<PlantParserData> = moshi.adapter(PlantParserData::class.java)
    val jsonData = jsonAdapter.fromJson(dataKotlinParser)

    log(jsonData.toString())

    log(jsonAdapter.toJson(jsonData))
}

2、通過 KotlinJsonAdapterFactory 解析 Kotlin

// build.gradle 依賴
implementation "com.squareup.moshi:moshi-kotlin:1.14.0"
data class PlantKotlinData(
    val plantId: String,
    val name: String,
    val description: String,
    val growZoneNumber: Int,
    val wateringInterval: Int,
    val imageUrl: String,
)

fun parserKotlinData() {
    val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()

    val jsonAdapter: JsonAdapter<PlantKotlinData> = moshi.adapter(PlantKotlinData::class.java)
    val jsonData = jsonAdapter.fromJson(dataKotlinParser)

    log(jsonData.toString())

    log(jsonAdapter.toJson(jsonData))
}

3、newParameterizedType 解析 List

fun parserJsonList(){
    val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
    val plantListType = Types.newParameterizedType(List::class.java, PlantKotlinData::class.java)
    val plantListAdapter = moshi.adapter<List<PlantKotlinData>>(plantListType)

    val plantList = plantListAdapter.fromJson(dataList) ?: emptyList()

    log(plantList.toString())

    log(plantListAdapter.toJson(plantList))
}

4、indent 格式化打印

fun printPretty() {
    val plant = PlantKotlinData(
        "coriandrum-sativum",
        "Cilantro",
        "Coriander",
        2,
        4,
        "A_scene_of_Coriander_leaves.JPG"
    )

    val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
    val plantAdapter = moshi.adapter(PlantKotlinData::class.java)

    logJson<PlantKotlinData>(plant,plantAdapter)
}

5、InputSteam 流的解析

// import okio.buffer
// import okio.source
suspend fun inputStream(context: Context){
    coroutineScope {
        try {
            val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()

            val inputStream = context.assets.open("plants.json")

            val plantListType = Types.newParameterizedType(List::class.java, Plant::class.java)
            val plantListAdapter = moshi.adapter<List<Plant>>(plantListType)

            val plantList = plantListAdapter.fromJson(inputStream.source().buffer()) ?: emptyList()
            logJson<List<Plant>>(plantList,plantListAdapter)
        }catch (e:Exception){
           log("數(shù)據(jù)流解析失敗")
        }
    }

}

6、Kotlin OutputSteam

  • 對象以 JSON 的數(shù)據(jù) 寫入文件
  • 泛型的的轉(zhuǎn)換
fun <T> outStream(obj: T, context: Context) {
    val file = File(context.cacheDir, "textKotlin.txt")
    if (!file.exists()) file.createNewFile()
    log("${file.absolutePath} : ${file.exists()}")
    val fileOutputStream = FileOutputStream(file)
    val moshi = Moshi.Builder().build()
    
    val adapter = moshi.adapter(obj!!::class.java as Class<T>?) //根據(jù)泛型獲取adapter
    
    val out = fileOutputStream.sink().buffer() //OutputStream 轉(zhuǎn)化為 Sink.buffer
    adapter.toJson(out, obj) //對象數(shù)據(jù)的寫入
    
    out.flush()
    log("kotlin end")
}

7、Java OutputSteam

  • 對象以 JSON 的數(shù)據(jù) 寫入文件
  • 泛型的的轉(zhuǎn)換
public static <T> void outStream(T obj, Context context)  {
    try {
        File file = new File(context.getCacheDir(),"text.txt");
        if(!file.exists()) file.createNewFile();
        log(file.getAbsolutePath() +":" +file.exists());
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        Moshi moshi = new Moshi.Builder().build();

        //根據(jù)泛型獲取adapter
        JsonAdapter<T> adapter = moshi.adapter((Class<T>) obj.getClass());

        //OutputStream 轉(zhuǎn)化為 Sink.buffer
        BufferedSink out = Okio.buffer(Okio.sink(fileOutputStream));

        //對象數(shù)據(jù)的寫入
        adapter.toJson(out, obj);

        out.flush();
        log("java end");
    }catch (Exception e){
        Log.e("moshi",  e.toString());
    }
}

8、自定義 json Adapter

class CardAdapter {

    @ToJson
    fun toJson(card: Card) = card.rank + card.suit.toString()

    @FromJson
    fun fromJson(card: String): Card {
        if (card.length != 2) throw JsonDataException("Unknown card: $card")
        val rank = card[0]
        return when (card[1]) {
            'C' -> Card(rank, Suit.CLUBS)
            'D' -> Card(rank, Suit.DIAMONDS)
            'H' -> Card(rank, Suit.HEARTS)
            'S' -> Card(rank, Suit.SPADES)
            else -> throw JsonDataException("unknown suit: $card")
        }
    }
}

fun parserCustom(){
    val text = """
        {
          "hidden_card": "6S",
          "visible_cards":[
            "4C",
            "AH"
          ]
        }
    """.trimIndent()

    val moshi = Moshi.Builder().add(CardAdapter()).add(KotlinJsonAdapterFactory()).build()
    val jsonAdapter = moshi.adapter(BlackjackHand::class.java)

    val blackjackHand = jsonAdapter.fromJson(text)
    log(blackjackHand.toString())
}

9、base64 轉(zhuǎn)換

fun base64Decode() {
    val json = "\"TW9zaGksIE9saXZlLCBXaGl0ZSBDaGluPw\""

    val moshi = Moshi.Builder().add(ByteString::class.java, Base64ByteStringAdapter()).build()
    val jsonAdapter: JsonAdapter<ByteString> = moshi.adapter(ByteString::class.java)

    val byteString: ByteString = jsonAdapter.fromJson(json)
    log(byteString.toString()) //輸出 [text=Moshi, Olive, White Chin?]
}

class Base64ByteStringAdapter : JsonAdapter<ByteString>() {
    override fun fromJson(reader: JsonReader): ByteString? {
        val base64: String = reader.nextString()
        println(base64)
        return base64.decodeBase64()
    }

    override fun toJson(writer: JsonWriter, value: ByteString?) {
        val string = value?.base64()
        writer.value(string)
    }
}

10、自定義 AdapterFactory

fun customAdapterFactory(){
    val moshi = Moshi.Builder().add(SortedSetAdapterFactory()).build()
    val jsonAdapter: JsonAdapter<SortedSet<String>> = moshi.adapter(
        Types.newParameterizedType(
            SortedSet::class.java, String::class.java
        )
    )

    val model: TreeSet<String> = TreeSet()
    model.add("a")
    model.add("b")
    model.add("d")
    model.add("c")

    val json = jsonAdapter.toJson(model)
    log(json)
}

class SortedSetAdapter<T>(private val elementAdapter:JsonAdapter<T>): JsonAdapter<SortedSet<T>>() {
    override fun fromJson(reader: JsonReader): SortedSet<T> {
        val result: TreeSet<T> = TreeSet()
        reader.beginArray()
        while (reader.hasNext()) {
            elementAdapter.fromJson(reader)?.let { result.add(it) }
        }
        reader.endArray()
        return result
    }

    override fun toJson(writer: JsonWriter, value: SortedSet<T>?) {
        writer.beginArray()
        if(value != null) {
            for (element in value) {
                elementAdapter.toJson(writer, element)
            }
        }
        writer.endArray()
    }

}

class SortedSetAdapterFactory:JsonAdapter.Factory {
    override fun create(
        type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi
    ): JsonAdapter<*>? {
        if(annotations.isNotEmpty()) return null

        if(type !is ParameterizedType)return null

        if(type.rawType != SortedSet::class.java) return null

        val elementType = type.actualTypeArguments[0]
        val elementAdapter:JsonAdapter<Any?> = moshi.adapter(elementType)
        return SortedSetAdapter(elementAdapter).nullSafe()
    }

}

11、自定義代理 Delegate

fun customAdapterWithDelegate() {
    val data = """
  [
    {
        "name":"not-started"
    },
    {
        "name":"in-progress"
    },
    {
        "name":"in-progress2"
    },
    {
        "name":"rejected"
    },
    {
        "name":"completed"
    }
]
    """.trimIndent()

    val moshi = Moshi.Builder().add(StageAdapter()).add(KotlinJsonAdapterFactory()).build()
    val jsonAdapter = moshi.adapter<List<StageEle>>(
        Types.newParameterizedType(
            List::class.java,
            StageEle::class.java
        )
    )
    log(jsonAdapter.fromJson(data).toString())
}


class StageAdapter {
    @FromJson
    fun fromJson(jsonReader: JsonReader, delegate: JsonAdapter<Stage>): Stage {
        val value = jsonReader.nextString()

        return if (value.startsWith("in-progress")) {
            Stage.IN_PROGRESS
        } else {
            delegate.fromJsonValue(value) ?: Stage.IN_PROGRESS
        }
    }
}

enum class Stage {
    @Json(name = "not-started") NOT_STARTED, @Json(name = "in-progress") IN_PROGRESS,
    @Json(name = "rejected") REJECTED, @Json(name = "completed") COMPLETED
}

data class StageEle(val name: Stage)

12、JsonQualifier 顏色轉(zhuǎn)換

class ColorAdapter {

    @ToJson
    fun toJson(@HexColor rgb: Int): String = String.format("#%06x", rgb)

    @FromJson
    @HexColor
    fun fromJson(rgb: String): Int = Integer.parseInt(rgb.substring(1), 16)
}

@Retention(AnnotationRetention.RUNTIME) @JsonQualifier annotation class HexColor

internal class Rectangle {
    private var hidth = 0
    private val height = 0

    @HexColor var color = 0override fun toString(): String {
        return String.format("%dx%d #%06x ->%d", width, height, color, color)
    }
}

fun customQualifier() {
    val data = """
        {
            "color":"#ff0000",
            "height":768,
            "width":1024
        }
    """.trimIndent()

    val moshi = Moshi.Builder().add(ColorAdapter()).add(KotlinJsonAdapterFactory()).build()
    val jsonAdapter = moshi.adapter(
        Rectangle::class.java
    )

    val rectangle: Rectangle = jsonAdapter.fromJson(data)
    log(rectangle.toString())
}

12、跳過錯誤值,并把錯誤值設(shè)置為默認值

class DefaultOnDataMismatchAdapter<T> private constructor(private val delegate: JsonAdapter<T>, private val defaultValue: T) :
    JsonAdapter<T>() {
    override fun fromJson(reader: JsonReader): T? {
        val peeked = reader.peekJson()
        return try {
            delegate.fromJson(peeked)
        } catch (e: Exception) {
            defaultValue
        } finally {
            peeked.close()

            // Skip the value back on the reader, no matter the state of the peeked reader.
            reader.skipValue()
        }
    }

    override fun toJson(writer: JsonWriter, value: T?) {
        delegate.toJson(writer, value)
    }

    companion object{
        fun <T>newFactory(type:Class<T>,defaultValue: T): Factory =object :Factory{
            override fun create(
                requestedType: Type, annotations: MutableSet<out Annotation>, moshi: Moshi
            ): JsonAdapter<T>? {
                if (type != requestedType) return null
                val delegate: JsonAdapter<T> = moshi.nextAdapter(this, type, annotations)
                return DefaultOnDataMismatchAdapter(delegate, defaultValue)
            }

        }
    }
}

fun recoverFromTypeMismatch() {
    // 只接收 CLUBS(梅花) ,DIAMONDS(方塊),HEARTS(紅桃), SPADES(黑桃) 所以 STARS 自動轉(zhuǎn)化為 Suit.CLUBS
    val json = """
        ["DIAMONDS", "STARS", "HEARTS"]
    """.trimIndent()

    val moshi =
        Moshi.Builder().add(newFactory(Suit::class.java, Suit.CLUBS))
            .build()
    val jsonAdapter: JsonAdapter<List<Suit>> = moshi.adapter(
        Types.newParameterizedType(
            MutableList::class.java, Suit::class.java
        )
    )

    log(jsonAdapter.fromJson(json).toString())
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容