首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Retrofit Moshi无法为java.util.HashMap创建@Body转换器

基础概念

Retrofit 是一个用于 Android 和 Java 的 RESTful HTTP 客户端库,它简化了与 Web 服务的交互。Moshi 是一个现代的 JSON 库,用于在 Java 中解析和生成 JSON 数据。Retrofit 使用转换器(Converter)将数据在 Java 对象和 JSON 之间进行转换。

问题描述

在使用 Retrofit 和 Moshi 时,可能会遇到 java.util.HashMap 无法被转换为 @Body 的问题。这是因为 Moshi 默认情况下不支持 HashMap 的转换。

原因

Moshi 默认情况下不支持 HashMap 的转换,因为它不知道如何将 HashMap 转换为 JSON 或从 JSON 转换回 HashMap

解决方法

方法一:使用自定义的 JsonAdapter

你可以创建一个自定义的 JsonAdapter 来处理 HashMap 的转换。

代码语言:txt
复制
import com.squareup.moshi.*;
import retrofit2.Retrofit;
import retrofit2.converter.moshi.MoshiConverterFactory;

import java.lang.reflect.Type;
import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        Moshi moshi = new Moshi.Builder()
                .add(new HashMapAdapter())
                .build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.example.com/")
                .addConverterFactory(MoshiConverterFactory.create(moshi))
                .build();

        // 继续使用 retrofit 进行 API 调用
    }

    static class HashMapAdapter {
        @FromJson
        public HashMap<String, Object> fromJson(JsonReader reader) throws IOException {
            HashMap<String, Object> map = new HashMap<>();
            reader.beginObject();
            while (reader.hasNext()) {
                String key = reader.nextName();
                Object value = readJsonValue(reader);
                map.put(key, value);
            }
            reader.endObject();
            return map;
        }

        @ToJson
        public void toJson(JsonWriter writer, HashMap<String, Object> map) throws IOException {
            writer.beginObject();
            for (HashMap.Entry<String, Object> entry : map.entrySet()) {
                writer.name(entry.getKey());
                writeJsonValue(writer, entry.getValue());
            }
            writer.endObject();
        }

        private Object readJsonValue(JsonReader reader) throws IOException {
            switch (reader.peek()) {
                case STRING:
                    return reader.nextString();
                case NUMBER:
                    return reader.nextDouble();
                case BOOLEAN:
                    return reader.nextBoolean();
                case NULL:
                    reader.nextNull();
                    return null;
                case BEGIN_OBJECT:
                    return readJsonObject(reader);
                case BEGIN_ARRAY:
                    return readJsonArray(reader);
                default:
                    throw new IllegalStateException("Unexpected value: " + reader.peek());
            }
        }

        private void writeJsonValue(JsonWriter writer, Object value) throws IOException {
            if (value == null) {
                writer.nullValue();
            } else if (value instanceof String) {
                writer.value((String) value);
            } else if (value instanceof Number) {
                writer.value(((Number) value).doubleValue());
            } else if (value instanceof Boolean) {
                writer.value((Boolean) value);
            } else if (value instanceof HashMap) {
                writeJsonObject(writer, (HashMap<String, Object>) value);
            } else if (value instanceof Iterable) {
                writeJsonArray(writer, (Iterable<?>) value);
            } else {
                throw new IllegalArgumentException("Unsupported type: " + value.getClass());
            }
        }

        private HashMap<String, Object> readJsonObject(JsonReader reader) throws IOException {
            HashMap<String, Object> map = new HashMap<>();
            reader.beginObject();
            while (reader.hasNext()) {
                String key = reader.nextName();
                Object value = readJsonValue(reader);
                map.put(key, value);
            }
            reader.endObject();
            return map;
        }

        private void writeJsonObject(JsonWriter writer, HashMap<String, Object> map) throws IOException {
            writer.beginObject();
            for (HashMap.Entry<String, Object> entry : map.entrySet()) {
                writer.name(entry.getKey());
                writeJsonValue(writer, entry.getValue());
            }
            writer.endObject();
        }

        private ArrayList<Object> readJsonArray(JsonReader reader) throws IOException {
            ArrayList<Object> list = new ArrayList<>();
            reader.beginArray();
            while (reader.hasNext()) {
                Object value = readJsonValue(reader);
                list.add(value);
            }
            reader.endArray();
            return list;
        }

        private void writeJsonArray(JsonWriter writer, Iterable<?> array) throws IOException {
            writer.beginArray();
            for (Object item : array) {
                writeJsonValue(writer, item);
            }
            writer.endArray();
        }
    }
}

方法二:使用 @JsonClass(generateAdapter = true) 注解

你可以创建一个包装类,并使用 @JsonClass(generateAdapter = true) 注解来生成适配器。

代码语言:txt
复制
import com.squareup.moshi.JsonClass;
import com.squareup.moshi.Moshi;
import retrofit2.Retrofit;
import retrofit2.converter.moshi.MoshiConverterFactory;

import java.util.HashMap;

@JsonClass(generateAdapter = true)
public class MapWrapper {
    public HashMap<String, Object> map;

    public MapWrapper(HashMap<String, Object> map) {
        this.map = map;
    }
}

public class Main {
    public static void main(String[] args) {
        Moshi moshi = new Moshi.Builder().build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.example.com/")
                .addConverterFactory(MoshiConverterFactory.create(moshi))
                .build();

        // 使用 MapWrapper 进行 API 调用
        MapWrapper wrapper = new MapWrapper(new HashMap<>());
        // 继续使用 retrofit 进行 API 调用
    }
}

应用场景

这种方法适用于需要将 HashMap 作为请求体发送到服务器的场景,例如动态构建请求参数时。

参考链接

通过以上方法,你可以解决 Retrofit 和 Moshi 无法为 java.util.HashMap 创建 @Body 转换器的问题。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

没有搜到相关的视频

领券