Пользовательский адаптер Moshi с RxAndroid & Retrofit & Kotlin

После настройки проекта Kotlin для Android я написал простой MainActivity.kt . Он назывался Retrofit для получения файла JSON, который содержал следующие данные:

 {
     «сообщение»: «успех»,
     «пользователь»: {
         "username": "Eric"
     }
 }

Теперь я хочу использовать Moshi для преобразования данных JSON в класс Kotlin, так что вот два класса, которые отражают вышеупомянутую структуру JSON:

 class User (var username: String)

 class UserJson (сообщение var: String, var user: User)

И адаптер пользовательского типа для Moshi:

 class UserAdapter {
     @FromJson fun fromJson (userJson: UserJson): Пользователь {
         Log.d («MyLog», «message = $ {userJson.message}») // = успех
         Log.d («MyLog», «user = $ {userJson.user}») // = null

         return userJson.user
     }
 }

Когда он переходит в функцию fromJson() , userJson.message = "success" как и ожидалось. Но странно, что userJson.user имеет значение null , которое должно быть User(username="Eric") .

Я новичок в Moshi и Kotlin, и я уже застрял в этой проблеме около 10 часов. Пожалуйста, помогите мне. Спасибо за любую помощь.

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

Ниже приведен весь код MainActivity.kt (только 50 строк):

 class MainActivity: AppCompatActivity () {

     override fun onCreate (savedInstanceState: Bundle?) {
         super.onCreate (savedInstanceState)
         setContentView (R.layout.activity_main)

         // Адаптеры пользовательского типа для 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 ())
                 }
     }
 }


 // ========== Для дооснащения ==========
 интерфейс AccountService {

     @GET ( "U / 17350105 / test.json")
     fun signUpAnonymously (): Наблюдаемый <Пользователь>

 }


 // ========== Для Моши ==========
 class User (var username: String)

 class UserJson (сообщение var: String, var user: User)

 class UserAdapter {

     @FromJson fun fromJson (userJson: UserJson): Пользователь {
         Log.d («MyLog», «message = $ {userJson.message}») // = успех
         Log.d («MyLog», «user = $ {userJson.user}») // = null

         return userJson.user
     }

 }

build.gradle :

 компилировать "io.reactivex.rxjava2: rxjava: 2.0.0"
 компилировать "io.reactivex.rxjava2: rxandroid: 2.0.0"

 компилировать "com.android.support:appcompat-v7:25.0.0"

 compile "com.squareup.retrofit2: модифицировать: 2.1.0"
 compile "com.squareup.retrofit2: converter-moshi: 2.1.0"
 compile 'com.jakewharton.retrofit: retrofit2-rxjava2-adapter: 1.0.0'

Еще раз спасибо.

Вы можете решить проблему, изменив свой код, чтобы сделать что-то вроде ниже.

В основном в вашем случае, когда пользовательский UserAdapter зарегистрирован, он сообщает moshi, что он может создавать User только из объекта UserJson . Следовательно, Moshi не распознает объект JSON с ключевым словом user .

Добавив косвенность в форме User1 (пожалуйста, извините соглашение об именах), UserJson правильно создается с User1 из 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) } } 

Если вам нужен только объект User . Существует библиотека под названием Moshi-Lazy-Adapters, которая предоставляет аннотацию @Wrapped , которая позволяет указать путь к желаемому obejct. Все, что вам нужно сделать, это добавить соответствующий адаптер к экземпляру moshi и задать код службы для:

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

Нет необходимости в каких-либо других адаптерах.