Java JSON操作

228 阅读4分钟

解析超大JSON文件

将超大JSON文件导出到Excel中,采用JsonToken解决方案:

package com.godfrey.poi.util;
 
 
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MappingJsonFactory;
 
import java.io.File;
 
/**
 * @author godfrey
 * @since 2021-12-05
 */
public class ParseJsonUtil {
    public static void main(String[] args) throws Exception {
        JsonFactory f = new MappingJsonFactory();
        JsonParser jp = f.createJsonParser(new File("F:/FeaturesToJSON.json"));
        JsonToken current;
        current = jp.nextToken();
        if (current != JsonToken.START_OBJECT) {
            System.out.println("Error: root should be object: quiting.");
            return;
        }
        while (jp.nextToken() != JsonToken.END_OBJECT) {
            String fieldName = jp.getCurrentName();
            // move from field name to field value
            current = jp.nextToken();
            if ("features".equals(fieldName)) {
                if (current == JsonToken.START_ARRAY) {
                    // For each of the records in the array
                    while (jp.nextToken() != JsonToken.END_ARRAY) {
                        // read the record into a tree model,
                        // this moves the parsing position to the end of it
                        JsonNode node = jp.readValueAsTree();
                        // And now we have random access to everything in the object
                        System.out.println("field1: " + node.get("field1").asText());
                        System.out.println("field2: " + node.get("field2").asText());
                    }
                } else {
                    System.out.println("Error: records should be an array: skipping.");
                    jp.skipChildren();
                }
            } else {
                System.out.println("Unprocessed property: " + fieldName);
                jp.skipChildren();
            }
        }
    }
}

JSONObject解析报错:java.lang.ClassCastException: net.sf.ezmorph.bean.MorphDynaBean

背景

当利用net.sf.json.JSONObject中的toBean方法把字符串解析为JSONObject对象时,如果这个对象中的属性里含有复杂的对象,那么我们在获取这个复杂对象时会报错:java.lang.ClassCastException: net.sf.ezmorph.bean.MorphDynaBean cannot be cast to XXX

解决方案

  • json转化为带有list集合的复杂对象时出现ClassCastException异常

    新建map对象并用list集合的名称作为key,list集合中复杂对象的Class作为value值put到map中。在将json对象转化为bean对象时,将这个map作为最后一个参数传入到toBean方法里面进行解析转化,具体代码如下:

    //retStr为调用接口返回的String类型的json格式字符串,其中里面存放着一个叫做flights的复杂集合对象,FlightResponse是自己封装的最外层的对象。
    //retStr 格式为: {"resp":{"msg":"成功","code":"00000000","flights":[{"flightArrName":"重庆/江北","companyName":"CA","canFavFlag":"0","fltProStatus":"到达","flightNowStation":"100","flightId":"71434393","remark":"","flightDepName":"重庆/江北","flightNO":"CA4487","fltDepTime":"2022-04-21 14:55","fltArrTime":"2022-04-21 17:58","flightDeptimePlan":"2022-04-21 14:55","fltDepTimeS":"2022-04-21 15:00","delayReason":"","flightDep":"CKG","flightTerminal":" ","flightHTerminal":" ","flightDate":"2022-04-21","fltDepTimeE":"--","flightModel":"737","flightStatus":"到达","modelType":"窄体","isStopOver":"N","fltArrTimeE":"2022-04-21 17:59","isFav":"0","flightArrtimePlan":"2022-04-21 17:58","flightStatusFlag":"5","flightArr":"CKG","fltProgress":"100","fltTotalTime":10800000,"isShare":"N","fltArrTimeS":"2022-04-21 18:00"},{"flightArrName":"西双版纳/嘎洒","companyName":"CA","canFavFlag":"0","fltProStatus":"到达","flightNowStation":"100","flightId":"71805686","remark":"","flightDepName":"重庆/江北","flightNO":"CA4487","fltDepTime":"2022-04-21 19:30","fltArrTime":"2022-04-21 21:23","flightDeptimePlan":"2022-04-21 19:30","fltDepTimeS":"2022-04-21 19:00","delayReason":"天气原因","flightDep":"CKG","flightTerminal":" ","flightHTerminal":" ","flightDate":"2022-04-21","fltDepTimeE":"--","flightModel":"737","flightStatus":"到达","modelType":"窄体","isStopOver":"N","fltArrTimeE":"2022-04-21 21:13","isFav":"0","flightArrtimePlan":"2022-04-21 21:23","flightStatusFlag":"5","flightArr":"JHG","fltProgress":"100","fltTotalTime":7200000,"isShare":"N","fltArrTimeS":"2022-04-21 21:00"}]},"securityCode":"0000"}
    
    String retStr = response.body().string();
    JSONObject obj = JSONObject.fromObject(retStr);
    Map<String, Class<?>> classMap = new HashMap<>();
    classMap.put("flights", Flights.class);
    FlightResponse flightResponse = (FlightResponse) JSONObject.toBean(obj,FlightResponse.class, classMap);
    

net.sf.ezmorph.bean.MorphDynaBean@3d92f1

net.sf.ezmorph.bean.MorphDynaBean@3d92f1  是  json-lib  中的一个内置对象,当对象缺省的时候,就用这个对象接收。你也可以用它,但是我们往往是需要返回我们自己的实体,或者自己的泛型集合。

net.sf.ezmorph.bean.MorphDynaBean@3d92f1的形成

下面是一个对象实体,然后answers 是一个List<SOAskAnswers>

public class SOAsk implements Serializable{
	private static final long serialVersionUID = 1L;
	
	/**回答集合*/
	private List<SOAskAnswers> answers = new ArrayList<SOAskAnswers>();
	/**分类*/
	private String category;
	/**分类名称*/
	private String categoryName;
	/**创建日期*/
	private String date;
	/**seo - 描述*/
	private String description;
	/**seo - 关键词*/
	private String keywords;
	/**来源 */
	private String from ;
	/**数据ID,url*/
	private String id;
	/**问题描述*/
	private String question;
	/**浏览次数*/
	private long readCount = 0 ;
	/**标题*/
	private String title;
	/**用户ID*/
	private String userId;
	/**用户名称*/
	private String userName;
	/**状态。0:没满意答案,1:有满意答案*/
	private int status = 0;
	
	//TODO getter & setter
	
}

JSON  反射对象的时候,集合对象就出现了net.sf.ezmorph.bean.MorphDynaBean@3d92f1

//查询返回一个JSON(map),然后反射回来对象,其中有一个属性就是集合。
List<SOAsk> list = new ArrayList<SOAsk>();
for (SearchHit searchHit : hits) {
	Map<String, Object> source = searchHit.getSource();
	JsonConfig config = new JsonConfig();
	//设置对象class
	config.setRootClass(SOAsk.class);
	SOAsk entity = (SOAsk)JSONObject.toBean(JSONObject.fromObject(source) , config);
	list.add(entity);
}

解决办法:

//查询返回一个JSON(map),然后反射回来对象,其中有一个属性就是集合。
List<SOAsk> list = new ArrayList<SOAsk>();
for (SearchHit searchHit : hits) {
	Map<String, Object> source = searchHit.getSource();
	JsonConfig config = new JsonConfig();
	//设置对象class
	config.setRootClass(SOAsk.class);
	
	//键值对的设置对象Class
	Map<String,Class<?>> classMap = new HashMap<String, Class<?>>();
	//设置集合List<SOAskAnswers> answers = new ArrayList<SOAskAnswers>() 的泛型类型为SOAskAnswers
	classMap.put("answers", SOAskAnswers.class);
	//这里可以设置多个,如果当前对象里有很多的话 。。。
	
	
	//设置进去
	config.setClassMap(classMap);
	SOAsk entity = (SOAsk)JSONObject.toBean(JSONObject.fromObject(source) , config);
	list.add(entity);
}