1. 程式人生 > >基於Gson的Http請求解析long型日期時出錯的解決方案

基於Gson的Http請求解析long型日期時出錯的解決方案

在http的post方法中,我們通常使用Gson來實現物件和Json的相互轉換。然而,原生的Gson在將包含Date型別物件序列化的過程中,會自動將Date型別轉換為long型。此時若想反序列化物件,則Gson將會丟擲一個JsonSyntaxException,表示解析失敗。

那麼為什麼會失敗呢?通過檢視原始碼可知,Gson預設的日期介面卡DateTypeAdapter,只支援這種“yyyy-MM-dd'T'HH:mm:ss'Z'”的字串日期格式,如圖1所示。


圖1

因此,我們可通過重寫DateTypeAdapter來達到解析long型日期格式的目的。首先實現Json的反序列化介面,然後重寫deserialize方法,同時我們還可通過構造器傳入DateFormat物件,以支援特定字串日期格式的解析,如圖2所示。


圖2

最後附上完整的的http工具類(post方法),希望對大家有所幫助。

/**
 * Http工具類
 */
public class HttpUtils {
 
	private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);
	private static final Client CLIENT = Client.create();
	private static final Gson GSON = new GsonBuilder()
	        .registerTypeAdapter(Date.class, new DateTypeAdapter())
	        .create();
 
	private static final String ACCEPT = ":  accept:  ";
	private static final String PATH = "path=  ";
	private static final String APPJSON = "application/json";
	private static final String RESPONSE = ":  response:  ";
 
	/**
	 * 該方法可轉換複雜的物件(包含複雜引用型別成員變數)
	 * @param path
	 * @param request
	 * @param describe
	 * @param type
	 * @return
	 */
	public static T post(String path, Object request, String describe, Type type) {
		
		if (request != null) {
			
			logger.info("\n" + describe + ACCEPT + request + "\n" + PATH + path);
			WebResource webResource = CLIENT.resource(path);
 
			String response = webResource.accept(APPJSON).type(APPJSON).post(String.class, new Gson().toJson(request));
			logger.info("\n" + describe + RESPONSE + response);
			
			return GSON.fromJson(response, type);
		}
 
		return null;
	}
	
	/**
	 * 該方法可轉換複雜的物件(包含複雜引用型別成員變數),同時還可新增請求頭資訊
	 * @param path
	 * @param header
	 * @param request
	 * @param describe
	 * @param type
	 * @return
	 */
	public static T postWithHeader(String path, Map<String, String> header, Object request,
			String describe, Type type) {
		
		if (request != null) {
			
			logger.info("\n" + describe + ACCEPT + request + "\n" + PATH + path);
			WebResource webResource = CLIENT.resource(path);
			Builder builder = webResource.getRequestBuilder();
			for (Map.Entry<String, String> entry : header.entrySet()) {
				builder = builder.header(entry.getKey(), entry.getValue());
			}
			String response = builder.accept(APPJSON).type(APPJSON).post(String.class, new Gson().toJson(request));
			logger.info("\n" + describe + RESPONSE + response);
			
			return GSON.fromJson(response, type);
		}
 
		return null;
	}
}
 
/**
* 重寫日期型別介面卡
* 預設日期型別為Long型,若日期格式為String型別,則必須通過構造器傳入對應DateFormat型別進行日期轉換
*/
class DateTypeAdapter implements JsonDeserializer<Date> {
 
    private DateFormat format;
 
    public DateTypeAdapter() {
 
    }
 
    public DateTypeAdapter(DateFormat format) {
 
        this.format = format;
    }
 
    public synchronized Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
 
        if (!(json instanceof JsonPrimitive)) {
            throw new JsonParseException("This is not a primitive value");
        }
 
        String jsonStr = json.getAsString();
 
        if (format != null) {
 
            try {
                return format.parse(jsonStr);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
 
        return new Date(Long.parseLong(jsonStr));
    }
}