如何用Gson/Jackson将JSON列表包装为带Map的对象(纯Java无Spring)
刚好之前做过类似的纯Java API客户端需求,给你分享下用Gson和Jackson分别实现的具体方案,完全不用Spring这类框架,完美匹配你的场景~
首先先明确下你提到的两种JSON结构示例,方便后续代码对应:
第一种(任意键但字段相同的对象):
{ "item_001": {"id": 1, "name": "Apple"}, "item_002": {"id": 2, "name": "Banana"}, "item_003": {"id": 3, "name": "Cherry"} }需要转成包含列表的包装对象(比如
ItemListWrapper,里面有List<Item>)
第二种(带列表的对象):
{ "code": 200, "message": "success", "data": [{"id":1,"name":"Apple"}, {"id":2,"name":"Banana"}] }直接转成对应结构的对象(比如
ApiResponse<Item>)
用Gson实现的方案
1. 先定义基础模型类
先把需要的实体类和包装类写好:
// 基础数据实体 class Item { private int id; private String name; // 自动生成getter、setter、toString方法即可 } // 第一种JSON对应的包装类 class ItemListWrapper { private List<Item> items; public ItemListWrapper(List<Item> items) { this.items = items; } // getter、setter方法 public List<Item> getItems() { return items; } public void setItems(List<Item> items) { this.items = items; } } // 第二种JSON的通用响应类 class ApiResponse<T> { private int code; private String message; private List<T> data; // 自动生成getter、setter、toString方法 }
2. 自定义反序列化器处理第一种JSON
因为第一种JSON是键值对结构,需要把所有值提取出来转成列表,再包装到ItemListWrapper里,所以写个自定义反序列化器:
import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonDeserializationContext; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import java.util.Map; class ItemListWrapperDeserializer implements JsonDeserializer<ItemListWrapper> { @Override public ItemListWrapper deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); List<Item> items = new ArrayList<>(); // 遍历所有键值对,把值转成Item对象加入列表 for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) { Item item = context.deserialize(entry.getValue(), Item.class); items.add(item); } return new ItemListWrapper(items); } }
3. 构建通用API客户端
写一个通用的客户端类,支持传入期望的响应类型,自动处理两种JSON结构:
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; class GsonApiClient { private final Gson gson; public GsonApiClient() { // 注册自定义反序列化器,让Gson识别第一种JSON的处理逻辑 this.gson = new GsonBuilder() .registerTypeAdapter(ItemListWrapper.class, new ItemListWrapperDeserializer()) .create(); } // 处理非泛型的响应类型(比如ItemListWrapper) public <T> T fetchData(String apiUrl, Class<T> responseType) throws Exception { HttpURLConnection conn = (HttpURLConnection) new URL(apiUrl).openConnection(); conn.setRequestMethod("GET"); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } return gson.fromJson(response.toString(), responseType); } finally { conn.disconnect(); } } // 处理带泛型的响应类型(比如ApiResponse<Item>) public <T> T fetchGenericData(String apiUrl, TypeToken<T> typeToken) throws Exception { HttpURLConnection conn = (HttpURLConnection) new URL(apiUrl).openConnection(); conn.setRequestMethod("GET"); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } return gson.fromJson(response.toString(), typeToken.getType()); } finally { conn.disconnect(); } } }
4. 使用示例
public class Main { public static void main(String[] args) throws Exception { GsonApiClient client = new GsonApiClient(); // 处理第一种JSON,转成ItemListWrapper String url1 = "https://your-api.com/items-as-map"; ItemListWrapper wrapper = client.fetchData(url1, ItemListWrapper.class); System.out.println("第一种JSON处理结果:" + wrapper.getItems()); // 处理第二种JSON,转成ApiResponse<Item> String url2 = "https://your-api.com/items-as-list"; ApiResponse<Item> response = client.fetchGenericData(url2, new TypeToken<ApiResponse<Item>>() {}); System.out.println("第二种JSON处理结果:" + response.getData()); } }
用Jackson实现的方案
如果你更倾向于Codehaus Jackson(不过现在主流是FasterXML Jackson,这里用FasterXML的示例,API和Codehaus类似,调整依赖即可):
1. 定义模型类
和Gson的模型类基本一致,可添加Jackson注解辅助序列化:
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; class Item { private int id; private String name; // getter、setter、toString } class ItemListWrapper { private List<Item> items; @JsonCreator public ItemListWrapper(@JsonProperty("items") List<Item> items) { this.items = items; } // getter、setter } class ApiResponse<T> { private int code; private String message; private List<T> data; // getter、setter、toString }
2. 自定义反序列化器
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; class ItemListWrapperDeserializer extends JsonDeserializer<ItemListWrapper> { @Override public ItemListWrapper deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode rootNode = p.getCodec().readTree(p); List<Item> items = new ArrayList<>(); // 遍历所有子节点,转成Item对象 Iterator<JsonNode> elements = rootNode.elements(); while (elements.hasNext()) { JsonNode itemNode = elements.next(); Item item = p.getCodec().treeToValue(itemNode, Item.class); items.add(item); } return new ItemListWrapper(items); } }
3. 构建API客户端
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.core.type.TypeReference; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; class JacksonApiClient { private final ObjectMapper objectMapper; public JacksonApiClient() { this.objectMapper = new ObjectMapper(); // 注册自定义反序列化器 SimpleModule module = new SimpleModule(); module.addDeserializer(ItemListWrapper.class, new ItemListWrapperDeserializer()); objectMapper.registerModule(module); } // 处理非泛型类型 public <T> T fetchData(String apiUrl, Class<T> responseType) throws Exception { HttpURLConnection conn = (HttpURLConnection) new URL(apiUrl).openConnection(); conn.setRequestMethod("GET"); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { return objectMapper.readValue(reader, responseType); } finally { conn.disconnect(); } } // 处理带泛型的类型 public <T> T fetchGenericData(String apiUrl, TypeReference<T> typeRef) throws Exception { HttpURLConnection conn = (HttpURLConnection) new URL(apiUrl).openConnection(); conn.setRequestMethod("GET"); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { return objectMapper.readValue(reader, typeRef); } finally { conn.disconnect(); } } }
4. 使用示例
public class Main { public static void main(String[] args) throws Exception { JacksonApiClient client = new JacksonApiClient(); // 处理第一种JSON String url1 = "https://your-api.com/items-as-map"; ItemListWrapper wrapper = client.fetchData(url1, ItemListWrapper.class); System.out.println("第一种JSON处理结果:" + wrapper.getItems()); // 处理第二种JSON String url2 = "https://your-api.com/items-as-list"; ApiResponse<Item> response = client.fetchGenericData(url2, new TypeReference<ApiResponse<Item>>() {}); System.out.println("第二种JSON处理结果:" + response.getData()); } }
一些额外注意点
- 依赖方面:Gson只需要引入
com.google.code.gson:gson;Jackson引入com.fasterxml.jackson.core:jackson-databind即可(Codehaus Jackson的话依赖是org.codehaus.jackson:jackson-mapper-asl,API略有不同但核心逻辑一致)。 - 如果第一种JSON的键有业务价值,你可以修改包装类,比如改成
List<Map.Entry<String, Item>>或者自定义NamedItem类(包含键和Item对象),只需要调整反序列化器的逻辑即可。 - 客户端的HTTP请求部分可以按需扩展,比如添加请求头、支持POST方法、超时设置等,上面的示例是最基础的GET请求实现。
内容的提问来源于stack exchange,提问作者Virkom
相关产品推荐
相关产品推荐

