关于json对象转为java对象的有关问题
关于json对象转为java对象的问题
先描述下问题:
1、在写junit单元测试用例时,返回的json串转为java对象时不成功!出现错误提示
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.xx.xx.modules.bd.entity.xx.xx。
2、经过debug,发现对象属性全部都自动转为LinkedHashMap了,
content值为:{"statusCode":200,"msg":"成功返回","obj":[{"id":"41","isNewRecord":false,"remarks":"","createDate":"2016-08-28 09:03:52","updateDate":"2016-08-28 09:03:52","xxList":[],"xx":"","xx":"","xx":"","xx":"01","xx":"1","xx":45,"xxList":[]}]}
如图:
3、JsonResp 代码:
package com.xxx.xxx.common.json; import java.io.Serializable; /** * json 返回 * Created by weimingjia on 2016/7/10. */ public class JsonResp implements Serializable{ private int statusCode = 200; //状态码 private String msg; private Object obj; public JsonResp(){} public JsonResp(int statusCode,String msg){ this.statusCode = statusCode; this.msg = msg; } public JsonResp(int statusCode,String msg,Object obj){ this.statusCode = statusCode; this.msg = msg; this.obj = obj; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } public int getStatusCode() { return statusCode; } public void setStatusCode(int statusCode) { this.statusCode = statusCode; } }
4、jsonMapper代码:
/** * Copyright © 2012-2014 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved. */ package com.xxx.xxx.common.mapper; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.TimeZone; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonParser.Feature; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.util.JSONPObject; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * 简单封装Jackson,实现JSON String<->Java Object的Mapper. * 封装不同的输出风格, 使用不同的builder函数创建实例. * @author ThinkGem * @version 2013-11-15 */ public class JsonMapper extends ObjectMapper { private static final long serialVersionUID = 1L; private static Logger logger = LoggerFactory.getLogger(JsonMapper.class); private static JsonMapper mapper; public JsonMapper() { this(Include.NON_NULL); } public JsonMapper(Include include) { // 设置输出时包含属性的风格 if (include != null) { this.setSerializationInclusion(include); } // 允许单引号、允许不带引号的字段名称 this.enableSimple(); // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性 this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 空值处理为空串 this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>(){ @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { jgen.writeString(""); } }); // 进行HTML解码。 /*this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer<String>(){ @Override public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { jgen.writeString(StringEscapeUtils.unescapeHtml4(value)); } }));*/ // 设置时区 this.setTimeZone(TimeZone.getDefault());//getTimeZone("GMT+8:00") } /** * 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用. */ public static JsonMapper getInstance() { if (mapper == null){ mapper = new JsonMapper().enableSimple(); } return mapper; } /** * 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用。 */ public static JsonMapper nonDefaultMapper() { if (mapper == null){ mapper = new JsonMapper(Include.NON_DEFAULT); } return mapper; } /** * Object可以是POJO,也可以是Collection或数组。 * 如果对象为Null, 返回"null". * 如果集合为空集合, 返回"[]". */ public String toJson(Object object) { try { return this.writeValueAsString(object); } catch (IOException e) { logger.warn("write to json string error:" + object, e); return null; } } /** * 反序列化POJO或简单Collection如List<String>. * * 如果JSON字符串为Null或"null"字符串, 返回Null. * 如果JSON字符串为"[]", 返回空集合. * * 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String,JavaType) * @see #fromJson(String, JavaType) */ public <T> T fromJson(String jsonString, Class<T> clazz) { if (StringUtils.isEmpty(jsonString)) { return null; } try { return this.readValue(jsonString, clazz); } catch (IOException e) { logger.warn("parse json string error:" + jsonString, e); return null; } } /** * 反序列化复杂Collection如List<Bean>, 先使用函數createCollectionType构造类型,然后调用本函数. * @see #createCollectionType(Class, Class...) */ @SuppressWarnings("unchecked") public <T> T fromJson(String jsonString, JavaType javaType) { if (StringUtils.isEmpty(jsonString)) { return null; } try { return (T) this.readValue(jsonString, javaType); } catch (IOException e) { logger.warn("parse json string error:" + jsonString, e); return null; } } /** * 構造泛型的Collection Type如: * ArrayList<MyBean>, 则调用constructCollectionType(ArrayList.class,MyBean.class) * HashMap<String,MyBean>, 则调用(HashMap.class,String.class, MyBean.class) */ public JavaType createCollectionType(Class<?> collectionClass, Class<?>... elementClasses) { return this.getTypeFactory().constructParametricType(collectionClass, elementClasses); } /** * 當JSON裡只含有Bean的部分屬性時,更新一個已存在Bean,只覆蓋該部分的屬性. */ @SuppressWarnings("unchecked") public <T> T update(String jsonString, T object) { try { return (T) this.readerForUpdating(object).readValue(jsonString); } catch (JsonProcessingException e) { logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e); } catch (IOException e) { logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e); } return null; } /** * 輸出JSONP格式數據. */ public String toJsonP(String functionName, Object object) { return toJson(new JSONPObject(functionName, object)); } /** * 設定是否使用Enum的toString函數來讀寫Enum, * 為False時時使用Enum的name()函數來讀寫Enum, 默認為False. * 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用. */ public JsonMapper enableEnumUseToString() { this.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); this.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); return this; } /** * 支持使用Jaxb的Annotation,使得POJO上的annotation不用与Jackson耦合。 * 默认会先查找jaxb的annotation,如果找不到再找jackson的。 */ public JsonMapper enableJaxbAnnotation() { JaxbAnnotationModule module = new JaxbAnnotationModule(); this.registerModule(module); return this; } /** * 允许单引号 * 允许不带引号的字段名称 */ public JsonMapper enableSimple() { this.configure(Feature.ALLOW_SINGLE_QUOTES, true); this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); return this; } /** * 取出Mapper做进一步的设置或使用其他序列化API. */ public ObjectMapper getMapper() { return this; } /** * 对象转换为JSON字符串 * @param object * @return */ public static String toJsonString(Object object){ return JsonMapper.getInstance().toJson(object); } /** * JSON字符串转换为对象 * @param jsonString * @param clazz * @return */ public static Object fromJsonString(String jsonString, Class<?> clazz){ return JsonMapper.getInstance().fromJson(jsonString, clazz); } /** * 测试 */ public static void main(String[] args) { List<Map<String, Object>> list = Lists.newArrayList(); Map<String, Object> map = Maps.newHashMap(); map.put("id", 1); map.put("pId", -1); map.put("name", "根节点"); list.add(map); map = Maps.newHashMap(); map.put("id", 2); map.put("pId", 1); map.put("name", "你好"); map.put("open", true); list.add(map); String json = JsonMapper.getInstance().toJson(list); System.out.println(json); } }
5、单元测试用例代码:
package com.xxx.xxx.xx.xxx.xx.xx; import com.google.common.reflect.Reflection; import com.xxx.xxx.common.json.JsonResp; import com.xxxx.xxx.modules.bd.entity.prescription.PactsPrescription; import com.xxxx.xxx.modules.bd.entity.prescription.PactsTemplate; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.junit.Test; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MvcResult; import java.util.ArrayList; import java.util.List; import java.util.Map; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.number.OrderingComparison.greaterThan; import static org.junit.Assert.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; /** * Created by weimingjia on 16-8-27. */ public class PactsPrescriptionRestControllerTest extends PactsTemplateRestControllerTest{ private String path = "/xxx/xx/xx/rest"; @Test public void testGetPactsPrescriptionByTemplateId() throws Exception { Object id = getAddResponseContent(); assertNotNull("xxx id is null",id); assertNotSame("xxx id is empty","",id); logger.info("xxx id is "+id); String pactsTemplateJsonAdd = String.format(pactsTemplateJson, id); PactsTemplate pactsTemplate = jsonMapper.fromJson(pactsTemplateJsonAdd,PactsTemplate.class); System.out.println(pactsTemplate); List<PactsPrescription> prescriptionListCorrect = pactsTemplate.getPrescriptionList(); assertNotNull("根据json文件读取xx模板 is null",prescriptionListCorrect); assertThat("根据json文件读取xx模板,xx集合 is empty",prescriptionListCorrect.size(),greaterThan(0)); PactsPrescription pactsPrescriptionCorrect = prescriptionListCorrect.get(0); MvcResult mvcResult= this.mockMvc.perform(get(path+"/byPactsTemplate/"+id.toString())) .andDo(print()) .andExpect(jsonPath("$.statusCode").value(200)) .andExpect(jsonPath("$.obj").value(is(instanceOf(List.class)))).andReturn(); String content = mvcResult.getResponse().getContentAsString(); System.out.println(content); // JSONObject jsonobject = JSONObject.fromObject(content); // JSONArray array = jsonobject.getJSONArray("obj"); // List<PactsPrescription> prescriptionList = new ArrayList<PactsPrescription>(); // for (int i = 0; i < array.size(); i++) { // JSONObject object = (JSONObject)array.get(i); // PactsPrescription passport = (PactsPrescription)JSONObject.toBean(object, // PactsPrescription.class); // if(passport != null){ // prescriptionList.add(passport); // } // } JsonResp jsonResp = jsonMapper.fromJson(content,JsonResp.class); System.out.println(jsonResp.getObj()); List<PactsPrescription> prescriptionList = (List<PactsPrescription>)jsonResp.getObj(); assertNotNull("根据xx模板id获取xx集合 is null",prescriptionList); assertThat("根据xx模板id获取xx集合 is empty",prescriptionList.size(),greaterThan(0)); PactsPrescription pactsPrescription = prescriptionList.get(0); assertThat("处方名称不一致",pactsPrescription.getPrescriptionName(),equalTo(pactsPrescriptionCorrect.getPrescriptionName())); assertThat("处方类型不一致",pactsPrescription.getPrescriptionType(),equalTo(pactsPrescriptionCorrect.getPrescriptionType())); } }
解决方式一:
1、引入jar包:
<!-- https://mvnrepository.com/artifact/com.hynnet/json-lib --> <dependency> <groupId>com.hynnet</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> </dependency>
2、将以下代码注释打开:
// JSONObject jsonobject = JSONObject.fromObject(content); // JSONArray array = jsonobject.getJSONArray("obj"); // List<PactsPrescription> prescriptionList = new ArrayList<PactsPrescription>(); // for (int i = 0; i < array.size(); i++) { // JSONObject object = (JSONObject)array.get(i); // PactsPrescription passport = (PactsPrescription)JSONObject.toBean(object, // PactsPrescription.class); // if(passport != null){ // prescriptionList.add(passport); // } // }
同时,注释以下代码:
JsonResp jsonResp = jsonMapper.fromJson(content,JsonResp.class); System.out.println(jsonResp.getObj()); List<xxx> pxxList = (List<xxx>)jsonResp.getObj();
至此,完成!debug如图:
解决方式二:
ObjectMapper objectMapper = new ObjectMapper(); JsonNode rootNode = objectMapper.readTree(content); JsonNode objNode=rootNode.get("obj"); String json = objectMapper.writeValueAsString(objNode); JavaType javaType = objectMapper.getTypeFactory().constructParametricType( List.class, xxx.class); List<xxx> prescriptionList=objectMapper.readValue(json,javaType);
这种方式好处:不用重新引入新的json包,还是使用
import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper;