gson使用教程-翻译2

原文地址:http://www.studytrails.com/java/json/java-google-json-parse-json-token-by-token.jsp

在上一节教程当中,我们看到如何将json转换成java对象,这节中我们会涉及到自定义解析json.这种方式看起来似乎麻烦,但是当你需要进行自定义解析的时候,这种方式就会显得灵活方便.使用的方式:
通过使用JsonReader来读取json字符串来获取标记流.一个对象或者一个数组,也就是”{“,”[“,是一个标记.
以下为一个demo:

package com.studytrails.json.gson;

import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.io.IOUtils;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

public class ParseTokenExample7
{
    public static void main(String[] args) throws MalformedURLException, IOException
    {
        String url = "http://freemusicarchive.org/api/get/albums.json?api_key=60BLHNQCAOUFPIBZ&limit=1";
        String json = IOUtils.toString(new URL(url));
        // use the reader to read the json to a stream of tokens
        JsonReader reader = new JsonReader(new StringReader(json));
        // we call the handle object method to handle the full json object. This
        // implies that the first token in JsonToken.BEGIN_OBJECT, which is
        // always true.
        handleObject(reader);
    }

    /**
     * Handle an Object. Consume the first token which is BEGIN_OBJECT. Within
     * the Object there could be array or non array tokens. We write handler
     * methods for both. Noe the peek() method. It is used to find out the type
     * of the next token without actually consuming it.
     * 
     * @param reader
     * @throws IOException
     */
    private static void handleObject(JsonReader reader) throws IOException
    {
        reader.beginObject();
        while (reader.hasNext()) {
            JsonToken token = reader.peek();
            if (token.equals(JsonToken.BEGIN_ARRAY))
                handleArray(reader);
            else if (token.equals(JsonToken.END_OBJECT)) {
                reader.endObject();
                return;
            } else
                handleNonArrayToken(reader, token);
        }

    }

    /**
     * Handle a json array. The first token would be JsonToken.BEGIN_ARRAY.
     * Arrays may contain objects or primitives.
     * 
     * @param reader
     * @throws IOException
     */
    public static void handleArray(JsonReader reader) throws IOException
    {
        reader.beginArray();
        while (true) {
            JsonToken token = reader.peek();
            if (token.equals(JsonToken.END_ARRAY)) {
                reader.endArray();
                break;
            } else if (token.equals(JsonToken.BEGIN_OBJECT)) {
                handleObject(reader);
            } else if (token.equals(JsonToken.END_OBJECT)) {
                reader.endObject();
            } else
                handleNonArrayToken(reader, token);
        }
    }

    /**
     * Handle non array non object tokens
     * @param reader
     * @param token
     * @throws IOException
     */
    public static void handleNonArrayToken(JsonReader reader, JsonToken token) throws IOException
    {
        if (token.equals(JsonToken.NAME))
            System.out.println(reader.nextName());
        else if (token.equals(JsonToken.STRING))
            System.out.println(reader.nextString());
        else if (token.equals(JsonToken.NUMBER))
            System.out.println(reader.nextDouble());
        else
            reader.skipValue();
    }
}

可以看到这个demo中的json跟上一节的是一样的结构.

上面的教程中比较生涩(大神请自动忽略),具体可以看到JsonReader的api说明(在这里我翻译出来):

JsonReader这个类可以把Json解析成一个标记流,这个标记流中包含字面的值(string,number,boolean,null)以及对象和数组的开始,结束符号.也就是{}和[].这些标记的顺序跟在json中出现的顺序是一致的.在Json object中,键值对是一个标记.

解析的大概流程:
首先创建一个JsonReader对象,然后为已知的json结构创建处理的方法.分为object和array两种类型.
- 在array类型的处理方法中,首先需要调用beginArray()方法来消费掉”[“这个标记,然后创建一个循环,直到hasNext()方法返回是false,结束这个循环.在循环中,我们就可以读取所有的键值对,最后,调用endArray()方法消费掉”]”标记.
- 同样的,在object类型的处理中,首先调用begingObject()来消费掉”{“,以及最后调用endObject()来消费掉”}”,在两者之间进行一个读取键值对的循环,知道hasNext()返回fasle;

遇到对应的类型的时候,调用相应的方法处理即可.当遇到未知的类型的时候,严格的解析是要抛出一个异常的.而宽松的解析则可以通过skipValue()来跳过未知类型.
如果一个值是null的时候,可以使用peek()方法来检查是否为空,空标记可以用nextNull()或者skipValue()方法来消费掉.
以下是一个demo:
要解析的json:

[
   {
     "id": 912345678901,
     "text": "How do I read a JSON stream in Java?",
     "geo": null,
     "user": {
       "name": "json_newb",
       "followers_count": 41
      }
   },
   {
     "id": 912345678902,
     "text": "@json_newb just use JsonReader!",
     "geo": [50.454722, -104.606667],
     "user": {
       "name": "jesse",
       "followers_count": 2
     }
   }
 ]

代码:

public List<Message> readJsonStream(InputStream in) throws IOException {
     JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
     try {
       return readMessagesArray(reader);
     } finally {
       reader.close();
     }
   }

   public List<Message> readMessagesArray(JsonReader reader) throws IOException {
     List<Message> messages = new ArrayList<Message>();

     reader.beginArray();
     while (reader.hasNext()) {
       messages.add(readMessage(reader));
     }
     reader.endArray();
     return messages;
   }

   public Message readMessage(JsonReader reader) throws IOException {
     long id = -1;
     String text = null;
     User user = null;
     List<Double> geo = null;

     reader.beginObject();
     while (reader.hasNext()) {
       String name = reader.nextName();
       if (name.equals("id")) {
         id = reader.nextLong();
       } else if (name.equals("text")) {
         text = reader.nextString();
       } else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
         geo = readDoublesArray(reader);
       } else if (name.equals("user")) {
         user = readUser(reader);
       } else {
         reader.skipValue();
       }
     }
     reader.endObject();
     return new Message(id, text, user, geo);
   }

   public List<Double> readDoublesArray(JsonReader reader) throws IOException {
     List<Double> doubles = new ArrayList<Double>();

     reader.beginArray();
     while (reader.hasNext()) {
       doubles.add(reader.nextDouble());
     }
     reader.endArray();
     return doubles;
   }

   public User readUser(JsonReader reader) throws IOException {
     String username = null;
     int followersCount = -1;

     reader.beginObject();
     while (reader.hasNext()) {
       String name = reader.nextName();
       if (name.equals("name")) {
         username = reader.nextString();
       } else if (name.equals("followers_count")) {
         followersCount = reader.nextInt();
       } else {
         reader.skipValue();
       }
     }
     reader.endObject();
     return new User(username, followersCount);
   }
Number Handling

这个类允许将一个数字类型的值解析成String跟String类型解析成数字类型.例如:[“1”,”1”]中的值既可以用nextInt()方法去读取,也可以用nextString()方法来读.这样是为了方式数字型读取的时候的损耗,例如:在JavaScript中,像9007199254740993这么大的数字,使用double这样的类型去读的话就会有精度的损耗.所以使用nextString()来读取的话就会减少这个精度的问题.

Non-Execute Prefix

使用json来交换私密信息的web服务器容易受到Cross-site request forgery这种攻击.在这种攻击中,恶意网站通过Html的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值