RetrofitにおけるConverterによるデータ変換処理

22584 ワード

retrofitにはDate、xxEntityなどのカスタムデータ型が転送されますが、これらのデータ型retrofitはサポートされていません.処理のcoverterを提供する必要があります.
  • @QueryからDateパラメータが入力され、インタフェースは以下の通り:
  • 	/**
         *    banner
         *   date,retrofite      
         */
        @GET("banner/json")
        fun getBanner(@Query("date" ) date: Date): Call<BaseEntity<Any>>
    
  • は、カスタムCoverterおよびConverterFactory
  • を提供する.
    /**
     * Created by mayi on 2020-05-25.
     *
     */
    class DateConverter :Converter<Date,String> {
    
        override fun convert(value: Date): String? {// Date       String,  okhttp
           return SimpleDateFormat("yyyyMMdd_hhmmss").format(value)
        }
    
    }
    
    /**
     * Created by mayi on 2020-05-25.
     */
    class DateConverterFactory :Converter.Factory() {
    
    
        override fun stringConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<*, String>? {
    
            //  type  Date    ,     
            if (type == Date::class.java){
                return DateConverter()
            }
    
            return super.stringConverter(type, annotations, retrofit)
        }
    
    
        companion object{
            fun create(): Converter.Factory {
                return DateConverterFactory()
            }
    
        }
    
    }
    
  • Retrofitに登録されている
  •     private val retrofit: Retrofit = Retrofit.Builder().baseUrl(BaseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .addConverterFactory(DateConverterFactory.create())//  Date  Converter Retrofit
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(httpClient)
                .build()
    
  • @POST RequestBodyデータ変換元インタフェース:
  •     /**
         *   
         */
        @FormUrlEncoded
        @POST("user/login")
        fun toLogin(@Field("username") username:String
                    ,@Field("password") password:String):Call<BaseEntity<Any>>
    

    改造後:
        /**
         *   
         */
        @POST("user/login")
        fun toLogin4(@Body params: PkLinkMap):Call<BaseEntity<Any>>
    

    PkLinkMapエンティティ:
    /**
     * Created by mayi on 2020-05-30.
     */
    class PkLinkMap :LinkedHashMap<String,String>()
    

    ConverterとConverterFactoryの提供
    /**
     * Created by mayi on 2020-05-30.
     */
    class PkLinkMapConverter : Converter<PkLinkMap, RequestBody> {
        private val MEDIA_TYPE: MediaType = "application/json; charset=UTF-8".toMediaType()
    
        override fun convert(value: PkLinkMap): RequestBody? {
            value["other_params"] = "this is other params"
            return RequestBody.create(MEDIA_TYPE, value.toJson())
    
        }
    
    }
    
    /**
     * Created by mayi on 2020-05-30.
     */
    class PkLinkMapConverterFactory : Converter.Factory() {
    
    
        override fun requestBodyConverter(type: Type,
                                          parameterAnnotations: Array<Annotation>,
                                          methodAnnotations: Array<Annotation>,
                                          retrofit: Retrofit): Converter<*, RequestBody>? {
    
            //    
            if (type== PkLinkMap::class.java){
                return PkLinkMapConverter()
            }
            return super.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit)
        }
    
        companion object{
    
            fun create(): Converter.Factory {
                return PkLinkMapConverterFactory()
            }
    
        }
    }
    

    原理:Retrofitのパラメータ処理はConverterによって処理されており、Converterはインタフェースであり、特殊なデータ型を処理したい場合は、自分で実現して対応するConcerterFactoryを提供すればよい.
    Converterインタフェースは次のとおりです.
    public interface Converter<F, T> {
      @Nullable T convert(F value) throws IOException;
    
      /** Creates {@link Converter} instances based on a type and target usage. */
      abstract class Factory {
        /**
         * Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
         * {@code type} cannot be handled by this factory. This is used to create converters for
         * response types such as {@code SimpleResponse} from a {@code Call}
         * declaration.
         */
        public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
            Annotation[] annotations, Retrofit retrofit) {
          return null;
        }
    
        /**
         * Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
         * {@code type} cannot be handled by this factory. This is used to create converters for types
         * specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap}
         * values.
         */
        public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
            Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
          return null;
        }
    
        /**
         * Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
         * {@code type} cannot be handled by this factory. This is used to create converters for types
         * specified by {@link Field @Field}, {@link FieldMap @FieldMap} values,
         * {@link Header @Header}, {@link HeaderMap @HeaderMap}, {@link Path @Path},
         * {@link Query @Query}, and {@link QueryMap @QueryMap} values.
         */
        public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
            Retrofit retrofit) {
          return null;
        }
    
        /**
         * Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
         * example, index 1 of {@code Map} returns {@code Runnable}.
         */
        protected static Type getParameterUpperBound(int index, ParameterizedType type) {
          return Utils.getParameterUpperBound(index, type);
        }
    
        /**
         * Extract the raw class type from {@code type}. For example, the type representing
         * {@code List extends Runnable>} returns {@code List.class}.
         */
        protected static Class<?> getRawType(Type type) {
          return Utils.getRawType(type);
        }
      }
    }