Adaptador personalizado de Moshi con RxAndroid & Retrofit & Kotlin

Después de configurar Kotlin para el proyecto de Android, escribí un sencillo MainActivity.kt . Llamó a Retrofit para get un file JSON que contenía los siguientes datos:

 {
     "post": "éxito",
     "usuario": {
         "nombre de usuario": "Eric"
     }
 }

Ahora quiero usar Moshi para convertir los datos JSON a la class de Kotlin, así que aquí están las dos classs para reflejar la estructura JSON anterior:

 Usuario de class (nombre de usuario var: String)

 class UserJson (var message: String, var user: User)

Y un adaptador de tipo personalizado para Moshi:

 class UserAdapter {
     @FromJson divertido deJson (usuarioJson: UserJson): Usuario {
         Log.d ("MyLog", "message = $ {userJson.message}") // = éxito
         Log.d ("MyLog", "usuario = $ {usuarioJson.usuario}") // = nulo

         return userJson.user
     }
 }

Cuando entra en la function de fromJson() , userJson.message = "success" como se esperaba. Pero lo extraño es que userJson.user es null , que debería ser User(username="Eric") .

Soy nuevo en Moshi y Kotlin, y ya me he quedado con este problema durante aproximadamente 10 horas. Por favor, ayúdame. Gracias por cualquier ayuda.

========================================

El siguiente es el código completo de MainActivity.kt (solo 50 líneas):

 class MainActivity: AppCompatActivity () {

     anular diversión onCreate (savedInstanceState: Bundle?) {
         super.onCreate (savedInstanceState)
         setContentView (R.layout.activity_main)

         // Adaptadores de tipo personalizado para Moshi
         val userMoshi = Moshi.Builder (). add (UserAdapter ()). build ()

         val retrofit = Retrofit.Builder ()
                 .baseUrl ("https://dl.dropboxusercontent.com/")
                 .addConverterFactory (MoshiConverterFactory.create (userMoshi))
                 .addCallAdapterFactory (RxJava2CallAdapterFactory.create ())
                 .build()

         val accountService = retrofit.create (AccountService :: class.java)

         accountService.signUpAnonymously ()
                 .subscribeOn (Schedulers.io ())
                 .observeOn (AndroidSchedulers.mainThread ())
                 .subscribe {user ->
                     Log.d ("MyLog", user.toString ())
                 }
     }
 }


 // ========== Para Retrofit ==========
 interfaz AccountService {

     @GET ("u / 17350105 / test.json")
     diversión signUpAnonymously (): Observable <Usuario>

 }


 // ========== Para Moshi ==========
 Usuario de class (nombre de usuario var: String)

 class UserJson (var message: String, var user: User)

 class UserAdapter {

     @FromJson divertido deJson (usuarioJson: UserJson): Usuario {
         Log.d ("MyLog", "message = $ {userJson.message}") // = éxito
         Log.d ("MyLog", "usuario = $ {usuarioJson.usuario}") // = nulo

         return userJson.user
     }

 }

El build.gradle es:

 compile "io.reactivex.rxjava2: rxjava: 2.0.0"
 compile "io.reactivex.rxjava2: rxandroid: 2.0.0"

 comstackr "com.android.support:appcompat-v7:25.0.0"

 compile "com.squareup.retrofit2: retrofit: 2.1.0"
 comstack "com.squareup.retrofit2: converter-moshi: 2.1.0"
 comstackr 'com.jakewharton.retrofit: retrofit2-rxjava2-adapter: 1.0.0'

Gracias de nuevo.

Puede resolver el problema cambiando su código para hacer algo como a continuación.

Básicamente en su caso cuando el UserAdapter está registrado, le dice a moshi que puede crear un User solo desde el object UserJson . Por lo tanto, Moshi no reconoce el object JSON con el user palabra key.

Al agregar una indirección en forma de User1 (perdón por la convención de nomenclatura), UserJson se crea correctamente con User1 de JSON.

 class User(var username: String) class User1(var username: String) // I introduced this class class UserJson(var message: String, var user: User1) // changed User to User1 class UserAdapter { @FromJson fun fromJson(userJson: UserJson): User { println("message = ${userJson.message}") println("user = ${userJson.user}") return User(userJson.user.username) } } 

Si solo necesitas el object User . Hay una biblioteca llamada Moshi-Lazy-Adapters que proporciona una anotación @Wrapped , que permite especificar la ruta al object deseado. Todo lo que tiene que hacer es agregar el adaptador correspondiente a su instancia de moshi y cambiar el código de service a:

 interface AccountService { @GET("u/17350105/test.json") @Wrapped("user") fun signUpAnonymously() : Observable<User> } 

No es necesario ningún otro adaptador personalizado.

  • Mockito querido pero no invocado
  • Asunto de RxJava: escuche el tipo diferente que el que emite
  • Llamada asincrónica para cada elemento dentro de una colección
  • Temporizador RxJava2 y combinar
  • RxAndroid, cómo detectar si observable ha finalizado la emisión
  • Observable.just () que devuelve Unidad en Kotlin
  • RX java / Android cómo lograr este brindis en cada clic usando el operador de rebote
  • RxJava2 cómo separar diferentes implementaciones de emisor observable
  • ¿Hay alguna manera de cambiar mi método a la stream Observable que será una cadena de modificadores?
  • Llamar a un RxJava Single In Kotlin Lambda
  • Cómo llenar una vista de list usando Kotlin, retroadaptación y RXjava