NiceToMytyuk
NiceToMytyuk

Reputation: 4307

How to ignore field when Serializing in moshi?

Im new to Moshi and Kotlin and i actually made two methods which returns data from my Room database and make from two objects only one which then i'm going to serialize via Moshi.

Is there a way to ignore or remove some fields from serialization? i tried by using @Transient but that throw lot of errors cause of my model structure.

Here is how my models looks like:

@JsonClass(generateAdapter = true)
@Entity(tableName = "corpo", foreignKeys = [
    ForeignKey(
        entity = Testata::class,
        parentColumns = ["id"],
        childColumns = ["id_testata"],
        onDelete = CASCADE
    )
], indices = [ Index("id_testata") ], primaryKeys = [
    "barcode", "id_testata"
])
data class Corpo(
    var barcode: String,
    var desc: String?, // ignore this
    @ColumnInfo(defaultValue = "PZ")
    var um: String, // ignore this
    var qta: Float, 
    var id_testata: Int // i have to ignore this
)

And

@JsonClass(generateAdapter = true)
@Entity(tableName = "testata")
data class Testata(
    @PrimaryKey(autoGenerate = true)
    var id: Int,
    var cod: String,
    var tipo: String,
    var cod_fornitore: String,
    var desc_fornitore: String, // ignore this
    var data: String,
    var inviato: Boolean // ignore this
){
    constructor(cod: String, tipo: String, cod_fornitore: String, desc_fornitore: String, data: String, inviato: Boolean)
            : this(0, cod, tipo, cod_fornitore, desc_fornitore, data, inviato)
}

@JsonClass(generateAdapter = true) // this is my class which combine the two classes from Room db
data class Documento(
    var testata: Testata,
    var corpo: List<Corpo>
)

And here i get my serialized object via Moshi:

        val moshi = Moshi.Builder().build()
        val jsonAdapter: JsonAdapter<Documento> = moshi.adapter(Documento::class.java)
        val documento = Documento(corpoViewModel.selectTestata(testata.id), corpoViewModel.selectCorpo(testata.id))
        val json = jsonAdapter.toJson(documento)

At this point how can i ignore the fields i commented and remove them from my serialization?

Upvotes: 1

Views: 1478

Answers (1)

Pietro Scarampella
Pietro Scarampella

Reputation: 472

I see 2 viable options for your use case.

Before you go you will need 2 separate classes for the desired serialized json and you can choose:

  1. Using a Mapper to map one dto to the other.

  2. Using a Moshi's Custom Type Adapter for handling the mapping of both Testata and Corpo

First of all, define the two desired models:

data class JsonCorpo(
    var barcode: String,
    var qta: Float, 
)

data class JsonTestata(
    var id: Int,
    var cod: String,
    var tipo: String,
    var cod_fornitore: String,
    var data: String,
)

And use JsonTestata and JsonCorpo instead of Testata and Corpo, inside your combined Documento class

Option 1

I usually have an interface for mappers. This is handy if you use an injection framework like Dagger because you don't have to remember the name of the mapper class.

/**
 * Base mapper to convert [Input] type to [Output] type.
 */
interface Mapper<Input, Output> {
    /**
     * Transforms [input] into [Output].
     *
     * @param input the input to be transformed
     * @return transformation result [Output]
     */
    fun map(input: Input): Output

    /**
     * Transforms a [List] of [Input] into a [List] of [Output].
     *
     * @param input The input to be transformed
     * @return transformation result
     */
    fun map(input: List<Input>): List<Output> {
        val result: MutableList<Output> = LinkedList()
        for (item in input) {
            result.add(map(item))
        }
        return result
    }
}

And declare each mapping:

class CorpoToJsonCorpoMapper: Mapper<Corpo, SerializedCorpo> {
    
    override fun map(input: Corpo): SerializedCorpo = with(input) {
        SerializedCorpo(barcode, qta)
    }
}

class TestataToJsonTestataMapper: Mapper<Testata, SerializedTestata> {
    
    override fun map(input: Testata): SerializedTestata = with(input) {
        SerializedTestata(id, cod, tipo, cod_fornitore, data)
    }
}

And then you can use the two mappers to map the result from

corpoViewModel.selectTestata(testata.id) and corpoViewModel.selectCorpo(testata.id)

Option 2

You let a Moshi's adapter take care of the mapping:

class CorpoJsonAdapter {
  @FromJson Event corpoFromJson(JsonCorpo jsonCorpo) {
    return Corpo(
       ...
       // Here handle the deserialization
    );
  }

  @ToJson JsonCorpo corpoToJson(Corpo corpo) {
     return JsonCorpo(corpo.barcode, corpo.qta)
  }
}

and similar declaring a TestataJsonAdapter to handle the serialization and deserialization for the Testata class.

Upvotes: 2

Related Questions